diff --git a/src/components/user-profile/ApplicationList.tsx b/src/components/user-profile/ApplicationList.tsx index bd414f5..cdac3bd 100644 --- a/src/components/user-profile/ApplicationList.tsx +++ b/src/components/user-profile/ApplicationList.tsx @@ -3,30 +3,125 @@ import { setSelectedApplication } from "@/store/features/userSlice"; import { useRouter } from "next/navigation"; import { useDispatch } from "react-redux"; +import { URL_MEDIA } from "../../../api"; -export default function ApplicationList({ applications }: { applications: any[] }) { +const formatFullDateTime = (dateString: string) => { + const date = new Date(dateString); + const time = date.toLocaleTimeString("vi-VN", { hour: "2-digit", minute: "2-digit" }); + const day = date.toLocaleDateString("vi-VN", { day: "2-digit", month: "2-digit", year: "numeric" }); + return `${time} ${day}`; +}; + +const processMedia = (mediaArray: any[]) => { + if (!mediaArray || mediaArray.length === 0) return { type: "empty" }; + const imageFiles = mediaArray.filter((file) => { + const isImageMime = file.mime_type?.startsWith("image/"); + const isImageExt = /\.(jpg|jpeg|png|webp|gif)$/i.test(file.storage_key); + return isImageMime || isImageExt; + }); + const docFiles = mediaArray.filter((file) => { + const isImage = file.mime_type?.startsWith("image/") || /\.(jpg|jpeg|png|webp|gif)$/i.test(file.storage_key); + return !isImage; + }); + if (imageFiles.length > 0) return { type: "image", src: `${URL_MEDIA}${imageFiles[0].storage_key}` }; + if (docFiles.length > 0) { + const extensions = docFiles.map((file) => file.mime_type ? file.mime_type.split("/")[1] : file.storage_key.split(".").pop() || "file"); + return { type: "documents", extensions }; + } + return { type: "empty" }; +}; + +export default function ApplicationSquareCardList({ applications }: { applications: any[] }) { const router = useRouter(); const dispatch = useDispatch(); - const handleViewDetail = (app: any) => { + const handleViewDetail = (app: any) => { dispatch(setSelectedApplication(app)); router.push(`/profile/applications`); -}; + }; return ( -
- {applications.map((app) => ( -
handleViewDetail(app)} - className="p-4 border rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 transition" - > -
- Loại: {app.verify_type} - Xem chi tiết → -
-
- ))} +
+

+ Applications CV +

+ +
+ {applications?.map((app) => { + const mediaState = processMedia(app.media); + return ( +
handleViewDetail(app)} + className="group relative h-40 aspect-square border dark:border-zinc-800 rounded-xl cursor-pointer overflow-hidden transition-all duration-300 hover:ring-2 hover:ring-blue-500/50" + > +
+ {mediaState.type === "image" ? ( + + ) : ( +
+ {mediaState.type === "documents" ? ( +
+ {mediaState.extensions?.slice(0, 3).map((ext, i) => ( + + .{ext} + + ))} +
+ ) : ( +
+ )} +
+ )} +
+ +
+ +
+
+ +
+ + {app.media?.length > 0 && ( + + {app.media.length} FILE + + )} +
+ +
+
+

+ {app.verify_type || "VERIFY"} +

+ {app?.reviewer?.display_name && ( +

+ By: {app.reviewer.display_name} +

+ )} +
+ +
+

+ {formatFullDateTime(app.created_at)} +

+
+ + + +
+
+
+
+ ); + })} +
); } \ No newline at end of file diff --git a/src/components/user-profile/UserMetaCard.tsx b/src/components/user-profile/UserMetaCard.tsx index 9916f16..e7ff851 100644 --- a/src/components/user-profile/UserMetaCard.tsx +++ b/src/components/user-profile/UserMetaCard.tsx @@ -37,7 +37,7 @@ export default function UserMetaCard({ data }: { data: UserMetaCardProps }) { setIsUploading(true); const uploadedMedia = await uploadMedia(file); - console.log("Upload thành công:", uploadedMedia); + // console.log("Upload thành công:", uploadedMedia); if (uploadedMedia?.url) { diff --git a/src/service/mediaService.ts b/src/service/mediaService.ts index d4fc921..e9229d4 100644 --- a/src/service/mediaService.ts +++ b/src/service/mediaService.ts @@ -58,14 +58,14 @@ export const uploadFileToS3 = async ( "Content-Type": file.type, }, }); - console.log("Response from S3 upload:", res); + // console.log("Response from S3 upload:", res); }; export const confirmUpload = async (token_id: string) => { const res = await api.post("/media/presigned/complete", { token_id, }); - console.log("Response from confirm upload:", res); + // console.log("Response from confirm upload:", res); return res.data; }; @@ -80,12 +80,12 @@ export const uploadMedia = async (file: File) => { }, }, ); - console.log("Presigned URL:", presigned); + // console.log("Presigned URL:", presigned); await uploadFileToS3(file, presigned); const media = await confirmUpload(presigned.token_id); - console.log("Media sau khi upload:", media); + // console.log("Media sau khi upload:", media); return media; }; @@ -100,7 +100,7 @@ export const getPresignedUrl = async (file: File) => { }, }, ); - console.log("Presigned URL:", presigned); + // console.log("Presigned URL:", presigned); return presigned; }; diff --git a/src/store/features/userSlice.ts b/src/store/features/userSlice.ts index d966dfe..aed21c5 100644 --- a/src/store/features/userSlice.ts +++ b/src/store/features/userSlice.ts @@ -1,7 +1,6 @@ import { UserData } from '@/interface/user'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -// Hàm helper để đọc dữ liệu an toàn từ storage const getStoredApplication = () => { if (typeof window !== "undefined") { const saved = sessionStorage.getItem('selected_application'); @@ -19,7 +18,7 @@ interface UserState { const initialState: UserState = { data: null, isAuthenticated: false, - selectedApplication: getStoredApplication(), // Khởi tạo từ storage + selectedApplication: getStoredApplication(), }; const userSlice = createSlice({ @@ -32,7 +31,6 @@ const userSlice = createSlice({ }, setSelectedApplication: (state, action: PayloadAction) => { state.selectedApplication = action.payload; - // Lưu vào sessionStorage để khi reload trang không bị mất if (typeof window !== "undefined") { sessionStorage.setItem('selected_application', JSON.stringify(action.payload)); }