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(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