consistent profile image, initials with background color as backup, better profile image editing

This commit is contained in:
jackiettran
2025-12-12 23:08:54 -05:00
parent 3f319bfdd0
commit 55e08e14b8
11 changed files with 196 additions and 184 deletions

View File

@@ -7,6 +7,7 @@ import { getPublicImageUrl } from "../services/uploadService";
import GoogleMapWithRadius from "../components/GoogleMapWithRadius";
import ItemReviews from "../components/ItemReviews";
import ConfirmationModal from "../components/ConfirmationModal";
import Avatar from "../components/Avatar";
const ItemDetail: React.FC = () => {
const { id } = useParams<{ id: string }>();
@@ -480,28 +481,7 @@ const ItemDetail: React.FC = () => {
onClick={() => navigate(`/users/${item.ownerId}`)}
style={{ cursor: "pointer" }}
>
{item.owner.imageFilename ? (
<img
src={item.owner.imageFilename}
alt={`${item.owner.firstName} ${item.owner.lastName}`}
className="rounded-circle me-2"
style={{
width: "30px",
height: "30px",
objectFit: "cover",
}}
/>
) : (
<div
className="rounded-circle bg-secondary d-flex align-items-center justify-content-center me-2"
style={{ width: "30px", height: "30px" }}
>
<i
className="bi bi-person-fill text-white"
style={{ fontSize: "0.8rem" }}
></i>
</div>
)}
<Avatar user={item.owner} size="xs" className="me-2" />
<span className="text-muted">
{item.owner.firstName} {item.owner.lastName}
</span>

View File

@@ -4,6 +4,7 @@ import { messageAPI } from "../services/api";
import { useAuth } from "../contexts/AuthContext";
import { useSocket } from "../contexts/SocketContext";
import ChatWindow from "../components/ChatWindow";
import Avatar from "../components/Avatar";
const Messages: React.FC = () => {
const { user } = useAuth();
@@ -230,25 +231,7 @@ const Messages: React.FC = () => {
<div className="d-flex w-100 justify-content-between align-items-start">
<div className="d-flex align-items-center flex-grow-1">
{/* Profile Picture */}
{conversation.partner.imageFilename ? (
<img
src={conversation.partner.imageFilename}
alt={`${conversation.partner.firstName} ${conversation.partner.lastName}`}
className="rounded-circle me-3"
style={{
width: "50px",
height: "50px",
objectFit: "cover",
}}
/>
) : (
<div
className="rounded-circle bg-secondary d-flex align-items-center justify-content-center me-3"
style={{ width: "50px", height: "50px" }}
>
<i className="bi bi-person-fill text-white"></i>
</div>
)}
<Avatar user={conversation.partner} size="lg" className="me-3" />
<div className="flex-grow-1" style={{ minWidth: 0 }}>
{/* User Name and Unread Badge */}

View File

@@ -8,6 +8,7 @@ import AvailabilitySettings from "../components/AvailabilitySettings";
import ReviewItemModal from "../components/ReviewModal";
import ReviewRenterModal from "../components/ReviewRenterModal";
import ReviewDetailsModal from "../components/ReviewDetailsModal";
import Avatar from "../components/Avatar";
import {
geocodingService,
AddressComponents,
@@ -313,6 +314,11 @@ const Profile: React.FC = () => {
// Update preview to use the S3 URL
setImagePreview(publicUrl);
// Save imageFilename to database immediately
const response = await userAPI.updateProfile({ imageFilename: key });
setProfileData(response.data);
updateUser(response.data);
} catch (err: any) {
console.error("Image upload error:", err);
setError(err.message || "Failed to upload image");
@@ -747,55 +753,34 @@ const Profile: React.FC = () => {
<div className="card-body">
<div className="text-center">
<div className="position-relative d-inline-block mb-3">
{imagePreview ? (
<img
src={imagePreview}
alt="Profile"
className="rounded-circle"
style={{
width: "120px",
height: "120px",
objectFit: "cover",
}}
<Avatar
user={user}
size="xxl"
imageUrl={imagePreview}
/>
<label
htmlFor="imageFilenameOverview"
className="position-absolute bottom-0 end-0 btn btn-sm btn-primary rounded-circle d-flex align-items-center justify-content-center"
style={{
width: "35px",
height: "35px",
}}
>
<i className="bi bi-pencil-fill"></i>
<input
type="file"
id="imageFilenameOverview"
accept="image/*"
onChange={handleImageChange}
className="d-none"
/>
) : (
<div
className="rounded-circle bg-secondary d-flex align-items-center justify-content-center"
style={{ width: "120px", height: "120px" }}
>
<i
className="bi bi-person-fill text-white"
style={{ fontSize: "2.5rem" }}
></i>
</div>
)}
{editing && (
<label
htmlFor="imageFilenameOverview"
className="position-absolute bottom-0 end-0 btn btn-sm btn-primary rounded-circle"
style={{
width: "35px",
height: "35px",
padding: "0",
}}
>
<i className="bi bi-camera-fill"></i>
<input
type="file"
id="imageFilenameOverview"
accept="image/*"
onChange={handleImageChange}
className="d-none"
/>
</label>
)}
</label>
</div>
<div>
<h5>
{profileData?.firstName} {profileData?.lastName}
</h5>
<p className="text-muted">@{profileData?.username}</p>
</div>
</div>
</div>

View File

@@ -5,6 +5,7 @@ import { userAPI, itemAPI } from '../services/api';
import { getPublicImageUrl } from '../services/uploadService';
import { useAuth } from '../contexts/AuthContext';
import ChatWindow from '../components/ChatWindow';
import Avatar from '../components/Avatar';
const PublicProfile: React.FC = () => {
const { id } = useParams<{ id: string }>();
@@ -72,21 +73,7 @@ const PublicProfile: React.FC = () => {
<div className="card">
<div className="card-body">
<div className="text-center mb-4">
{user.imageFilename ? (
<img
src={user.imageFilename}
alt={`${user.firstName} ${user.lastName}`}
className="rounded-circle mb-3"
style={{ width: '150px', height: '150px', objectFit: 'cover' }}
/>
) : (
<div
className="rounded-circle bg-secondary d-flex align-items-center justify-content-center mb-3 mx-auto"
style={{ width: '150px', height: '150px' }}
>
<i className="bi bi-person-fill text-white" style={{ fontSize: '3rem' }}></i>
</div>
)}
<Avatar user={user} size="xxxl" className="mb-3 mx-auto" />
<h3>{user.firstName} {user.lastName}</h3>
{currentUser && currentUser.id !== user.id && (
<button