fix create sub bidang portofolio
This commit is contained in:
@@ -129,11 +129,13 @@ model Portofolio {
|
|||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Profile Profile? @relation(fields: [profileId], references: [id])
|
Profile Profile? @relation(fields: [profileId], references: [id])
|
||||||
profileId String?
|
profileId String?
|
||||||
MasterBidangBisnis MasterBidangBisnis @relation(fields: [masterBidangBisnisId], references: [id])
|
|
||||||
masterBidangBisnisId String
|
|
||||||
Portofolio_MediaSosial Portofolio_MediaSosial?
|
Portofolio_MediaSosial Portofolio_MediaSosial?
|
||||||
BusinessMaps BusinessMaps?
|
BusinessMaps BusinessMaps?
|
||||||
logoId String?
|
logoId String?
|
||||||
|
|
||||||
|
MasterBidangBisnis MasterBidangBisnis @relation(fields: [masterBidangBisnisId], references: [id])
|
||||||
|
masterBidangBisnisId String
|
||||||
|
Portofolio_BidangDanSubBidangBisnis Portofolio_BidangDanSubBidangBisnis[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Portofolio_MediaSosial {
|
model Portofolio_MediaSosial {
|
||||||
@@ -152,26 +154,42 @@ model Portofolio_MediaSosial {
|
|||||||
|
|
||||||
// ------------------- MASTER -------------------------- //
|
// ------------------- MASTER -------------------------- //
|
||||||
|
|
||||||
|
model Portofolio_BidangDanSubBidangBisnis {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
Portofolio Portofolio? @relation(fields: [portofolioId], references: [id])
|
||||||
|
portofolioId String?
|
||||||
|
MasterBidangBisnis MasterBidangBisnis? @relation(fields: [masterBidangBisnisId], references: [id])
|
||||||
|
masterBidangBisnisId String?
|
||||||
|
MasterSubBidangBisnis MasterSubBidangBisnis? @relation(fields: [masterSubBidangBisnisId], references: [id])
|
||||||
|
masterSubBidangBisnisId String?
|
||||||
|
}
|
||||||
|
|
||||||
model MasterBidangBisnis {
|
model MasterBidangBisnis {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String
|
name String
|
||||||
slug String @unique @default("NULL")
|
slug String @unique @default("NULL")
|
||||||
active Boolean @default(true)
|
active Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Portofolio Portofolio[]
|
Portofolio Portofolio[]
|
||||||
MasterSubBidangBisnis MasterSubBidangBisnis[]
|
MasterSubBidangBisnis MasterSubBidangBisnis[]
|
||||||
|
Portofolio_BidangDanSubBidangBisnis Portofolio_BidangDanSubBidangBisnis[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model MasterSubBidangBisnis {
|
model MasterSubBidangBisnis {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
slug String @unique @default("NULL")
|
slug String @unique @default("NULL")
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
MasterBidangBisnis MasterBidangBisnis? @relation(fields: [masterBidangBisnisId], references: [id])
|
MasterBidangBisnis MasterBidangBisnis? @relation(fields: [masterBidangBisnisId], references: [id])
|
||||||
masterBidangBisnisId String?
|
masterBidangBisnisId String?
|
||||||
|
Portofolio_BidangDanSubBidangBisnis Portofolio_BidangDanSubBidangBisnis[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model MasterBank {
|
model MasterBank {
|
||||||
|
|||||||
40
src/app/api/master/sub-bidang-bisnis/[id]/route.ts
Normal file
40
src/app/api/master/sub-bidang-bisnis/[id]/route.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { prisma } from "@/lib";
|
||||||
|
import backendLogger from "@/util/backendLogger";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(
|
||||||
|
request: Request,
|
||||||
|
{ params }: { params: { id: string } }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
let fixData;
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
fixData = await prisma.masterSubBidangBisnis.findMany({
|
||||||
|
where: {
|
||||||
|
masterBidangBisnisId: id.toString(),
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
message: "Berhasil mendapatkan data",
|
||||||
|
data: fixData,
|
||||||
|
},
|
||||||
|
{ status: 200 }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
backendLogger.error("Error Get Master Sub Bidang Bisnis >>", error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "API Error Get Data",
|
||||||
|
reason: (error as Error).message,
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/app/api/master/sub-bidang-bisnis/route.ts
Normal file
33
src/app/api/master/sub-bidang-bisnis/route.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { prisma } from "@/lib";
|
||||||
|
import backendLogger from "@/util/backendLogger";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
try {
|
||||||
|
let fixData;
|
||||||
|
fixData = await prisma.masterSubBidangBisnis.findMany({
|
||||||
|
where: {
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
message: "Berhasil mendapatkan data",
|
||||||
|
data: fixData,
|
||||||
|
},
|
||||||
|
{ status: 200 }
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
backendLogger.error("Error Get Master Sub Bidang Bisnis >>", error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "API Error Get Data",
|
||||||
|
reason: (error as Error).message,
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,15 @@ export async function GET(
|
|||||||
userId: true,
|
userId: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Portofolio_BidangDanSubBidangBisnis: {
|
||||||
|
select: {
|
||||||
|
MasterSubBidangBisnis: {
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -47,6 +56,7 @@ export async function GET(
|
|||||||
deskripsi: data?.deskripsi,
|
deskripsi: data?.deskripsi,
|
||||||
logoId: data?.logoId,
|
logoId: data?.logoId,
|
||||||
bidangBisnis: data?.MasterBidangBisnis?.name,
|
bidangBisnis: data?.MasterBidangBisnis?.name,
|
||||||
|
subBidangBisnis: data?.Portofolio_BidangDanSubBidangBisnis?.map((item) => item.MasterSubBidangBisnis?.name),
|
||||||
authorId: data?.Profile?.userId,
|
authorId: data?.Profile?.userId,
|
||||||
};
|
};
|
||||||
} else if (kategori == "lokasi") {
|
} else if (kategori == "lokasi") {
|
||||||
|
|||||||
@@ -155,6 +155,28 @@ 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: {
|
||||||
|
portofolioId: createPortofolio.id,
|
||||||
|
masterBidangBisnisId: data.masterBidangBisnisId,
|
||||||
|
masterSubBidangBisnisId: i.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (!createSubBidang)
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: "Gagal membuat sub bidang bisnis",
|
||||||
|
},
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!createPortofolio)
|
if (!createPortofolio)
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { CreatePortofolio } from "@/app_modules/katalog/portofolio";
|
import { CreatePortofolio } from "@/app_modules/katalog/portofolio";
|
||||||
|
import Portofolio_V3_Create from "@/app_modules/katalog/portofolio/create/new_create";
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreatePortofolio />
|
{/* <CreatePortofolio /> */}
|
||||||
|
<Portofolio_V3_Create/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,22 +3,24 @@
|
|||||||
import { APIs } from "@/lib";
|
import { APIs } from "@/lib";
|
||||||
import { pathAssetImage } from "@/lib/path_asset_image";
|
import { pathAssetImage } from "@/lib/path_asset_image";
|
||||||
import { RouterImagePreview } from "@/lib/router_hipmi/router_image_preview";
|
import { RouterImagePreview } from "@/lib/router_hipmi/router_image_preview";
|
||||||
import { Center, Image, Skeleton } from "@mantine/core";
|
import { Center, Image, MantineNumberSize, Skeleton } from "@mantine/core";
|
||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
type IRadius = "xs" | "sm" | "md" | "lg" | "xl";
|
type IRadius = MantineNumberSize | undefined
|
||||||
export function ComponentGlobal_LoadImage({
|
export function ComponentGlobal_LoadImage({
|
||||||
fileId,
|
fileId,
|
||||||
maw,
|
maw,
|
||||||
h,
|
h,
|
||||||
radius,
|
radius,
|
||||||
|
style,
|
||||||
}: {
|
}: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
maw?: number | string;
|
maw?: number | string;
|
||||||
h?: number;
|
h?: number;
|
||||||
radius?: IRadius;
|
radius?: IRadius;
|
||||||
|
style?: React.CSSProperties;
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isImage, setIsImage] = useState<boolean | null>(null);
|
const [isImage, setIsImage] = useState<boolean | null>(null);
|
||||||
@@ -63,6 +65,9 @@ export function ComponentGlobal_LoadImage({
|
|||||||
<>
|
<>
|
||||||
<Center h={"100%"}>
|
<Center h={"100%"}>
|
||||||
<Image
|
<Image
|
||||||
|
style={{
|
||||||
|
...style
|
||||||
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
router.push(RouterImagePreview.main({ id: fileId }), {
|
router.push(RouterImagePreview.main({ id: fileId }), {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ import { useRouter } from "next/navigation";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { apiCreatePortofolio } from "../api_fetch_portofolio";
|
import { apiCreatePortofolio } from "../api_fetch_portofolio";
|
||||||
|
|
||||||
|
|
||||||
|
type SubBidang = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
interface ICreatePortofolio {
|
interface ICreatePortofolio {
|
||||||
namaBisnis: string;
|
namaBisnis: string;
|
||||||
masterBidangBisnisId: string;
|
masterBidangBisnisId: string;
|
||||||
@@ -28,18 +32,23 @@ interface ICreatePortofolio {
|
|||||||
instagram: string;
|
instagram: string;
|
||||||
tiktok: string;
|
tiktok: string;
|
||||||
youtube: string;
|
youtube: string;
|
||||||
|
subBidang: SubBidang[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function Portofolio_ComponentButtonSelanjutnya({
|
export function Portofolio_ComponentButtonSelanjutnya({
|
||||||
profileId,
|
profileId,
|
||||||
dataPortofolio,
|
dataPortofolio,
|
||||||
dataMedsos,
|
dataMedsos,
|
||||||
file,
|
file,
|
||||||
|
listSubBidangSelected,
|
||||||
}: {
|
}: {
|
||||||
profileId: string;
|
profileId: string;
|
||||||
dataPortofolio: MODEL_PORTOFOLIO_OLD;
|
dataPortofolio: MODEL_PORTOFOLIO_OLD;
|
||||||
dataMedsos: any;
|
dataMedsos: any;
|
||||||
file: File;
|
file: File;
|
||||||
|
listSubBidangSelected?: SubBidang[];
|
||||||
}) {
|
}) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -62,6 +71,7 @@ export function Portofolio_ComponentButtonSelanjutnya({
|
|||||||
const newData: ICreatePortofolio = {
|
const newData: ICreatePortofolio = {
|
||||||
namaBisnis: dataPortofolio.namaBisnis,
|
namaBisnis: dataPortofolio.namaBisnis,
|
||||||
masterBidangBisnisId: dataPortofolio.masterBidangBisnisId,
|
masterBidangBisnisId: dataPortofolio.masterBidangBisnisId,
|
||||||
|
// masterSubBidangBisnisId: dataPortofolio.masterSubBidangBisnisId as string,
|
||||||
alamatKantor: dataPortofolio.alamatKantor,
|
alamatKantor: dataPortofolio.alamatKantor,
|
||||||
tlpn: dataPortofolio.tlpn,
|
tlpn: dataPortofolio.tlpn,
|
||||||
deskripsi: dataPortofolio.deskripsi,
|
deskripsi: dataPortofolio.deskripsi,
|
||||||
@@ -71,6 +81,7 @@ export function Portofolio_ComponentButtonSelanjutnya({
|
|||||||
tiktok: dataMedsos.tiktok,
|
tiktok: dataMedsos.tiktok,
|
||||||
youtube: dataMedsos.youtube,
|
youtube: dataMedsos.youtube,
|
||||||
fileId: fileId,
|
fileId: fileId,
|
||||||
|
subBidang: listSubBidangSelected || []
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await apiCreatePortofolio({
|
const response = await apiCreatePortofolio({
|
||||||
@@ -91,8 +102,10 @@ export function Portofolio_ComponentButtonSelanjutnya({
|
|||||||
if (!validateData()) return;
|
if (!validateData()) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log("listSubBidangSelected>>", listSubBidangSelected);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
|
|
||||||
const uploadFile = await funGlobal_UploadToStorage({
|
const uploadFile = await funGlobal_UploadToStorage({
|
||||||
file: file,
|
file: file,
|
||||||
dirId: DIRECTORY_ID.portofolio_logo,
|
dirId: DIRECTORY_ID.portofolio_logo,
|
||||||
@@ -107,14 +120,25 @@ export function Portofolio_ComponentButtonSelanjutnya({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
ComponentGlobal_NotifikasiGagal("Gagal disimpan");
|
ComponentGlobal_NotifikasiGagal("Gagal disimpan");
|
||||||
clientLogger.error("Error create portofolio", error);
|
console.error("Error create portofolio", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* <pre style={{ color: "white" }}>
|
||||||
|
{JSON.stringify(dataPortofolio, null, 2)}
|
||||||
|
</pre>
|
||||||
|
<pre style={{ color: "white" }}>
|
||||||
|
{JSON.stringify(listSubBidangSelected, null, 2)}
|
||||||
|
</pre> */}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
disabled={_.values(dataPortofolio).includes("") || !file}
|
disabled={
|
||||||
|
_.values(dataPortofolio).includes("") ||
|
||||||
|
!file ||
|
||||||
|
listSubBidangSelected?.some((item) => !item.id)
|
||||||
|
}
|
||||||
mt={"md"}
|
mt={"md"}
|
||||||
radius={50}
|
radius={50}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|||||||
505
src/app_modules/katalog/portofolio/create/new_create.tsx
Normal file
505
src/app_modules/katalog/portofolio/create/new_create.tsx
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { MainColor } from "@/app_modules/_global/color/color_pallet";
|
||||||
|
import {
|
||||||
|
ComponentGlobal_BoxUploadImage,
|
||||||
|
ComponentGlobal_ButtonUploadFileImage,
|
||||||
|
} from "@/app_modules/_global/component";
|
||||||
|
import ComponentGlobal_BoxInformation from "@/app_modules/_global/component/box_information";
|
||||||
|
import ComponentGlobal_InputCountDown from "@/app_modules/_global/component/input_countdown";
|
||||||
|
import { apiGetMasterBidangBisnis } from "@/app_modules/_global/lib/api_fetch_master";
|
||||||
|
import { ISUB_BIDANG_BISNIS } from "@/app_modules/model_global/portofolio";
|
||||||
|
import { clientLogger } from "@/util/clientLogger";
|
||||||
|
import {
|
||||||
|
AspectRatio,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Group,
|
||||||
|
Image,
|
||||||
|
Select,
|
||||||
|
Stack,
|
||||||
|
Styles,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
Textarea,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { BaseSelectStylesNames } from "@mantine/core/lib/Select/types";
|
||||||
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
|
import { IconMinus, IconPhoto, IconPlus } from "@tabler/icons-react";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { useParams } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { PhoneInput } from "react-international-phone";
|
||||||
|
import "react-international-phone/style.css";
|
||||||
|
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;
|
||||||
|
|
||||||
|
const [dataPortofolio, setDataPortofolio] = useState({
|
||||||
|
namaBisnis: "",
|
||||||
|
masterBidangBisnisId: "",
|
||||||
|
// masterSubBidangBisnisId: "",
|
||||||
|
alamatKantor: "",
|
||||||
|
tlpn: "",
|
||||||
|
deskripsi: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [dataMedsos, setDataMedsos] = useState({
|
||||||
|
facebook: "",
|
||||||
|
twitter: "",
|
||||||
|
instagram: "",
|
||||||
|
youtube: "",
|
||||||
|
tiktok: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [file, setFile] = useState<File | null>(null);
|
||||||
|
const [img, setImg] = useState<any | null>(null);
|
||||||
|
const [listBidangBisnis, setListBidangBisnis] = useState<
|
||||||
|
MODEL_PORTOFOLIO_BIDANG_BISNIS[] | null
|
||||||
|
>(null);
|
||||||
|
|
||||||
|
const [listSubBidang, setListSubBidang] = useState<
|
||||||
|
ISUB_BIDANG_BISNIS[] | null
|
||||||
|
>(null);
|
||||||
|
|
||||||
|
const [selectedSubBidang, setSelectedSubBidang] = useState<
|
||||||
|
ISUB_BIDANG_BISNIS[] | null
|
||||||
|
>(null);
|
||||||
|
const [listSubBidangSelected, setListSubBidangSelected] = useState([
|
||||||
|
{
|
||||||
|
id: "",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
onLoadMasterBidangBisnis();
|
||||||
|
onLoadMasterSubBidangBisnis();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
async function onLoadMasterBidangBisnis() {
|
||||||
|
try {
|
||||||
|
const respone = await apiGetMasterBidangBisnis();
|
||||||
|
|
||||||
|
if (respone.success) {
|
||||||
|
setListBidangBisnis(respone.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
clientLogger.error("Error on load master bidang bisnis", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onLoadMasterSubBidangBisnis() {
|
||||||
|
try {
|
||||||
|
const response = await apiGetSubBidangBisnis({});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
setListSubBidang(response.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
clientLogger.error("Error on load master sub bidang bisnis", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlerSelectedSubBidang = ({ id }: { id: string }) => {
|
||||||
|
const selectedList = listSubBidang?.filter(
|
||||||
|
(item) => item.masterBidangBisnisId === id
|
||||||
|
);
|
||||||
|
setSelectedSubBidang(selectedList as ISUB_BIDANG_BISNIS[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseStyles: Styles<BaseSelectStylesNames, Record<string, any>> = {
|
||||||
|
label: {
|
||||||
|
color: MainColor.white,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
backgroundColor: MainColor.white,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack px={"sm"} mb={"lg"} spacing={50}>
|
||||||
|
<Stack spacing={"sm"}>
|
||||||
|
<ComponentGlobal_BoxInformation informasi="Lengkapi data bisnis" />
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
label="Nama Bisnis"
|
||||||
|
placeholder="Nama bisnis"
|
||||||
|
maxLength={100}
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
namaBisnis: _.startCase(val.target.value),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
dropdown: {
|
||||||
|
backgroundColor: MainColor.white,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
label="Bidang Bisnis"
|
||||||
|
placeholder={
|
||||||
|
listBidangBisnis ? "Pilih bidang bisnis" : "Loading..."
|
||||||
|
}
|
||||||
|
data={_.map(listBidangBisnis as any).map((e: any) => ({
|
||||||
|
value: e.id,
|
||||||
|
label: e.name,
|
||||||
|
}))}
|
||||||
|
onChange={(val: any) => {
|
||||||
|
const isSameBidang = dataPortofolio.masterBidangBisnisId === val;
|
||||||
|
|
||||||
|
// Update data portofolio
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
masterBidangBisnisId: val,
|
||||||
|
// masterSubBidangBisnisId: isSameBidang
|
||||||
|
// ? dataPortofolio.masterSubBidangBisnisId
|
||||||
|
// : "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Jika berbeda bidang, reset sub bidang ke satu input kosong
|
||||||
|
if (!isSameBidang) {
|
||||||
|
setListSubBidangSelected([{ id: "" }]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panggil handler sub bidang berdasarkan bidang bisnis terpilih
|
||||||
|
handlerSelectedSubBidang({ id: val });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack>
|
||||||
|
{listSubBidangSelected.map((e, index) => (
|
||||||
|
<Box key={index}>
|
||||||
|
<Select
|
||||||
|
disabled={dataPortofolio.masterBidangBisnisId === ""}
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
dropdown: {
|
||||||
|
backgroundColor: MainColor.white,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
label={`Sub Bidang Bisnis ${index + 1}`}
|
||||||
|
placeholder={
|
||||||
|
selectedSubBidang
|
||||||
|
? "Pilih sub bidang bisnis"
|
||||||
|
: "Menunggu pilihan bidang bisnis"
|
||||||
|
}
|
||||||
|
data={_.map(selectedSubBidang as any)
|
||||||
|
.filter((option: any) => {
|
||||||
|
const selectedValues = listSubBidangSelected.map(
|
||||||
|
(s) => s.id
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
option.id === e.id || // biarkan tetap muncul kalau ini valuenya sendiri
|
||||||
|
!selectedValues.includes(option.id)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.map((e: any) => ({
|
||||||
|
value: e.id,
|
||||||
|
label: e.name,
|
||||||
|
}))}
|
||||||
|
value={e.id}
|
||||||
|
onChange={(val) => {
|
||||||
|
const list = _.clone(listSubBidangSelected);
|
||||||
|
list[index].id = val as any;
|
||||||
|
setListSubBidangSelected(list);
|
||||||
|
}}
|
||||||
|
error={
|
||||||
|
listSubBidangSelected.length > 1 && !e.id
|
||||||
|
? "Wajib dipilih / kurangi list"
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Group position="center">
|
||||||
|
<Button
|
||||||
|
disabled={
|
||||||
|
listSubBidangSelected.length === selectedSubBidang?.length
|
||||||
|
}
|
||||||
|
radius="xl"
|
||||||
|
leftIcon={<IconPlus size={15} />}
|
||||||
|
onClick={() => {
|
||||||
|
setListSubBidangSelected([
|
||||||
|
...listSubBidangSelected,
|
||||||
|
{ id: "" },
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
compact
|
||||||
|
bg={MainColor.yellow}
|
||||||
|
color="yellow"
|
||||||
|
c="black"
|
||||||
|
>
|
||||||
|
<Text fz={8}>Tambah List</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={listSubBidangSelected.length <= 1}
|
||||||
|
radius="xl"
|
||||||
|
leftIcon={<IconMinus size={15} />}
|
||||||
|
onClick={() => {
|
||||||
|
setListSubBidangSelected(listSubBidangSelected.slice(0, -1));
|
||||||
|
}}
|
||||||
|
compact
|
||||||
|
bg={MainColor.yellow}
|
||||||
|
color="yellow"
|
||||||
|
c="black"
|
||||||
|
>
|
||||||
|
<Text fz={8}>Kurangi List</Text>
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{/* <pre style={{ color: "white" }}>
|
||||||
|
{JSON.stringify(dataPortofolio, null, 2)}
|
||||||
|
</pre>
|
||||||
|
<pre style={{ color: "white" }}>
|
||||||
|
{JSON.stringify(listSubBidangSelected, null, 2)}
|
||||||
|
</pre> */}
|
||||||
|
|
||||||
|
{/* <Select
|
||||||
|
disabled={dataPortofolio.masterBidangBisnisId == ""}
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
dropdown: {
|
||||||
|
backgroundColor: MainColor.white,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
value={dataPortofolio.masterSubBidangBisnisId == ""
|
||||||
|
? null
|
||||||
|
: dataPortofolio.masterSubBidangBisnisId
|
||||||
|
}
|
||||||
|
withAsterisk
|
||||||
|
label="Sub Bidang Bisnis"
|
||||||
|
placeholder={
|
||||||
|
selectedSubBidang ? "Pilih sub bidang bisnis" : "Menunggu pilihan bidang bisnis"
|
||||||
|
}
|
||||||
|
data={_.map(selectedSubBidang as any).map((e: any) => ({
|
||||||
|
value: e.id,
|
||||||
|
label: e.name,
|
||||||
|
}))}
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
masterSubBidangBisnisId: val as any,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/> */}
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
withAsterisk
|
||||||
|
label="Alamat Bisnis"
|
||||||
|
placeholder="Alamat bisnis"
|
||||||
|
maxLength={100}
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
alamatKantor: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack spacing={5}>
|
||||||
|
<Text c={MainColor.white} fz={"sm"}>
|
||||||
|
Nomor Telepon{" "}
|
||||||
|
<Text c={"red"} span inherit>
|
||||||
|
*
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<PhoneInput
|
||||||
|
placeholder="Nomor telepon"
|
||||||
|
countrySelectorStyleProps={{
|
||||||
|
buttonStyle: {
|
||||||
|
backgroundColor: MainColor.login,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
inputStyle={{ width: "100%", backgroundColor: MainColor.white }}
|
||||||
|
defaultCountry="id"
|
||||||
|
onChange={(val) => {
|
||||||
|
const valPhone = val.substring(1);
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
|
||||||
|
tlpn: valPhone,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack spacing={5}>
|
||||||
|
<Textarea
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
required: {
|
||||||
|
color: MainColor.red,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
maxLength={300}
|
||||||
|
autosize
|
||||||
|
minRows={2}
|
||||||
|
maxRows={5}
|
||||||
|
withAsterisk
|
||||||
|
label="Deskripsi"
|
||||||
|
placeholder="Deskripsi singkat mengenai usaha"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataPortofolio({
|
||||||
|
...dataPortofolio,
|
||||||
|
deskripsi: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ComponentGlobal_InputCountDown
|
||||||
|
maxInput={300}
|
||||||
|
lengthInput={dataPortofolio.deskripsi.length}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack>
|
||||||
|
<ComponentGlobal_BoxInformation informasi="Upload logo bisnis anda untuk ditampilkan dalam portofolio " />
|
||||||
|
<ComponentGlobal_BoxUploadImage>
|
||||||
|
{img ? (
|
||||||
|
<AspectRatio ratio={1 / 1} mah={265} mx={"auto"}>
|
||||||
|
<Image
|
||||||
|
style={{ maxHeight: 250, margin: "auto", padding: "5px" }}
|
||||||
|
alt="Foto"
|
||||||
|
height={250}
|
||||||
|
src={img}
|
||||||
|
/>
|
||||||
|
</AspectRatio>
|
||||||
|
) : (
|
||||||
|
<Stack spacing={5} justify="center" align="center" h={"100%"}>
|
||||||
|
<IconPhoto size={100} />
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</ComponentGlobal_BoxUploadImage>
|
||||||
|
|
||||||
|
<Center>
|
||||||
|
<ComponentGlobal_ButtonUploadFileImage
|
||||||
|
onSetFile={setFile}
|
||||||
|
onSetImage={setImg}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack>
|
||||||
|
<ComponentGlobal_BoxInformation informasi="Isi hanya pada sosial media yang anda miliki" />
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
}}
|
||||||
|
label="Facebook"
|
||||||
|
maxLength={100}
|
||||||
|
placeholder="Facebook"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataMedsos({
|
||||||
|
...dataMedsos,
|
||||||
|
facebook: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
}}
|
||||||
|
label="Instagram"
|
||||||
|
maxLength={100}
|
||||||
|
placeholder="Instagram"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataMedsos({
|
||||||
|
...dataMedsos,
|
||||||
|
instagram: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
}}
|
||||||
|
label="Tiktok"
|
||||||
|
maxLength={100}
|
||||||
|
placeholder="Tiktok"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataMedsos({
|
||||||
|
...dataMedsos,
|
||||||
|
tiktok: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
}}
|
||||||
|
label="Twitter"
|
||||||
|
maxLength={100}
|
||||||
|
placeholder="Twitter"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataMedsos({
|
||||||
|
...dataMedsos,
|
||||||
|
twitter: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
styles={{
|
||||||
|
...baseStyles,
|
||||||
|
}}
|
||||||
|
label="Youtube"
|
||||||
|
maxLength={100}
|
||||||
|
placeholder="Youtube"
|
||||||
|
onChange={(val) => {
|
||||||
|
setDataMedsos({
|
||||||
|
...dataMedsos,
|
||||||
|
youtube: val.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Portofolio_ComponentButtonSelanjutnya
|
||||||
|
dataPortofolio={dataPortofolio as any}
|
||||||
|
listSubBidangSelected={listSubBidangSelected as any}
|
||||||
|
dataMedsos={dataMedsos}
|
||||||
|
profileId={profileId}
|
||||||
|
//
|
||||||
|
file={file as File}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -48,3 +48,46 @@ export const apiDeletePortofolio = async (path: string) => {
|
|||||||
|
|
||||||
return await response.json().catch(() => null);
|
return await response.json().catch(() => null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const apiGetSubBidangBisnis = async ({id}: {id?: string}) => {
|
||||||
|
try {
|
||||||
|
// Fetch token from cookie
|
||||||
|
const { token } = await fetch("/api/get-cookie").then((res) =>
|
||||||
|
res.json()
|
||||||
|
);
|
||||||
|
if (!token) {
|
||||||
|
console.error("No token found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bidangBisnisId = id ? `/${id}` : "";
|
||||||
|
const response = await fetch(`/api/master/sub-bidang-bisnis${bidangBisnisId}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if the response is OK
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => null);
|
||||||
|
console.error(
|
||||||
|
"Failed to get all forum:",
|
||||||
|
response.statusText,
|
||||||
|
errorData
|
||||||
|
);
|
||||||
|
throw new Error(errorData?.message || "Failed to get all forum");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the JSON response
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error get all forum", error);
|
||||||
|
throw error; // Re-throw the error to handle it in the calling function
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ export interface IDetailPortofolioBisnis {
|
|||||||
deskripsi: string
|
deskripsi: string
|
||||||
logoId: string
|
logoId: string
|
||||||
bidangBisnis: string
|
bidangBisnis: string
|
||||||
|
subBidangBisnis: string[]
|
||||||
authorId: string
|
authorId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export interface MODEL_PORTOFOLIO_BIDANG_BISNIS {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
|
slug: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MODEL_PORTOFOLIO_MEDSOS {
|
export interface MODEL_PORTOFOLIO_MEDSOS {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
import {
|
import {
|
||||||
IconBuildingSkyscraper,
|
IconBuildingSkyscraper,
|
||||||
|
IconCaretRightFilled,
|
||||||
IconListDetails,
|
IconListDetails,
|
||||||
IconMapPin,
|
IconMapPin,
|
||||||
IconPhoneCall,
|
IconPhoneCall,
|
||||||
@@ -39,6 +40,7 @@ export default function Portofolio_UiDetailDataNew() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await apiGetOnePortofolioById(param.id, "bisnis");
|
const response = await apiGetOnePortofolioById(param.id, "bisnis");
|
||||||
if (response) {
|
if (response) {
|
||||||
|
console.log(response.data);
|
||||||
setDataPorto(response.data);
|
setDataPorto(response.data);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -104,6 +106,7 @@ export default function Portofolio_UiDetailDataNew() {
|
|||||||
<Text>{dataPorto?.namaBisnis}</Text>
|
<Text>{dataPorto?.namaBisnis}</Text>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Col span={2}>
|
<Grid.Col span={2}>
|
||||||
<IconListDetails />
|
<IconListDetails />
|
||||||
@@ -112,6 +115,25 @@ export default function Portofolio_UiDetailDataNew() {
|
|||||||
<Text>{dataPorto?.bidangBisnis}</Text>
|
<Text>{dataPorto?.bidangBisnis}</Text>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{dataPorto?.subBidangBisnis.map((item, index) => (
|
||||||
|
<Grid key={index} ml={2}>
|
||||||
|
<Grid.Col span={2}>
|
||||||
|
<IconCaretRightFilled />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={"auto"}>
|
||||||
|
<Text>{item}</Text>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
{/* <Grid>
|
||||||
|
<Grid.Col span={2}>
|
||||||
|
<IconListDetails />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={"auto"}>
|
||||||
|
<Text>{dataPorto?.subBidangBisnis}</Text>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid> */}
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Col span={2}>
|
<Grid.Col span={2}>
|
||||||
<IconPhoneCall />
|
<IconPhoneCall />
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
|
||||||
export interface MODEL_PORTOFOLIO_Lama {
|
export interface MODEL_PORTOFOLIO_Lama {
|
||||||
id: string;
|
id: string;
|
||||||
namaBisnis: string;
|
namaBisnis: string;
|
||||||
@@ -15,6 +17,21 @@ export interface BIDANG_BISNIS_OLD {
|
|||||||
active: boolean;
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MODAL_SUB_BIDANG_BISNIS {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ISUB_BIDANG_BISNIS = Prisma.MasterSubBidangBisnisGetPayload<{
|
||||||
|
select: {
|
||||||
|
id: true;
|
||||||
|
name: true;
|
||||||
|
isActive: true;
|
||||||
|
masterBidangBisnisId: true;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
|
||||||
export interface MODEL_PORTOFOLIO_OLD {
|
export interface MODEL_PORTOFOLIO_OLD {
|
||||||
id: string;
|
id: string;
|
||||||
namaBisnis: string;
|
namaBisnis: string;
|
||||||
@@ -24,5 +41,7 @@ export interface MODEL_PORTOFOLIO_OLD {
|
|||||||
active: boolean;
|
active: boolean;
|
||||||
MasterBidangBisnis: BIDANG_BISNIS_OLD;
|
MasterBidangBisnis: BIDANG_BISNIS_OLD;
|
||||||
masterBidangBisnisId: string
|
masterBidangBisnisId: string
|
||||||
|
MasterSubBidangBisnis: MODAL_SUB_BIDANG_BISNIS;
|
||||||
|
masterSubBidangBisnisId?: string
|
||||||
profileId: string,
|
profileId: string,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user