From 3cb5416cfb3fd8e7e3d9db47ef11fe1fc00f9df4 Mon Sep 17 00:00:00 2001 From: amel Date: Fri, 6 Dec 2024 21:33:24 +0800 Subject: [PATCH] upd: portofolio detail Deskripsi: - update api detail portofolio - delete api portofolio No Issues --- src/app/api/new/portofolio/[id]/route.ts | 172 ++++++++++++++++++ src/app/dev/portofolio/main/[id]/layout.tsx | 23 +-- src/app/dev/portofolio/main/[id]/page.tsx | 15 +- .../component/button_delete_new.tsx | 97 ++++++++++ .../portofolio/component/button_more_new.tsx | 87 +++++++++ src/app_modules/katalog/portofolio/index.ts | 4 + .../katalog/portofolio/lib/api_portofolio.ts | 15 ++ .../katalog/portofolio/lib/type_portofolio.ts | 29 +++ .../portofolio/ui/ui_detail_data_new.tsx | 131 +++++++++++++ .../portofolio/ui/ui_detail_map_new.tsx | 129 +++++++++++++ .../portofolio/ui/ui_detail_media_new.tsx | 131 +++++++++++++ .../ui/ui_detail_portofolio_new.tsx | 19 ++ .../katalog/portofolio/ui/ui_layout_new.tsx | 20 ++ .../ui/ui_skeleton_detail_bisnis.tsx | 35 ++++ 14 files changed, 884 insertions(+), 23 deletions(-) create mode 100644 src/app/api/new/portofolio/[id]/route.ts create mode 100644 src/app_modules/katalog/portofolio/component/button_delete_new.tsx create mode 100644 src/app_modules/katalog/portofolio/component/button_more_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_detail_data_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_detail_map_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_detail_media_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_detail_portofolio_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_layout_new.tsx create mode 100644 src/app_modules/katalog/portofolio/ui/ui_skeleton_detail_bisnis.tsx diff --git a/src/app/api/new/portofolio/[id]/route.ts b/src/app/api/new/portofolio/[id]/route.ts new file mode 100644 index 00000000..5d783cb5 --- /dev/null +++ b/src/app/api/new/portofolio/[id]/route.ts @@ -0,0 +1,172 @@ +import { prisma } from "@/app/lib"; +import { NextResponse } from "next/server"; +import fs from "fs"; + + + +// GET ONE DATA PORTOFOLIO BY ID PORTOFOLIO +export async function GET(request: Request, context: { params: { id: string } }) { + try { + let dataFix + const { id } = context.params; + const { searchParams } = new URL(request.url); + const kategori = searchParams.get('cat'); + + if (kategori == "bisnis") { + const data = await prisma.portofolio.findUnique({ + where: { + id: id, + }, + select: { + id_Portofolio: true, + namaBisnis: true, + alamatKantor: true, + tlpn: true, + deskripsi: true, + logoId: true, + MasterBidangBisnis: { + select: { + name: true + } + }, + Profile: { + select: { + userId: true + } + } + } + }); + + dataFix = { + id_Portofolio: data?.id_Portofolio, + namaBisnis: data?.namaBisnis, + alamatKantor: data?.alamatKantor, + tlpn: data?.tlpn, + deskripsi: data?.deskripsi, + logoId: data?.logoId, + bidangBisnis: data?.MasterBidangBisnis?.name, + authorId: data?.Profile?.userId + } + + } else if (kategori == "lokasi") { + const data = await prisma.portofolio.findUnique({ + where: { + id: id, + }, + select: { + logoId: true, + BusinessMaps: { + select: { + id: true, + namePin: true, + latitude: true, + longitude: true, + imageId: true, + pinId: true + } + } + } + }); + + dataFix = { + mapId: data?.BusinessMaps?.id, + logoId: data?.logoId, + namePin: data?.BusinessMaps?.namePin, + latitude: data?.BusinessMaps?.latitude, + longitude: data?.BusinessMaps?.longitude, + imageId: data?.BusinessMaps?.imageId, + pinId: data?.BusinessMaps?.pinId + } + + } else if (kategori == "sosmed") { + const data = await prisma.portofolio.findUnique({ + where: { + id: id, + }, + select: { + Portofolio_MediaSosial: { + select: { + facebook: true, + twitter: true, + instagram: true, + tiktok: true, + youtube: true + } + } + } + }); + + dataFix = { + facebook: data?.Portofolio_MediaSosial?.facebook, + twitter: data?.Portofolio_MediaSosial?.twitter, + instagram: data?.Portofolio_MediaSosial?.instagram, + tiktok: data?.Portofolio_MediaSosial?.tiktok, + youtube: data?.Portofolio_MediaSosial?.youtube + } + } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan data", data: dataFix }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan data, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} + +// DELETE ONE DATA PORTOFOLIO +export async function DELETE(request: Request, context: { params: { id: string } }) { + try { + const { id } = context.params + + const data = await prisma.portofolio.findUnique({ + where: { + id: id + } + }) + + const findLogo = await prisma.images.findFirst({ + where: { + id: String(data?.logoId), + }, + select: { + id: true, + url: true, + }, + }); + + if (findLogo) { + fs.unlinkSync(`./public/portofolio/logo/${findLogo.url}`) + const deleteLogo = await prisma.images.delete({ + where: { + id: String(findLogo?.id), + }, + }); + } + + + + const deletePortoMedsos = await prisma.portofolio_MediaSosial.delete({ + where: { + portofolioId: id, + }, + }); + + const deleteMap = await prisma.businessMaps.delete({ + where: { + portofolioId: id + } + }) + + const deletePortofolio = await prisma.portofolio.delete({ + where: { + id: id, + }, + }); + + return NextResponse.json({ success: true, message: "Berhasil menghapus data" }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal menghapus data, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/dev/portofolio/main/[id]/layout.tsx b/src/app/dev/portofolio/main/[id]/layout.tsx index 42f4bc01..1be53c84 100644 --- a/src/app/dev/portofolio/main/[id]/layout.tsx +++ b/src/app/dev/portofolio/main/[id]/layout.tsx @@ -1,27 +1,20 @@ -import { funGetUserIdByToken } from "@/app_modules/_global/fun/get"; -import { PortofolioLayout } from "@/app_modules/katalog/portofolio"; -import { portofolio_getOneById } from "@/app_modules/katalog/portofolio/fun/get/get_one_portofolio"; +import { PortofolioLayoutNew } from "@/app_modules/katalog/portofolio"; -export default async function Layout({ - children, - params, -}: { - children: any; - params: { id: string }; -}) { - let portoId = params.id; - const getPorto = await portofolio_getOneById(portoId); - const userLoginId = await funGetUserIdByToken(); +export default async function Layout({ children, params, }: { children: any; params: { id: string }; }) { + // let portoId = params.id; + // const getPorto = await portofolio_getOneById(portoId); + // const userLoginId = await funGetUserIdByToken(); return ( <> - {children} - + */} + {children} ); } diff --git a/src/app/dev/portofolio/main/[id]/page.tsx b/src/app/dev/portofolio/main/[id]/page.tsx index 61d37c14..ab45a811 100644 --- a/src/app/dev/portofolio/main/[id]/page.tsx +++ b/src/app/dev/portofolio/main/[id]/page.tsx @@ -1,20 +1,19 @@ -import { funGetUserIdByToken } from "@/app_modules/_global/fun/get"; -import { ViewPortofolio } from "@/app_modules/katalog/portofolio"; -import { portofolio_getOneById } from "@/app_modules/katalog/portofolio/fun/get/get_one_portofolio"; +import { Portofolio_UiDetailNew } from "@/app_modules/katalog/portofolio"; const mapboxToken = process.env.MAPBOX_TOKEN!; export default async function Page({ params }: { params: { id: string } }) { - const portofolioId = params.id; - const dataPortofolio = await portofolio_getOneById(portofolioId); - const userLoginId = await funGetUserIdByToken(); + // const portofolioId = params.id; + // const dataPortofolio = await portofolio_getOneById(portofolioId); + // const userLoginId = await funGetUserIdByToken(); return ( <> - + /> */} + ); } diff --git a/src/app_modules/katalog/portofolio/component/button_delete_new.tsx b/src/app_modules/katalog/portofolio/component/button_delete_new.tsx new file mode 100644 index 00000000..84d890d2 --- /dev/null +++ b/src/app_modules/katalog/portofolio/component/button_delete_new.tsx @@ -0,0 +1,97 @@ +import { funGetUserIdByToken } from "@/app_modules/_global/fun/get"; +import { ComponentGlobal_NotifikasiBerhasil, ComponentGlobal_NotifikasiGagal } from "@/app_modules/_global/notif_global"; +import { UIGlobal_Modal } from "@/app_modules/_global/ui"; +import { Button } from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import { IconTrash } from "@tabler/icons-react"; +import { useParams, useRouter } from "next/navigation"; +import { useState } from "react"; +import { apiDeletePortofolio, apiGetOnePortofolioById } from "../lib/api_portofolio"; +import { IDetailPortofolioBisnis } from "../lib/type_portofolio"; + +export default function ComponentPortofolio_ButtonDeleteNew() { + const param = useParams<{ id: string }>() + const [openModal, setModal] = useState(false) + const [loadingDel, setLoadingDel] = useState(false) + const [userLoginId, setUserLoginId] = useState("") + const [dataPorto, setDataPorto] = useState() + const router = useRouter() + + + async function onDelete() { + try { + setLoadingDel(true) + const response = await apiDeletePortofolio(param.id) + if (response.success) { + ComponentGlobal_NotifikasiBerhasil(response.message) + router.back() + } else { + ComponentGlobal_NotifikasiGagal(response.message); + } + } catch (error) { + console.error(error) + ComponentGlobal_NotifikasiGagal("Gagal menghapus portofolio"); + } finally { + setLoadingDel(false) + } + } + + async function funGetPortofolio() { + try { + const response = await apiGetOnePortofolioById(param.id, "bisnis") + const response2 = await funGetUserIdByToken() + if (response.success) { + setDataPorto(response.data) + setUserLoginId(response2) + } + } catch (error) { + console.error(error); + } + } + + useShallowEffect(() => { + funGetPortofolio() + }, []); + + + return ( + <> + {userLoginId === dataPorto?.authorId ? ( + + ) : ( + "" + )} + + setModal(false)} + buttonKiri={ + + } + buttonKanan={ + + } + /> + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/component/button_more_new.tsx b/src/app_modules/katalog/portofolio/component/button_more_new.tsx new file mode 100644 index 00000000..d28ed708 --- /dev/null +++ b/src/app_modules/katalog/portofolio/component/button_more_new.tsx @@ -0,0 +1,87 @@ +import { RouterPortofolio } from "@/app/lib/router_hipmi/router_katalog"; +import { RouterMap } from "@/app/lib/router_hipmi/router_map"; +import { UIGlobal_Drawer } from "@/app_modules/_global/ui"; +import { ActionIcon } from "@mantine/core"; +import { useShallowEffect } from "@mantine/hooks"; +import { IconEdit, IconPhotoEdit, IconId, IconMapPin2, IconMapPin, IconDotsVertical } from "@tabler/icons-react"; +import { useParams } from "next/navigation"; +import { useState } from "react"; +import { apiGetOnePortofolioById } from "../lib/api_portofolio"; +import { funGetUserIdByToken } from "@/app_modules/_global/fun/get"; + +export default function ComponentPortofolio_ButtonMoreNew() { + const param = useParams<{ id: string }>() + const [userLoginId, setUserLoginId] = useState("") + const [authorId, setAuthorId] = useState("") + const [openDrawer, setOpenDrawer] = useState(false) + + const listPage = [ + { + id: "1", + name: "Edit detail ", + icon: , + path: RouterPortofolio.edit_data_bisnis + `${param.id}`, + }, + { + id: "2", + name: "Edit logo ", + icon: , + path: RouterPortofolio.edit_logo_bisnis + `${param.id}`, + }, + { + id: "3", + name: "Edit sosial media", + icon: , + path: RouterPortofolio.edit_medsos_bisnis + `${param.id}`, + }, + { + id: "4", + name: "Edit data map", + icon: , + path: RouterMap.edit + `${param.id}`, + }, + { + id: "5", + name: "Custom pin map", + icon: , + path: RouterMap.custom_pin + `${param.id}`, + }, + ]; + + + async function funGetPortofolio() { + try { + const response = await apiGetOnePortofolioById(param.id, "bisnis") + const response2 = await funGetUserIdByToken() + if (response.success) { + setAuthorId(response.data.authorId) + setUserLoginId(response2) + } + } catch (error) { + console.error(error); + } + } + + useShallowEffect(() => { + funGetPortofolio() + }, []); + + + return ( + <> + {userLoginId === authorId ? ( + setOpenDrawer(true)}> + + + ) : ( + + )} + + setOpenDrawer(false)} + component={listPage} + /> + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/index.ts b/src/app_modules/katalog/portofolio/index.ts index 9d31be0f..e123bbff 100644 --- a/src/app_modules/katalog/portofolio/index.ts +++ b/src/app_modules/katalog/portofolio/index.ts @@ -11,6 +11,8 @@ import LayoutPortofolio_EditDataBisnis from "./edit/data/layout"; import LayoutPortofolio_EditLogoBisnis from "./edit/logo/layout"; import LayoutPortofolio_EditMedsosBisnis from "./edit/medsos/layout"; import ListDetailPortofolioNew from './view/list_detail_portofolio_new'; +import Portofolio_UiDetailNew from './ui/ui_detail_portofolio_new'; +import PortofolioLayoutNew from './ui/ui_layout_new'; export { CreatePortofolio, @@ -28,4 +30,6 @@ export { export type { IListPortofolio }; export { Portofolio_ViewListDetail } from "./view/view_list_detail_portofolio"; export { ListDetailPortofolioNew } +export { Portofolio_UiDetailNew } +export { PortofolioLayoutNew } diff --git a/src/app_modules/katalog/portofolio/lib/api_portofolio.ts b/src/app_modules/katalog/portofolio/lib/api_portofolio.ts index a4c460db..c152514d 100644 --- a/src/app_modules/katalog/portofolio/lib/api_portofolio.ts +++ b/src/app_modules/katalog/portofolio/lib/api_portofolio.ts @@ -1,4 +1,19 @@ export const apiGetPortofolioByProfile = async (path?: string) => { const response = await fetch(`/api/new/portofolio${(path) ? path : ''}`) return await response.json().catch(() => null) +} + +export const apiGetOnePortofolioById = async (path: string, cat:string) => { + const response = await fetch(`/api/new/portofolio/${path}?cat=${cat}`); + return await response.json().catch(() => null); +} + +export const apiDeletePortofolio = async (path: string) => { + const response = await fetch(`/api/new/portofolio/${path}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + return await response.json().catch(() => null); } \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/lib/type_portofolio.ts b/src/app_modules/katalog/portofolio/lib/type_portofolio.ts index 637935e1..1a543763 100644 --- a/src/app_modules/katalog/portofolio/lib/type_portofolio.ts +++ b/src/app_modules/katalog/portofolio/lib/type_portofolio.ts @@ -3,4 +3,33 @@ export interface IListPortofolio { id_Portofolio: string profileId: string namaBisnis: string +} + +export interface IDetailPortofolioBisnis { + id_Portofolio: string + namaBisnis: string + alamatKantor: string + tlpn: string + deskripsi: string + logoId: string + bidangBisnis: string + authorId: string +} + +export interface IDetailPortofolioLokasi { + mapId: string + logoId: string + namePin: string + latitude: string + longitude: string + imageId: string + pinId: string +} + +export interface IDetailPortofolioSosmed { + facebook: string + twitter: string + instagram: string + tiktok: string + youtube: string } \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_detail_data_new.tsx b/src/app_modules/katalog/portofolio/ui/ui_detail_data_new.tsx new file mode 100644 index 00000000..92d2cead --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_detail_data_new.tsx @@ -0,0 +1,131 @@ +import { AccentColor, MainColor } from "@/app_modules/_global/color"; +import { ComponentGlobal_LoadImage } from "@/app_modules/_global/component"; +import { Paper, Stack, Group, Title, SimpleGrid, Box, Grid, Divider, Text } from "@mantine/core"; +import { IconBuildingSkyscraper, IconListDetails, IconPhoneCall, IconMapPin, IconPinned } from "@tabler/icons-react"; +import { useState } from "react"; +import { IDetailPortofolioBisnis } from "../lib/type_portofolio"; +import { useParams } from "next/navigation"; +import { apiGetOnePortofolioById } from "../lib/api_portofolio"; +import { useShallowEffect } from "@mantine/hooks"; +import SkeletonDetailBisnis from "./ui_skeleton_detail_bisnis"; + +export default function Portofolio_UiDetailDataNew() { + const [loading, setLoading] = useState(true) + const param = useParams<{ id: string }>() + const [dataPorto, setDataPorto] = useState(); + + async function funGetPortofolio() { + try { + setLoading(true) + const response = await apiGetOnePortofolioById(param.id, "bisnis"); + if (response.success) { + setDataPorto(response.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false) + } + } + + useShallowEffect(() => { + funGetPortofolio() + }, []); + + return ( + <> + + { + loading ? + + : + + + Data Bisnis + + id: {" "} + + #{dataPorto?.id_Portofolio} + + + + + + + + + + + + + + + + + + {dataPorto?.namaBisnis} + + + + + + + + {dataPorto?.bidangBisnis} + + + + + + + + {dataPorto?.tlpn} + + + + + + + + {dataPorto?.alamatKantor} + + + + + + + + + + + + + Tentang Kami + + + {dataPorto?.deskripsi} + + + } + + + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_detail_map_new.tsx b/src/app_modules/katalog/portofolio/ui/ui_detail_map_new.tsx new file mode 100644 index 00000000..54faf735 --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_detail_map_new.tsx @@ -0,0 +1,129 @@ +import { APIs } from "@/app/lib"; +import { AccentColor } from "@/app_modules/_global/color"; +import { defaultMapZoom } from "@/app_modules/map/lib/default_lat_long"; +import { Paper, Stack, Title, Avatar, Skeleton } from "@mantine/core"; +import "mapbox-gl/dist/mapbox-gl.css"; +import { useParams } from "next/navigation"; +import { useState } from "react"; +import { AttributionControl, Map, Marker, NavigationControl, ScaleControl, } from "react-map-gl"; +import { IDetailPortofolioLokasi } from "../lib/type_portofolio"; +import { apiGetOnePortofolioById } from "../lib/api_portofolio"; +import { useShallowEffect } from "@mantine/hooks"; +import { ComponentMap_DetailData, ComponentMap_DrawerDetailData } from "@/app_modules/map/_component"; + +export default function Portofolio_UiMapNew({ mapboxToken }: { mapboxToken: string }) { + const [loading, setLoading] = useState(true) + const param = useParams<{ id: string }>() + const [dataPorto, setDataPorto] = useState() + const [openDrawer, setOpenDrawer] = useState(false) + + async function funGetPortofolio() { + try { + setLoading(true) + const response = await apiGetOnePortofolioById(param.id, "lokasi"); + if (response.success) { + setDataPorto(response.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false) + } + } + + useShallowEffect(() => { + funGetPortofolio() + }, []); + + + return ( + <> + + + + Lokasi Bisnis + + { + loading ? + + : + + { + setOpenDrawer(true); + }} + pitchAlignment="auto" + > + + + + + + + + + + + } + + + + setOpenDrawer(false)} + mapId={String(dataPorto?.mapId)} + component={} + /> + + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_detail_media_new.tsx b/src/app_modules/katalog/portofolio/ui/ui_detail_media_new.tsx new file mode 100644 index 00000000..132fe798 --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_detail_media_new.tsx @@ -0,0 +1,131 @@ +import { AccentColor } from "@/app_modules/_global/color"; +import { Paper, Title, Stack, Grid, Text, Skeleton, Box } from "@mantine/core"; +import { IconBrandFacebook, IconBrandInstagram, IconBrandTiktok, IconBrandTwitter, IconBrandYoutube } from "@tabler/icons-react"; +import { useParams } from "next/navigation"; +import { useState } from "react"; +import { IDetailPortofolioSosmed } from "../lib/type_portofolio"; +import { apiGetOnePortofolioById } from "../lib/api_portofolio"; +import { useShallowEffect } from "@mantine/hooks"; + +export default function Portofolio_UiSosialMediaNew() { + const [loading, setLoading] = useState(true) + const param = useParams<{ id: string }>() + const [dataPorto, setDataPorto] = useState(); + + async function funGetPortofolio() { + try { + setLoading(true) + const response = await apiGetOnePortofolioById(param.id, "sosmed"); + if (response.success) { + setDataPorto(response.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false) + } + } + + useShallowEffect(() => { + funGetPortofolio() + }, []); + + + return ( + <> + + Media Sosial Bisnis + { + loading ? + + {[...Array(4)].map((_, index) => ( + + + + + + + + + + + ))} + + : + + + + + + + {dataPorto?.facebook ? ( + {dataPorto?.facebook} + ) : ( + "-" + )} + + + + + + + + {dataPorto?.instagram ? ( + {dataPorto?.instagram} + ) : ( + "-" + )} + + + + + + + + {dataPorto?.tiktok ? ( + {dataPorto?.tiktok} + ) : ( + "-" + )} + + + + + + + + {dataPorto?.twitter ? ( + {dataPorto?.twitter} + ) : ( + "-" + )} + + + + + + + + {dataPorto?.youtube ? ( + {dataPorto?.youtube} + ) : ( + "-" + )} + + + + + } + + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_detail_portofolio_new.tsx b/src/app_modules/katalog/portofolio/ui/ui_detail_portofolio_new.tsx new file mode 100644 index 00000000..a0203528 --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_detail_portofolio_new.tsx @@ -0,0 +1,19 @@ +'use client' +import { Stack } from "@mantine/core"; +import Portofolio_UiDetailDataNew from "./ui_detail_data_new"; +import Portofolio_UiMapNew from "./ui_detail_map_new"; +import Portofolio_UiSosialMediaNew from "./ui_detail_media_new"; +import ComponentPortofolio_ButtonDeleteNew from "../component/button_delete_new"; + +export default function Portofolio_UiDetailNew({ mapboxToken }: { mapboxToken: string }) { + return ( + <> + + + + + + + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_layout_new.tsx b/src/app_modules/katalog/portofolio/ui/ui_layout_new.tsx new file mode 100644 index 00000000..9f6b5d75 --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_layout_new.tsx @@ -0,0 +1,20 @@ +'use client' +import { UIGlobal_LayoutHeaderTamplate, UIGlobal_LayoutTamplate } from "@/app_modules/_global/ui"; +import ComponentPortofolio_ButtonMoreNew from "../component/button_more_new"; + +export default function PortofolioLayoutNew({ children }: { children: any }) { + return ( + <> + } + /> + } + > + {children} + + + ) +} \ No newline at end of file diff --git a/src/app_modules/katalog/portofolio/ui/ui_skeleton_detail_bisnis.tsx b/src/app_modules/katalog/portofolio/ui/ui_skeleton_detail_bisnis.tsx new file mode 100644 index 00000000..b8708f23 --- /dev/null +++ b/src/app_modules/katalog/portofolio/ui/ui_skeleton_detail_bisnis.tsx @@ -0,0 +1,35 @@ +import { Box, Grid, Group, Skeleton, Stack } from "@mantine/core"; + +export default function SkeletonDetailBisnis() { + return <> + + + + + + + + {[...Array(4)].map((_, index) => ( + + + + + + + + + + + ))} + + + + + + + + + + + ; +} \ No newline at end of file