feat: Improve avatar loading experience by displaying placeholders until images are fully loaded across various components.

This commit is contained in:
pradeepkumar
2026-03-13 22:45:11 +05:30
parent b339dd865c
commit 7b5c670159
11 changed files with 225 additions and 80 deletions

View File

@@ -46,12 +46,18 @@ export function ProfileSettingsForm({
});
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
const [avatarLoaded, setAvatarLoaded] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);
// Reset avatar loaded state when URL changes (e.g., after upload)
useEffect(() => {
setAvatarLoaded(false);
}, [avatarUrl]);
// Store original data for cancel/reset functionality
const [originalData, setOriginalData] = useState<typeof formData | null>(null);
// Track if initial profile fetch is done to avoid re-showing loading spinner
@@ -382,20 +388,22 @@ export function ProfileSettingsForm({
{/* Profile Photo Section */}
<div className="mb-8">
<div className="flex items-start gap-4">
<div className="w-[60px] h-[60px] rounded-full overflow-hidden border border-[#00293D]/20 flex-shrink-0 bg-gray-100">
{avatarUrl ? (
<img
src={avatarUrl}
alt="Profile"
className="w-full h-full object-cover"
/>
) : (
<div className="w-[60px] h-[60px] rounded-full overflow-hidden border border-[#00293D]/20 flex-shrink-0 bg-gray-100 relative">
{(!avatarUrl || !avatarLoaded) && (
<Image
src="/assets/icons/user-placeholder-icon.svg"
alt="Profile"
width={60}
height={60}
className="w-full h-full object-cover"
className="absolute inset-0 w-full h-full object-cover"
/>
)}
{avatarUrl && (
<img
src={avatarUrl}
alt="Profile"
className={`absolute inset-0 w-full h-full object-cover transition-opacity duration-200 ${avatarLoaded ? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setAvatarLoaded(true)}
/>
)}
</div>