Compare commits

...

1 Commits

Author SHA1 Message Date
ff70fc78f5 update: management project
All checks were successful
Build and Release / release (push) Successful in 29s
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 15:03:49 +07:00
3 changed files with 52 additions and 15 deletions

View File

@@ -15,6 +15,7 @@ import {
} from "@/service/projectService"; } from "@/service/projectService";
import { Project } from "@/interface/project"; import { Project } from "@/interface/project";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
type TabType = "overview" | "members" | "settings"; type TabType = "overview" | "members" | "settings";
@@ -127,22 +128,54 @@ export default function ProjectDetailsPage() {
const handleUpdateRole = async (userId: string, newRole: string) => { const handleUpdateRole = async (userId: string, newRole: string) => {
try { try {
await updateProjectMemberRole(id, userId, { role: newRole as any }); const res = await updateProjectMemberRole(id, userId, {
toast.success("Cập nhật quyền thành công"); role: newRole as any,
fetchProject(); });
} catch (error) {
toast.error("Cập nhật quyền thất bại"); if (res?.status) {
toast.success("Cập nhật quyền thành công");
fetchProject();
} else {
toast.error(res?.message || "Cập nhật quyền thất bại");
}
} catch (error: any) {
const errorMessage =
error.response?.data?.message || "Cập nhật quyền thất bại";
toast.error(errorMessage);
} }
}; };
const handleRemoveMember = async (userId: string) => { const handleRemoveMember = async (userId: string) => {
if (!confirm("Xác nhận xóa thành viên này?")) return; // 1. Hiển thị hộp thoại xác nhận bằng SweetAlert2
const result = await Swal.fire({
title: "Xác nhận xóa?",
text: "Bạn có chắc chắn muốn xóa thành viên này khỏi dự án?",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Đồng ý",
cancelButtonText: "Hủy",
});
if (!result.isConfirmed) return;
try { try {
await removeProjectMember(id, userId); const res = await removeProjectMember(id, userId);
toast.success("Đã xóa thành viên");
if (res?.status) {
toast.success("Đã xóa thành viên");
} else {
toast.error(res?.message || "Xóa thành viên thất bại");
}
} catch (error: any) {
const errorMessage =
error.response?.data?.message || "Xóa thành viên thất bại";
toast.error(errorMessage);
console.error("Remove Member Error:", error);
} finally {
fetchProject(); fetchProject();
} catch (error) {
toast.error("Xóa thành viên thất bại");
} }
}; };
@@ -192,7 +225,8 @@ export default function ProjectDetailsPage() {
); );
return ( return (
<div className="min-h-screen bg-white dark:bg-[#0d1117] text-gray-900 dark:text-[#c9d1d9] font-sans"> <div className="min-h-screen dark:bg-[#0d1117] text-gray-900 dark:text-[#c9d1d9] font-sans">
<PageBreadcrumb pageTitle="Chi tiết dự án" />
<div className="pt-8 border-b border-gray-200 dark:border-[#30363d] bg-gray-50 dark:bg-[#0d1117]"> <div className="pt-8 border-b border-gray-200 dark:border-[#30363d] bg-gray-50 dark:bg-[#0d1117]">
<div className="px-6"> <div className="px-6">
<div className="flex items-center gap-2 text-xl mb-6"> <div className="flex items-center gap-2 text-xl mb-6">

View File

@@ -150,16 +150,16 @@ export default function ProjectsTable({
)} )}
</div> </div>
<div className="flex items-center max-w-[250px]"> <div className="flex items-center max-w-[250px]">
<span className="text-lg font-medium text-gray-700 dark:text-gray-300 truncate"> <span className="text-[14px] font-medium text-gray-700 dark:text-gray-300 truncate">
{item.user?.display_name || "Unknown"} {item.user?.display_name || "Unknown"}
</span> </span>
</div> </div>
<span className="text-lg text-gray-400 dark:text-gray-600 shrink-0"> <span className="text-[14px] text-gray-400 dark:text-gray-600 shrink-0">
/ /
</span> </span>
<h3 className="text-lg font-semibold text-blue-600 dark:text-[#58a6ff] truncate max-w-[300px]"> <h3 className="text-[14px] font-semibold text-blue-600 dark:text-[#58a6ff] truncate max-w-[300px]">
{item.title} {item.title}
</h3> </h3>

View File

@@ -159,6 +159,9 @@ export default function UserMetaCard({ data }: { data: UserMetaCardProps }) {
</> </>
)} )}
</div> </div>
<span className="text-sm text-gray-500 dark:text-gray-400">
ID: {data.data?.id}
</span>
</div> </div>
</div> </div>
</div> </div>