feat: Implement S3 presigned URL fetching for user avatars and add an image proxy utility.

This commit is contained in:
pradeepkumar
2026-01-26 22:43:41 +05:30
parent b927d89e49
commit ba29257ba5
4 changed files with 105 additions and 4 deletions

View File

@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { usersService, User, getErrorMessage } from '@/services';
import { usersService, User, getErrorMessage, uploadService } from '@/services';
type RoleFilter = 'ALL' | 'ADMIN' | 'USER' | 'AGENT';
@@ -21,8 +21,40 @@ export default function UsersPage() {
const [currentPage, setCurrentPage] = useState(1);
const [totalUsers, setTotalUsers] = useState(0);
const [activeFilter, setActiveFilter] = useState<RoleFilter>('ALL');
const [avatarUrls, setAvatarUrls] = useState<Record<string, string>>({});
const limit = 10;
// Helper function to check if avatar is an S3 key
const isS3Key = (avatar: string | null | undefined): boolean => {
if (!avatar) return false;
return !avatar.startsWith('http') && !avatar.startsWith('/');
};
// Fetch presigned URLs for user avatars
const fetchAvatarUrls = async (userList: User[]) => {
const urls: Record<string, string> = {};
await Promise.all(
userList.map(async (user) => {
const avatar = user.profile?.avatar;
if (avatar) {
if (isS3Key(avatar)) {
try {
const presignedUrl = await uploadService.getPresignedDownloadUrl(avatar);
urls[user.id] = presignedUrl;
} catch (err) {
console.error(`Failed to get avatar URL for user ${user.id}:`, err);
}
} else {
urls[user.id] = avatar;
}
}
})
);
setAvatarUrls(urls);
};
useEffect(() => {
fetchUsers();
}, [currentPage, activeFilter]);
@@ -36,8 +68,12 @@ export default function UsersPage() {
filters.role = activeFilter;
}
const response = await usersService.getUsers(filters);
setUsers(response.users || []);
const userList = response.users || [];
setUsers(userList);
setTotalUsers(response.total || 0);
// Fetch presigned URLs for avatars
await fetchAvatarUrls(userList);
} catch (err) {
const errorMessage = getErrorMessage(err);
setError(errorMessage);
@@ -167,10 +203,10 @@ export default function UsersPage() {
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center">
<div className="flex-shrink-0 h-10 w-10">
{user.profile?.avatar ? (
{avatarUrls[user.id] ? (
<img
className="h-10 w-10 rounded-full object-cover"
src={user.profile.avatar}
src={avatarUrls[user.id]}
alt=""
/>
) : (