feat: Improve avatar loading experience by displaying placeholders until images are fully loaded across various components.
This commit is contained in:
@@ -26,6 +26,7 @@ export function CommonHeader() {
|
||||
const mobileMenuRef = useRef<HTMLDivElement>(null);
|
||||
const [profileImage, setProfileImage] = useState<string | null>(null);
|
||||
const [profileName, setProfileName] = useState<string | null>(null);
|
||||
const [avatarLoaded, setAvatarLoaded] = useState(false);
|
||||
const [notificationCount, setNotificationCount] = useState(0);
|
||||
|
||||
// Close dropdowns when clicking outside
|
||||
@@ -73,6 +74,7 @@ export function CommonHeader() {
|
||||
}
|
||||
|
||||
if (avatar) {
|
||||
setAvatarLoaded(false);
|
||||
try {
|
||||
const avatarUrl = await uploadService.getPresignedDownloadUrl(avatar);
|
||||
setProfileImage(avatarUrl);
|
||||
@@ -150,6 +152,7 @@ export function CommonHeader() {
|
||||
alt="RE-QuestN"
|
||||
width={150}
|
||||
height={40}
|
||||
priority
|
||||
className="h-8 md:h-10 w-auto"
|
||||
/>
|
||||
</Link>
|
||||
@@ -198,23 +201,25 @@ export function CommonHeader() {
|
||||
className="flex items-center gap-2 md:gap-3 hover:opacity-80 transition-opacity cursor-pointer"
|
||||
>
|
||||
{/* Avatar */}
|
||||
<div className="w-[32px] h-[32px] md:w-[35px] md:h-[35px] rounded-full overflow-hidden border-2 border-[#e58625] bg-gray-100 flex-shrink-0">
|
||||
{userImage ? (
|
||||
<img
|
||||
src={userImage}
|
||||
alt="Profile"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-[32px] h-[32px] md:w-[35px] md:h-[35px] rounded-full overflow-hidden border-2 border-[#e58625] bg-gray-100 flex-shrink-0 relative">
|
||||
{(!userImage || !avatarLoaded) && (
|
||||
<Image
|
||||
src="/assets/icons/user-placeholder-icon.svg"
|
||||
alt="Profile"
|
||||
width={35}
|
||||
height={35}
|
||||
className="object-cover"
|
||||
className="absolute inset-0 object-cover"
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
/>
|
||||
)}
|
||||
{userImage && (
|
||||
<img
|
||||
src={userImage}
|
||||
alt="Profile"
|
||||
className={`w-full h-full object-cover ${avatarLoaded ? 'opacity-100' : 'opacity-0'}`}
|
||||
onLoad={() => setAvatarLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{/* Greeting Text - hidden on mobile */}
|
||||
<div className="hidden sm:flex flex-col text-left">
|
||||
@@ -233,23 +238,25 @@ export function CommonHeader() {
|
||||
<div className="absolute -top-2 right-6 w-0 h-0 border-l-[8px] border-l-transparent border-r-[8px] border-r-transparent border-b-[8px] border-b-white"></div>
|
||||
|
||||
<div className="flex items-center gap-3 px-4 py-4 border-b border-black/10">
|
||||
<div className="w-[42px] h-[42px] rounded-full overflow-hidden flex-shrink-0 bg-gray-100">
|
||||
{userImage ? (
|
||||
<img
|
||||
src={userImage}
|
||||
alt="Profile"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-[42px] h-[42px] rounded-full overflow-hidden flex-shrink-0 bg-gray-100 relative">
|
||||
{(!userImage || !avatarLoaded) && (
|
||||
<Image
|
||||
src="/assets/icons/user-placeholder-icon.svg"
|
||||
alt="Profile"
|
||||
width={42}
|
||||
height={42}
|
||||
className="object-cover"
|
||||
className="absolute inset-0 object-cover"
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
/>
|
||||
)}
|
||||
{userImage && (
|
||||
<img
|
||||
src={userImage}
|
||||
alt="Profile"
|
||||
className={`w-full h-full object-cover ${avatarLoaded ? 'opacity-100' : 'opacity-0'}`}
|
||||
onLoad={() => setAvatarLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col min-w-0 overflow-hidden">
|
||||
<p className="font-fractul font-medium text-[16px] leading-[20px] text-black">
|
||||
|
||||
Reference in New Issue
Block a user