From 950fc475b2451dbf04f55ea4a66ca24074f18c13 Mon Sep 17 00:00:00 2001 From: bokhonglo Date: Fri, 10 Apr 2026 16:54:50 +0700 Subject: [PATCH] upgrade update information --- .../(tables)/user-table/page.tsx | 3 +- src/components/tables/BasicTableOne.tsx | 2 +- src/components/user-profile/UserInfoCard.tsx | 40 +++- src/components/user-profile/UserMetaCard.tsx | 190 ++++++++---------- src/service/mediaService.ts | 7 +- 5 files changed, 120 insertions(+), 122 deletions(-) diff --git a/src/app/(admin)/(others-pages)/(tables)/user-table/page.tsx b/src/app/(admin)/(others-pages)/(tables)/user-table/page.tsx index aa7ff89..04a0355 100644 --- a/src/app/(admin)/(others-pages)/(tables)/user-table/page.tsx +++ b/src/app/(admin)/(others-pages)/(tables)/user-table/page.tsx @@ -17,7 +17,8 @@ import Pagination from "@/components/tables/Pagination"; export type SortColumn = "created_at" | "updated_at" | "display_name" | "email"; -export default function UserTable() { +export default function UserTable() { // UserTable + const [page, setPage] = useState(1); const [limitInput, setLimitInput] = useState("5"); diff --git a/src/components/tables/BasicTableOne.tsx b/src/components/tables/BasicTableOne.tsx index 179729f..ec7b9e0 100644 --- a/src/components/tables/BasicTableOne.tsx +++ b/src/components/tables/BasicTableOne.tsx @@ -1,5 +1,5 @@ "use client"; -import React from "react"; + import { Table, TableBody, diff --git a/src/components/user-profile/UserInfoCard.tsx b/src/components/user-profile/UserInfoCard.tsx index c46f1bd..d76824d 100644 --- a/src/components/user-profile/UserInfoCard.tsx +++ b/src/components/user-profile/UserInfoCard.tsx @@ -45,17 +45,42 @@ export default function UserInfoCard({ data }: { data: UserMetaCardProps }) { }; const handleSave = async (e: React.FormEvent) => { + e.preventDefault(); + + const userId = data?.data?.id; + if (!userId) return; + try { - const userId = data?.data?.id; - if (userId) { - await apiUpdateUser(userId, formData); - toast.success("Cập nhật thành công!"); - router.refresh(); + const response = await apiUpdateUser(userId, formData); + + if (response && response.status === false) { + toast.error(response.message || "Cập nhật thất bại."); + return; } - } catch (error) { - console.error("Lỗi khi cập nhật profile:", error); + + toast.success("Cập nhật thành công!"); + setTimeout(() => { + window.location.reload(); + }, 1000); + } catch (error: any) { + const serverResponse = error.response?.data; + + if (serverResponse && serverResponse.status === false) { + const msg = serverResponse.message || ""; + + if (msg.includes("idx_user_profiles_phone")) { + toast.error("Số điện thoại này đã được sử dụng!"); + } else { + toast.error(msg); + } + } else { + toast.error("Không thể kết nối đến máy chủ hoặc lỗi hệ thống."); + } + + console.error("Lỗi chi tiết:", error); } }; + return (
@@ -187,6 +212,7 @@ export default function UserInfoCard({ data }: { data: UserMetaCardProps }) { name="avatar_url" defaultValue={formData.avatar_url} onChange={handleChange} + disabled />
diff --git a/src/components/user-profile/UserMetaCard.tsx b/src/components/user-profile/UserMetaCard.tsx index 0cb6847..9916f16 100644 --- a/src/components/user-profile/UserMetaCard.tsx +++ b/src/components/user-profile/UserMetaCard.tsx @@ -1,43 +1,52 @@ "use client"; -import { useState, useRef } from "react"; +import { useState, useRef, useEffect } from "react"; import Image from "next/image"; import { UserMetaCardProps } from "@/interface/user"; import { uploadMedia } from "@/service/mediaService"; export default function UserMetaCard({ data }: { data: UserMetaCardProps }) { - const [previewImage, setPreviewImage] = useState( - data.data?.profile?.avatar_url || "/images/no-images.jpg", - ); + const currentAvatar = data.data?.profile?.avatar_url || "/images/no-images.jpg"; + + const [previewImage, setPreviewImage] = useState(currentAvatar); const [isUploading, setIsUploading] = useState(false); const fileInputRef = useRef(null); + useEffect(() => { + if (data.data?.profile?.avatar_url) { + setPreviewImage(data.data.profile.avatar_url); + } + }, [data.data?.profile?.avatar_url]); + const handleAvatarClick = () => { if (!isUploading) { fileInputRef.current?.click(); } }; - const handleFileChange = async ( - event: React.ChangeEvent, - ) => { + const handleFileChange = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; + + const objectUrl = URL.createObjectURL(file); + const backupImage = previewImage; + setPreviewImage(objectUrl); + try { setIsUploading(true); - console.log("Selected file:", file); - - const objectUrl = URL.createObjectURL(file); - setPreviewImage(objectUrl); - const uploadedMedia = await uploadMedia(file); + console.log("Upload thành công:", uploadedMedia); + + + if (uploadedMedia?.url) { + setPreviewImage(uploadedMedia.url); + } + } catch (error) { console.error("Lỗi khi upload avatar:", error); - setPreviewImage( - data.data?.profile?.avatar_url || "/images/no-images.jpg", - ); + setPreviewImage(backupImage); alert("Không thể tải ảnh lên. Vui lòng thử lại!"); } finally { setIsUploading(false); @@ -48,106 +57,65 @@ export default function UserMetaCard({ data }: { data: UserMetaCardProps }) { }; return ( - <> -
-
-
-
- avatar - -
- {isUploading ? ( - - - - - ) : ( - - - - - )} -
- - +
+
+
+
+ avatar + +
+ {isUploading ? ( + + + + + ) : ( + + + + + )}
-
-

- {data.data?.profile?.display_name || "Full Name"} -

-
-

- {data.data?.roles?.map((role) => role.name).join(", ") || - "No roles available"} -

- {data.data?.profile?.bio && ( - <> -
-

- {data.data?.profile?.bio || "No bio available"} -

- - )} - {data.data?.profile?.location && ( - <> -
-

- {data.data?.profile?.location || "user location"} -

- - )} -
+ +
+ +
+

+ {data.data?.profile?.display_name || "Full Name"} +

+
+

+ {data.data?.roles?.map((role) => role.name).join(", ") || "No roles available"} +

+ {data.data?.profile?.bio && ( + <> +
+

+ {data.data.profile.bio} +

+ + )}
- +
); -} +} \ No newline at end of file diff --git a/src/service/mediaService.ts b/src/service/mediaService.ts index d6ccb61..2e3d41b 100644 --- a/src/service/mediaService.ts +++ b/src/service/mediaService.ts @@ -52,12 +52,13 @@ export const uploadFileToS3 = async ( file: File, presigned: PreSignedResponse, ) => { - await axios.put(presigned.upload_url, file, { + const res = await axios.put(presigned.upload_url, file, { headers: { ...presigned.signed_headers, "Content-Type": file.type, }, }); + // console.log("Response from S3 upload:", res); }; export const confirmUpload = async (token_id: string) => { @@ -67,6 +68,7 @@ export const confirmUpload = async (token_id: string) => { return res.data; }; + export const uploadMedia = async (file: File) => { const { data: presigned } = await api.get( "/media/presigned", @@ -78,10 +80,11 @@ export const uploadMedia = async (file: File) => { }, }, ); + // console.log("Presigned URL:", presigned); await uploadFileToS3(file, presigned); const media = await confirmUpload(presigned.token_id); - + // console.log("Media sau khi upload:", media); return media; };