From 3285ccc4b3df2ec8a7d7196ae6232e86267d211e Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Tue, 7 Oct 2025 13:08:48 +0700 Subject: [PATCH] feat: update management users --- .../{internal => }/create/page.tsx | 0 .../management-user/detail/[id]/page.tsx | 239 ++++++ .../{internal => }/edit/[id]/page.tsx | 7 +- .../internal/detail/[id]/page.tsx | 733 ------------------ .../(admin)/admin/management-user/page.tsx | 34 +- components/form/content/image/image-form.tsx | 6 +- components/form/user/user-form.tsx | 86 +- .../management-user-internal-column-table.tsx | 19 +- .../management-user-internal-table.tsx | 2 +- lib/menus.ts | 270 +++---- service/management-user/management-user.ts | 40 + 11 files changed, 453 insertions(+), 983 deletions(-) rename app/[locale]/(admin)/admin/management-user/{internal => }/create/page.tsx (100%) create mode 100644 app/[locale]/(admin)/admin/management-user/detail/[id]/page.tsx rename app/[locale]/(admin)/admin/management-user/{internal => }/edit/[id]/page.tsx (88%) delete mode 100644 app/[locale]/(admin)/admin/management-user/internal/detail/[id]/page.tsx diff --git a/app/[locale]/(admin)/admin/management-user/internal/create/page.tsx b/app/[locale]/(admin)/admin/management-user/create/page.tsx similarity index 100% rename from app/[locale]/(admin)/admin/management-user/internal/create/page.tsx rename to app/[locale]/(admin)/admin/management-user/create/page.tsx diff --git a/app/[locale]/(admin)/admin/management-user/detail/[id]/page.tsx b/app/[locale]/(admin)/admin/management-user/detail/[id]/page.tsx new file mode 100644 index 0000000..31d12b3 --- /dev/null +++ b/app/[locale]/(admin)/admin/management-user/detail/[id]/page.tsx @@ -0,0 +1,239 @@ +"use client"; + +import { useRouter } from "@/i18n/routing"; +import { useParams } from "next/navigation"; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { getUserDetail } from "@/service/management-user/management-user"; +import { useEffect, useState } from "react"; +import { formatDateToIndonesian } from "@/utils/globals"; + +export default function UserDetailPage() { + const router = useRouter(); + const params = useParams(); + const userId = params?.id ? Number(params.id) : undefined; + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function loadUserDetail() { + if (!userId) return; + + try { + setLoading(true); + const response = await getUserDetail(userId); + if (response && !response.error && response.data.data) { + setUser(response.data.data); + } else { + console.error("Gagal mengambil detail user:", response?.message || "Unknown error"); + } + } catch (error) { + console.error("Error loading user detail:", error); + } finally { + setLoading(false); + } + } + + loadUserDetail(); + }, [userId]); + + if (loading) { + return ( +
+ +
+
+
+

Loading user detail...

+
+
+
+
+ ); + } + + if (!user) { + return ( +
+ +
+

User tidak ditemukan

+ +
+
+
+ ); + } + + return ( +
+ +
+

Detail User

+
+ + +
+
+ +
+ {/* Basic Information */} +
+

Informasi Dasar

+ +
+ +

{user.id}

+
+ +
+ +

{user.fullname}

+
+ +
+ +

{user.username}

+
+ +
+ +

{user.email}

+
+ +
+ +

{user.phoneNumber}

+
+ +
+ +

{user.address || "-"}

+
+ +
+ +

{user.dateOfBirth ? formatDateToIndonesian(user.dateOfBirth) : "-"}

+
+
+ + {/* System Information */} +
+

Informasi Sistem

+ +
+ +

{user.userRoleId}

+
+ +
+ +

{user.userLevelId}

+
+ +
+ +

{user.userLevelGroup || "-"}

+
+ +
+ +

{user.statusId}

+
+ +
+ +

{user.keycloakId}

+
+ +
+ +

{user.createdById ? `User ID: ${user.createdById}` : "System"}

+
+
+ + {/* Status & Timeline */} +
+

Status & Timeline

+ +
+ +
+
+

+ {user.isActive ? 'Aktif' : 'Tidak Aktif'} +

+
+
+ +
+ +

{formatDateToIndonesian(user.createdAt)}

+
+ +
+ +

{formatDateToIndonesian(user.updatedAt)}

+
+ +
+ +

{user.profilePicturePath ? "Tersedia" : "Tidak ada"}

+
+
+ + {/* Additional Information (only show if data exists) */} + {(user.genderType || user.identityType || user.identityNumber || user.lastEducation || user.workType) && ( +
+

Informasi Tambahan

+ + {user.genderType && ( +
+ +

{user.genderType}

+
+ )} + + {user.identityType && ( +
+ +

{user.identityType}

+
+ )} + + {user.identityNumber && ( +
+ +

{user.identityNumber}

+
+ )} + + {user.lastEducation && ( +
+ +

{user.lastEducation}

+
+ )} + + {user.workType && ( +
+ +

{user.workType}

+
+ )} +
+ )} +
+
+
+ ); +} \ No newline at end of file diff --git a/app/[locale]/(admin)/admin/management-user/internal/edit/[id]/page.tsx b/app/[locale]/(admin)/admin/management-user/edit/[id]/page.tsx similarity index 88% rename from app/[locale]/(admin)/admin/management-user/internal/edit/[id]/page.tsx rename to app/[locale]/(admin)/admin/management-user/edit/[id]/page.tsx index 57e1fcd..a35150b 100644 --- a/app/[locale]/(admin)/admin/management-user/internal/edit/[id]/page.tsx +++ b/app/[locale]/(admin)/admin/management-user/edit/[id]/page.tsx @@ -1,11 +1,12 @@ "use client"; -import { useRouter, useParams } from "@/i18n/routing"; +import { useRouter } from "@/i18n/routing"; import UserForm from "@/components/form/user/user-form"; +import { useSearchParams } from "next/navigation"; export default function EditUserPage() { const router = useRouter(); - const params = useParams(); + const params = useSearchParams(); const userId = params?.id ? Number(params.id) : undefined; const handleSuccess = () => { @@ -42,4 +43,4 @@ export default function EditUserPage() { /> ); -} \ No newline at end of file +} diff --git a/app/[locale]/(admin)/admin/management-user/internal/detail/[id]/page.tsx b/app/[locale]/(admin)/admin/management-user/internal/detail/[id]/page.tsx deleted file mode 100644 index 4ef6416..0000000 --- a/app/[locale]/(admin)/admin/management-user/internal/detail/[id]/page.tsx +++ /dev/null @@ -1,733 +0,0 @@ -"use client"; - -import SiteBreadcrumb from "@/components/site-breadcrumb"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { Check, ChevronsUpDown } from "lucide-react"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { cn, getCookiesDecrypt } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from "@/components/ui/command"; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { useEffect, useState } from "react"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Link, useRouter } from "@/i18n/routing"; -import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import dynamic from "next/dynamic"; -import { Checkbox } from "@/components/ui/checkbox"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import Swal from "sweetalert2"; -import withReactContent from "sweetalert2-react-content"; -import { close, error, loading } from "@/config/swal"; -import { useParams } from "next/navigation"; -import { AdministrationLevelList, getListCompetencies, getListEducation, getListSchools, getUserById, saveUserInternal } from "@/service/service/management-user/management-user"; - -const sns = [ - { - key: 1, - id: "comment", - typeId: 1, - name: "Komentar Konten", - }, - { - key: 2, - id: "fb", - typeId: 2, - name: "Facebook", - }, - { - key: 3, - id: "ig", - typeId: 3, - name: "Instagram", - }, - { - key: 4, - id: "twt", - typeId: 4, - name: "Twitter", - }, - { - key: 5, - id: "yt", - typeId: 5, - name: "Youtube", - }, - { - key: 6, - id: "emergency", - typeId: 6, - name: "Emergency Issue", - }, - { - key: 7, - id: "email", - typeId: 7, - name: "Email", - }, - { - key: 8, - id: "inbox", - typeId: 8, - name: "Pesan Masuk", - }, - { - key: 9, - id: "whatsapp", - typeId: 9, - name: "Whatssapp", - }, - { - key: 10, - id: "tiktok", - typeId: 10, - name: "Tiktok", - }, -]; - -interface RoleData { - id: number; - label: string; - name: string; - value: string; - levelNumber: number; -} - -const FormSchema = z.object({ - level: z.string({ - required_error: "Required", - }), - fullname: z.string({ - required_error: "Required", - }), - username: z.string({ - required_error: "Required", - }), - role: z.string({ - required_error: "Required", - }), - nrp: z.string({ - required_error: "Required", - }), - address: z.string({ - required_error: "Required", - }), - email: z.string({ - required_error: "Required", - }), - phoneNumber: z.string({ - required_error: "Required", - }), - password: z.string({ - required_error: "Required", - }), - confirmPassword: z.string({ - required_error: "Required", - }), - isValidPassword: z.boolean().refine((val) => val === true, { - message: "Check Password", - }), - sns: z.array(z.string()).optional(), - education: z.string().optional(), - school: z.string().optional(), - competency: z.string().optional(), -}); - -export default function DetailUserForm() { - const router = useRouter(); - const params = useParams(); - const id = params?.id; - const MySwal = withReactContent(Swal); - const levelName = getCookiesDecrypt("ulnae"); - const [roleList, setRoleList] = useState([]); - - const [userEducations, setUserEducations] = useState(); - const [userSchools, setUserSchools] = useState(); - const [userCompetencies, setUserCompetencies] = useState(); - - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: { - password: "", - confirmPassword: "", - sns: [], - education: "1", - school: "4", - competency: "2", - }, - }); - - const selectedRole = form.watch("role"); - - useEffect(() => { - getDataAdditional(); - initData(); - }, []); - - const initData = async () => { - loading(); - const response = await getUserById(String(id)); - const res = response?.data?.data; - close(); - console.log("res", res); - if (Number(res.roleId) > 4) { - form.setValue("fullname", res?.fullname); - form.setValue("username", res?.username); - form.setValue("phoneNumber", res?.phoneNumber); - form.setValue("nrp", res?.memberIdentity); - form.setValue("address", res?.address); - form.setValue("email", res?.email); - form.setValue("role", res?.role?.code); - form.setValue("level", String(res?.userLevelId)); - } else { - initFetch(); - console.log("sadad", res?.role?.code); - form.setValue("fullname", res?.fullname); - form.setValue("username", res?.username); - form.setValue("phoneNumber", res?.phoneNumber); - form.setValue("nrp", res?.memberIdentity); - form.setValue("address", res?.address); - form.setValue("email", res?.email); - form.setValue("role", res?.role?.code); - form.setValue("level", String(res?.userLevelId)); - } - }; - const initFetch = async () => { - const response = await AdministrationLevelList(); - const res = response?.data?.data; - var levelsArr: RoleData[] = []; - res.forEach((levels: RoleData) => { - levelsArr.push({ - id: levels.id, - label: levels.name, - name: levels.name, - value: String(levels.id), - levelNumber: levels.levelNumber, - }); - }); - setRoleList(levelsArr); - }; - - async function getDataAdditional() { - const resEducations = await getListEducation(); - setUserEducations(resEducations?.data?.data); - const resSchools = await getListSchools(); - setUserSchools(resSchools?.data?.data); - const resCompetencies = await getListCompetencies(); - setUserCompetencies(resCompetencies?.data?.data); - } - - const roles = - levelName == "MABES POLRI" - ? [ - { - id: "ADM-ID", - name: "Admin", - }, - { - id: "APP-ID", - name: "Approver", - }, - { - id: "CON-ID", - name: "Kontributor", - }, - { - id: "SPV-ID", - name: "Supervisor Feedback Center", - }, - { - id: "OPT-ID", - name: "Operator Feedback Center", - }, - { - id: "KKUR-ID", - name: "Koor Kurator", - }, - { - id: "KUR-ID", - name: "Kurator", - }, - ] - : [ - { - id: "APP-ID", - name: "Approver", - }, - { - id: "CON-ID", - name: "Kontributor", - }, - ]; - - async function save(data: z.infer) { - let req: any = { - id: id, - firstName: data.fullname, - username: data.username, - roleId: data.role, - userLevelId: Number(data.level), - memberIdentity: data.nrp, - address: data.address, - email: data.email, - password: data.password, - passwordConf: data.confirmPassword, - isDefault: false, - }; - - if (data.role == "OPT-ID") { - req.handledSocialMedia = data?.sns ? data.sns.join(",") : ""; - } - - if (data.role == "KUR-ID") { - req.userEducationId = Number(data.education); - req.userSchoolsId = Number(data.school); - req.userCompetencyId = Number(data.competency); - } - - loading(); - const response = await saveUserInternal(req); - - if (response?.error) { - error(response.message); - return false; - } - - close(); - MySwal.fire({ - title: "Sukses", - icon: "success", - showCancelButton: true, - confirmButtonColor: "#3085d6", - confirmButtonText: "Simpan", - }).then((result) => { - if (result.isConfirmed) { - router.push("/admin/management-user"); - } - }); - return false; - } - - async function onSubmit(data: z.infer) { - MySwal.fire({ - title: "Simpan Data?", - text: "", - icon: "warning", - showCancelButton: true, - cancelButtonColor: "#d33", - confirmButtonColor: "#3085d6", - confirmButtonText: "Simpan", - }).then((result) => { - if (result.isConfirmed) { - save(data); - } - }); - } - - return ( -
- -
- -

Data Pengelola Media Hub

- ( - - Pilih Level - - - - - - - - - - - No role found. - - {roleList.map((role) => ( - { - form.setValue("level", role.value); - }} - > - {role.label} - - - ))} - - - - - - - - )} - /> - ( - - Nama Lengkap - - - - - - - )} - /> - ( - - Username - - - - - - - )} - /> - - ( - - Role - - - {roles.map((role) => ( - - - - - - {role.name} - - - ))} - - - - - )} - /> - {selectedRole === "OPT-ID" && ( - ( - -
- Social Media Yang Ditangani -
-
- {sns.map((item) => ( - { - return ( - - - { - return checked - ? field.onChange([ - ...(field.value || []), - String(item.typeId), - ]) - : field.onChange( - (field.value || []).filter( - (value) => - value !== String(item.typeId) - ) - ); - }} - /> - - - {item.name} - - - ); - }} - /> - ))} -
- - -
- )} - /> - )} - - {selectedRole === "KUR-ID" && ( - <> - ( - - Pendidikan Terakhir - - - - - )} - /> - ( - - Universitas / Perguruan Tinggi - - - - - )} - /> - ( - - Kompetensi - - - - - )} - /> - - )} - ( - - Nomor Regitrasi Polri {`(NRP)`} - - - - - - - )} - /> - - ( - - Alamat - -