feat: Implement S3 presigned URL fetching for user avatars and add an image proxy utility.
This commit is contained in:
@@ -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=""
|
||||
/>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user