consistent profile image, initials with background color as backup, better profile image editing
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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 */}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user