diff --git a/src/app/api/portofolio/[id]/route.ts b/src/app/api/portofolio/[id]/route.ts index d6d46d28..0760c303 100644 --- a/src/app/api/portofolio/[id]/route.ts +++ b/src/app/api/portofolio/[id]/route.ts @@ -13,6 +13,18 @@ async function GET(request: Request, { params }: { params: { id: string } }) { id: id, }, include: { + Portofolio_BidangDanSubBidangBisnis: { + select: { + id: true, + MasterSubBidangBisnis: { + select: { + id: true, + name: true, + masterBidangBisnisId: true, + }, + }, + }, + }, MasterBidangBisnis: { select: { id: true, @@ -84,10 +96,26 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { const { id } = params; const { data } = await request.json(); - const udpateData = await prisma.portofolio.update({ - where: { - id: id, + const checkData = await prisma.portofolio.findUnique({ + where: { id }, + include: { + Portofolio_BidangDanSubBidangBisnis: true, }, + }); + + if (!checkData) { + return NextResponse.json( + { + success: false, + message: "Data tidak ditemukan", + }, + { status: 404 } + ); + } + + // Update data utama portofolio + const updatePortofolio = await prisma.portofolio.update({ + where: { id }, data: { namaBisnis: data.namaBisnis, alamatKantor: data.alamatKantor, @@ -97,25 +125,77 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { }, }); - if (!udpateData) - return NextResponse.json( - { - success: false, - message: "Gagal update data", - }, - { status: 400 } + const bidangBerubah = + checkData.masterBidangBisnisId !== data.masterBidangBisnisId; + + if (bidangBerubah) { + // Bidang berubah → hapus semua sub bidang lama + await prisma.portofolio_BidangDanSubBidangBisnis.deleteMany({ + where: { portofolioId: id }, + }); + + // Tambahkan sub bidang baru + for (const sub of data.subBidang) { + await prisma.portofolio_BidangDanSubBidangBisnis.create({ + data: { + portofolioId: id, + masterBidangBisnisId: data.masterBidangBisnisId, + masterSubBidangBisnisId: sub.MasterSubBidangBisnis.id, + }, + }); + } + } else { + // Bidang tidak berubah → sinkronisasi sub bidang + + const existingSub = checkData.Portofolio_BidangDanSubBidangBisnis; + + const incomingIds = data.subBidang.map( + (sub: any) => sub.MasterSubBidangBisnis.id ); + const existingIds = existingSub.map( + (item) => item.masterSubBidangBisnisId + ); + + // 1. Hapus sub bidang yang sudah tidak dipilih + const toDelete = existingSub.filter( + (item) => !incomingIds.includes(item.masterSubBidangBisnisId) + ); + + await prisma.portofolio_BidangDanSubBidangBisnis.deleteMany({ + where: { + id: { + in: toDelete.map((item) => item.id), + }, + }, + }); + + // 2. Tambahkan sub bidang baru yang belum ada di DB + const toCreate = data.subBidang.filter( + (sub: any) => !existingIds.includes(sub.MasterSubBidangBisnis.id) + ); + + for (const sub of toCreate) { + await prisma.portofolio_BidangDanSubBidangBisnis.create({ + data: { + portofolioId: id, + masterBidangBisnisId: data.masterBidangBisnisId, + masterSubBidangBisnisId: sub.MasterSubBidangBisnis.id, + }, + }); + } + } + return NextResponse.json( { success: true, - message: "Berhasil mendapatkan data", - data: udpateData, + message: "Berhasil update data", + data: updatePortofolio, }, - { status: 200 } ); } catch (error) { + backendLogger.error("Error update data portofolio", error); return NextResponse.json( { success: false, @@ -127,6 +207,8 @@ async function PUT(request: Request, { params }: { params: { id: string } }) { } } + + async function POST(request: Request, { params }: { params: { id: string } }) { if (request.method !== "POST") { return NextResponse.json( @@ -156,7 +238,6 @@ async function POST(request: Request, { params }: { params: { id: string } }) { }); for (let i of data.subBidang) { - // console.log("sub bidang", i.id) const createSubBidang = await prisma.portofolio_BidangDanSubBidangBisnis.create({ data: { @@ -166,7 +247,6 @@ async function POST(request: Request, { params }: { params: { id: string } }) { }, }); - if (!createSubBidang) return NextResponse.json( { diff --git a/src/app/dev/(user)/portofolio/edit/data/[id]/page.tsx b/src/app/dev/(user)/portofolio/edit/data/[id]/page.tsx index 625d8ee4..23e0b3c4 100644 --- a/src/app/dev/(user)/portofolio/edit/data/[id]/page.tsx +++ b/src/app/dev/(user)/portofolio/edit/data/[id]/page.tsx @@ -1,9 +1,11 @@ import { Portofolio_EditDataBisnis } from "@/app_modules/katalog/portofolio"; +import Portofolio_V3_EditDataBisnis from "@/app_modules/katalog/portofolio/edit/data/ui_new_edit_data"; export default async function Page() { return ( <> - + {/* */} + ); } diff --git a/src/app_modules/katalog/portofolio/create/new_create.tsx b/src/app_modules/katalog/portofolio/create/new_create.tsx index 1bb10804..37ee476b 100644 --- a/src/app_modules/katalog/portofolio/create/new_create.tsx +++ b/src/app_modules/katalog/portofolio/create/new_create.tsx @@ -36,6 +36,7 @@ import { Portofolio_ComponentButtonSelanjutnya } from "../component"; import { apiGetSubBidangBisnis } from "../lib/api_portofolio"; import { MODEL_PORTOFOLIO_BIDANG_BISNIS } from "../model/interface"; + export default function Portofolio_V3_Create() { const params = useParams<{ id: string }>(); const profileId = params.id; @@ -172,9 +173,6 @@ export default function Portofolio_V3_Create() { setDataPortofolio({ ...dataPortofolio, masterBidangBisnisId: val, - // masterSubBidangBisnisId: isSameBidang - // ? dataPortofolio.masterSubBidangBisnisId - // : "", }); // Jika berbeda bidang, reset sub bidang ke satu input kosong diff --git a/src/app_modules/katalog/portofolio/edit/data/ui_new_edit_data.tsx b/src/app_modules/katalog/portofolio/edit/data/ui_new_edit_data.tsx new file mode 100644 index 00000000..47a178e5 --- /dev/null +++ b/src/app_modules/katalog/portofolio/edit/data/ui_new_edit_data.tsx @@ -0,0 +1,610 @@ +"use client"; + +import { MainColor } from "@/app_modules/_global/color/color_pallet"; +import ComponentGlobal_ErrorInput from "@/app_modules/_global/component/error_input"; +import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown"; +import { apiGetMasterBidangBisnis } from "@/app_modules/_global/lib/api_fetch_master"; +import { ComponentGlobal_NotifikasiPeringatan } from "@/app_modules/_global/notif_global"; +import { ComponentGlobal_NotifikasiBerhasil } from "@/app_modules/_global/notif_global/notifikasi_berhasil"; +import { ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global/notifikasi_gagal"; +import { clientLogger } from "@/util/clientLogger"; +import { + ActionIcon, + Box, + Button, + Center, + Grid, + Select, + Stack, + Styles, + Text, + TextInput, + Textarea, +} from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import _ from "lodash"; +import { useParams, useRouter } from "next/navigation"; +import { useState, useEffect } from "react"; +import { PhoneInput } from "react-international-phone"; +import { + apiGetPortofolioById, + apiUpdatePortofolioById, +} from "../../component/api_fetch_portofolio"; +import { Portofolio_SkeletonEditDataBisnis } from "../../component/skeleton_view"; +import { + MODEL_PORTOFOLIO, + MODEL_PORTOFOLIO_BIDANG_BISNIS, +} from "../../model/interface"; +import { ISUB_BIDANG_BISNIS } from "@/app_modules/model_global/portofolio"; +import { apiGetSubBidangBisnis } from "../../lib/api_portofolio"; +import { BaseSelectStylesNames } from "@mantine/core/lib/Select/types"; +import { IconPlus, IconRowRemove, IconTrash } from "@tabler/icons-react"; +import Component_V3_Label_TextInput from "@/app_modules/_global/component/new/comp_V3_label_text_input"; + +interface SubBidangSelected { + id: string; + MasterSubBidangBisnis: { + id: string; + name: string; + }; +} + +interface IUpdatePortofoli { + namaBisnis: string; + alamatKantor: string; + tlpn: string; + deskripsi: string; + masterBidangBisnisId: string; + subBidang: SubBidangSelected[]; +} + +export default function Portofolio_EditDataBisnis() { + const router = useRouter(); + const [loading, setLoading] = useState(false); + + const params = useParams<{ id: string }>(); + const portofolioId = params.id; + const [data, setData] = useState(null); + const [listBidang, setListBidang] = useState< + MODEL_PORTOFOLIO_BIDANG_BISNIS[] + >([]); + + const [listSubBidang, setListSubBidang] = useState< + ISUB_BIDANG_BISNIS[] | null + >(null); + + const [selectedSubBidang, setSelectedSubBidang] = useState< + ISUB_BIDANG_BISNIS[] | null + >(null); + + const [listSubBidangSelected, setListSubBidangSelected] = useState< + SubBidangSelected[] + >([ + { + id: "", + MasterSubBidangBisnis: { + id: "", + name: "", + }, + }, + ]); + + useShallowEffect(() => { + onLoadData(); + onLoadBidang(); + onLoadMasterSubBidangBisnis(); + }, []); + + const onLoadData = async () => { + try { + const respone = await apiGetPortofolioById({ + id: portofolioId, + }); + + if (respone.success) { + setData(respone.data); + + // Cek apakah ada sub bidang bisnis yang terpilih + const subBidangData = respone.data.Portofolio_BidangDanSubBidangBisnis; + + // Jika ada sub bidang, gunakan data tersebut + if (subBidangData && subBidangData.length > 0) { + setListSubBidangSelected(subBidangData); + } else { + // Jika tidak ada sub bidang yang terpilih sebelumnya, tetap inisialisasi dengan array kosong + setListSubBidangSelected([ + { + id: "", + MasterSubBidangBisnis: { + id: "", + name: "", + }, + }, + ]); + } + + const bisnisId = respone.data.MasterBidangBisnis.id; + if (bisnisId) { + handlerLoadSelectedSubBidang({ id: bisnisId }); + } + } else { + setData(null); + } + } catch (error) { + clientLogger.error("Error get data portofolio", error); + } + }; + + const onLoadBidang = async () => { + try { + const respone = await apiGetMasterBidangBisnis(); + + if (respone.success) { + setListBidang(respone.data); + } else { + setListBidang([]); + } + } catch (error) { + clientLogger.error("Error get data master bidang bisnis", error); + } + }; + + async function onLoadMasterSubBidangBisnis() { + try { + const response = await apiGetSubBidangBisnis({}); + + if (response.success) { + setListSubBidang(response.data); + } + } catch (error) { + console.error("Error on load master sub bidang bisnis", error); + } + } + + const validateData = async (data: any) => { + if (_.values(data).includes("")) { + return "Lengkapi data"; + } + + if (data?.tlpn?.length < 8) { + return "Nomor telepon minimal 8 digit"; + } + + // Validasi sub bidang bisnis yang dipilih + // Pastikan setidaknya satu sub bidang dipilih + const validSubBidangCount = listSubBidangSelected.filter( + (item) => item.MasterSubBidangBisnis.id + ).length; + + if (validSubBidangCount === 0) { + return "Pilih minimal satu sub bidang bisnis"; + } + + return null; + }; + + const hanldeUpadteData = async (data: any) => { + try { + // Filter list sub bidang yang dipilih (hanya ambil yang memiliki id) + const validSubBidang = listSubBidangSelected.filter( + (item) => item.MasterSubBidangBisnis.id + ); + + const newData: IUpdatePortofoli = { + namaBisnis: data?.namaBisnis, + alamatKantor: data?.alamatKantor, + tlpn: data?.tlpn, + deskripsi: data?.deskripsi, + masterBidangBisnisId: data?.MasterBidangBisnis.id, + subBidang: validSubBidang, // Hanya kirim sub bidang yang valid + }; + + const respone = await apiUpdatePortofolioById({ + data: newData, + id: portofolioId, + }); + + return respone; + } catch (error) { + console.error("Error update data portofolio", error); + return null; + } + }; + + const submitUpdate = async () => { + const validate = await validateData(data); + if (validate) { + ComponentGlobal_NotifikasiPeringatan(validate); + return; + } + + try { + setLoading(true); + const updateData = await hanldeUpadteData(data); + + if (updateData.success) { + ComponentGlobal_NotifikasiBerhasil(updateData.message); + router.back(); + } else { + setLoading(false); + ComponentGlobal_NotifikasiGagal(updateData.message); + } + } catch (error) { + setLoading(false); + console.error("Error update data portofolio", error); + } + }; + + const baseStyles: Styles> = { + label: { + color: MainColor.white, + }, + input: { + backgroundColor: MainColor.white, + }, + }; + + // Handler untuk perubahan bidang bisnis + const handleBidangBisnisChange = (val: string) => { + const isSameBidang = data?.MasterBidangBisnis?.id === val; + + setData({ + ...(data as any), + MasterBidangBisnis: { + id: val, + }, + }); + + // Reset sub bidang jika ganti bidang + if (!isSameBidang) { + setListSubBidangSelected([ + { + id: "", + MasterSubBidangBisnis: { id: "", name: "" }, + }, + ]); + } + + handlerLoadSelectedSubBidang({ id: val }); + }; + + // Handler untuk saat komponen pertama kali load + const handlerLoadSelectedSubBidang = ({ id }: { id: string }) => { + if (!listSubBidang) return; + + const filteredSubBidang = listSubBidang.filter( + (item) => item.masterBidangBisnisId === id + ); + + setSelectedSubBidang(filteredSubBidang); + }; + + // Handler untuk menambah sub bidang bisnis + const handleAddSubBidang = () => { + setListSubBidangSelected([ + ...listSubBidangSelected, + { + id: "", + MasterSubBidangBisnis: { id: "", name: "" }, + }, + ]); + }; + + // Handler untuk menghapus sub bidang bisnis + const handleRemoveSubBidang = (index: number) => { + if (listSubBidangSelected.length <= 1) return; + + const updatedList = [...listSubBidangSelected]; + updatedList.splice(index, 1); + setListSubBidangSelected(updatedList); + }; + + // Handler untuk update sub bidang + const handleSubBidangChange = (val: string, index: number) => { + const selected = selectedSubBidang?.find((s) => s.id === val); + const list = _.cloneDeep(listSubBidangSelected); + + list[index] = { + id: "", + MasterSubBidangBisnis: selected || { + id: val, + name: "", + }, + }; + + setListSubBidangSelected(list); + }; + + // Effect untuk mengupdate selectedSubBidang saat listSubBidang berubah + useShallowEffect(() => { + if (data?.MasterBidangBisnis?.id && listSubBidang) { + handlerLoadSelectedSubBidang({ id: data.MasterBidangBisnis.id }); + } + }, [listSubBidang, data?.MasterBidangBisnis?.id]); + + if (!data || !listBidang || !listSubBidang) + return ; + + return ( + <> + + + + ) : ( + "" + ) + } + onChange={(val) => { + setData({ + ...data, + namaBisnis: val.target.value, + }); + }} + /> + + {/* Select Bidang dan Sub Bidang */} + 0 + ? "Pilih sub bidang bisnis" + : "Menunggu pilihan bidang bisnis" + } + value={e.MasterSubBidangBisnis.id} + data={availableSubBidangOptions} + onChange={(val) => + handleSubBidangChange(val as any, index) + } + /> + + + + {index > 0 ? ( + handleRemoveSubBidang(index)} + > + + + ) : ( + + )} + + + + + {listSubBidangSelected.length > 1 && + e.MasterSubBidangBisnis.id === "" ? ( + + ) : undefined} + + + + {/* Tombol untuk menghapus/menambah sub bidang bisnis */} + + {index === listSubBidangSelected.length - 1 && ( +
+ +
+ )} +
+
+ + ); + })} + + {/* Select Bidang dan Sub Bidang */} + + + ) : ( + "" + ) + } + onChange={(val) => { + setData({ + ...data, + alamatKantor: val.target.value, + }); + }} + /> + + + + + { + const valPhone = val.substring(1); + setData({ + ...data, + tlpn: valPhone, + }); + }} + /> + + {data?.tlpn === "" ? ( + + ) : ( + "" + )} + + + +