upd: portofolio detail

Deskripsi:
- update api detail portofolio
- delete api portofolio

No Issues
This commit is contained in:
amel
2024-12-06 21:33:24 +08:00
parent 5eec7d57be
commit 3cb5416cfb
14 changed files with 884 additions and 23 deletions

View File

@@ -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<IDetailPortofolioBisnis>()
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 ? (
<Button
radius={"xl"}
bg={"red"}
color="red"
onClick={() => {
setModal(true)
}}
>
<IconTrash />
</Button>
) : (
""
)}
<UIGlobal_Modal
title={"Anda yakin menghapus portofolio ini ?"}
opened={openModal}
close={() => setModal(false)}
buttonKiri={
<Button radius={"xl"} onClick={() => setModal(false)}>
Batal
</Button>
}
buttonKanan={
<Button
radius={"xl"}
color="red"
loaderPosition="center"
loading={loadingDel}
onClick={() => onDelete()}
>
Hapus
</Button>
}
/>
</>
)
}

View File

@@ -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: <IconEdit />,
path: RouterPortofolio.edit_data_bisnis + `${param.id}`,
},
{
id: "2",
name: "Edit logo ",
icon: <IconPhotoEdit />,
path: RouterPortofolio.edit_logo_bisnis + `${param.id}`,
},
{
id: "3",
name: "Edit sosial media",
icon: <IconId />,
path: RouterPortofolio.edit_medsos_bisnis + `${param.id}`,
},
{
id: "4",
name: "Edit data map",
icon: <IconMapPin2 />,
path: RouterMap.edit + `${param.id}`,
},
{
id: "5",
name: "Custom pin map",
icon: <IconMapPin />,
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 ? (
<ActionIcon variant="transparent" onClick={() => setOpenDrawer(true)}>
<IconDotsVertical color="white" />
</ActionIcon>
) : (
<ActionIcon disabled variant="transparent"></ActionIcon>
)}
<UIGlobal_Drawer
opened={openDrawer}
close={() => setOpenDrawer(false)}
component={listPage}
/>
</>
)
}

View File

@@ -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 }

View File

@@ -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);
}

View File

@@ -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
}

View File

@@ -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<IDetailPortofolioBisnis>();
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 (
<>
<Paper
p={"sm"}
style={{
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px ",
padding: "15px",
color: "white",
}}
>
{
loading ?
<SkeletonDetailBisnis />
:
<Stack>
<Group position="apart">
<Title order={6}>Data Bisnis</Title>
<Text color={MainColor.yellow} fw={"bold"}>
id: {" "}
<Text span inherit>
#{dataPorto?.id_Portofolio}
</Text>
</Text>
</Group>
<Stack>
<SimpleGrid
cols={2}
spacing={"md"}
breakpoints={[
{ maxWidth: "62rem", cols: 2, spacing: "md" },
{ maxWidth: "48rem", cols: 1, spacing: "sm" },
{ maxWidth: "36rem", cols: 1, spacing: "sm" },
]}
>
<Box>
<Paper>
<ComponentGlobal_LoadImage fileId={String(dataPorto?.logoId)} />
</Paper>
</Box>
<Box>
<Grid>
<Grid.Col span={2}>
<IconBuildingSkyscraper />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{dataPorto?.namaBisnis}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconListDetails />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{dataPorto?.bidangBisnis}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconPhoneCall />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{dataPorto?.tlpn}</Text>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconMapPin />
</Grid.Col>
<Grid.Col span={"auto"}>
<Text>{dataPorto?.alamatKantor}</Text>
</Grid.Col>
</Grid>
</Box>
</SimpleGrid>
</Stack>
<Divider color={AccentColor.softblue} />
<Stack spacing={5}>
<Group spacing={"xs"}>
<IconPinned />
<Text fz={"sm"} fw={"bold"}>
Tentang Kami
</Text>
</Group>
<Text px={"sm"}>{dataPorto?.deskripsi}</Text>
</Stack>
</Stack>
}
</Paper>
</>
)
}

View File

@@ -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<IDetailPortofolioLokasi>()
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 (
<>
<Paper
p={"sm"}
style={{
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px ",
padding: "15px",
color: "white",
}}
>
<Stack spacing={0}>
<Title mb={"lg"} order={6}>
Lokasi Bisnis
</Title>
{
loading ?
<Skeleton radius={"md"} w={"100%"} h={100} />
:
<Map
mapboxAccessToken={mapboxToken}
mapStyle={"mapbox://styles/mapbox/streets-v11"}
initialViewState={{
latitude: Number(dataPorto?.latitude),
longitude: Number(dataPorto?.longitude),
zoom: defaultMapZoom,
}}
style={{
cursor: "pointer",
width: "100%",
height: "50vh",
borderRadius: "10px",
}}
attributionControl={false}
>
<Marker
style={{
color: "red",
width: 40,
cursor: "pointer",
}}
latitude={Number(dataPorto?.latitude)}
longitude={Number(dataPorto?.longitude)}
anchor="bottom"
offset={[0, 0]}
scale={1}
onClick={() => {
setOpenDrawer(true);
}}
pitchAlignment="auto"
>
<Stack spacing={0} align="center">
<Avatar
src={
dataPorto?.pinId === null
? APIs.GET({ fileId: String(dataPorto?.logoId) })
: APIs.GET({ fileId: String(dataPorto?.pinId) })
}
alt="Logo"
style={{
border: `2px solid ${AccentColor.softblue}`,
backgroundColor: "white",
borderRadius: "100%",
}}
/>
</Stack>
</Marker>
<NavigationControl />
<ScaleControl position="top-left" />
<AttributionControl
style={{ color: "black" }}
customAttribution="Map design by PT. Bali Interaktif Perkasa"
/>
</Map>
}
</Stack>
<ComponentMap_DrawerDetailData
opened={openDrawer}
close={() => setOpenDrawer(false)}
mapId={String(dataPorto?.mapId)}
component={<ComponentMap_DetailData mapId={String(dataPorto?.mapId)} isDetail />}
/>
</Paper>
</>
)
}

View File

@@ -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<IDetailPortofolioSosmed>();
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 (
<>
<Paper
p={"sm"}
style={{
backgroundColor: AccentColor.darkblue,
border: `2px solid ${AccentColor.blue}`,
borderRadius: "10px ",
padding: "15px",
color: "white",
}}
>
<Title order={6}>Media Sosial Bisnis</Title>
{
loading ?
<Box>
{[...Array(4)].map((_, index) => (
<Box key={index} py={5}>
<Grid align="center">
<Grid.Col span={1}>
<Skeleton w={25} h={25} />
</Grid.Col>
<Grid.Col span={11}>
<Skeleton w={"100%"} h={15} />
</Grid.Col>
</Grid>
</Box>
))}
</Box>
:
<Stack p={"sm"}>
<Grid>
<Grid.Col span={2}>
<IconBrandFacebook />
</Grid.Col>
<Grid.Col span={"auto"}>
{dataPorto?.facebook ? (
<Text>{dataPorto?.facebook}</Text>
) : (
"-"
)}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconBrandInstagram />
</Grid.Col>
<Grid.Col span={"auto"}>
{dataPorto?.instagram ? (
<Text>{dataPorto?.instagram}</Text>
) : (
"-"
)}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconBrandTiktok />
</Grid.Col>
<Grid.Col span={"auto"}>
{dataPorto?.tiktok ? (
<Text>{dataPorto?.tiktok}</Text>
) : (
"-"
)}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconBrandTwitter />
</Grid.Col>
<Grid.Col span={"auto"}>
{dataPorto?.twitter ? (
<Text>{dataPorto?.twitter}</Text>
) : (
"-"
)}
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={2}>
<IconBrandYoutube />
</Grid.Col>
<Grid.Col span={"auto"}>
{dataPorto?.youtube ? (
<Text>{dataPorto?.youtube}</Text>
) : (
"-"
)}
</Grid.Col>
</Grid>
</Stack>
}
</Paper>
</>
)
}

View File

@@ -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 (
<>
<Stack mb={"lg"}>
<Portofolio_UiDetailDataNew />
<Portofolio_UiMapNew mapboxToken={mapboxToken} />
<Portofolio_UiSosialMediaNew />
<ComponentPortofolio_ButtonDeleteNew/>
</Stack>
</>
)
}

View File

@@ -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 (
<>
<UIGlobal_LayoutTamplate
header={
<UIGlobal_LayoutHeaderTamplate
title="Detail Portofolio"
customButtonRight={<ComponentPortofolio_ButtonMoreNew />}
/>
}
>
{children}
</UIGlobal_LayoutTamplate>
</>
)
}

View File

@@ -0,0 +1,35 @@
import { Box, Grid, Group, Skeleton, Stack } from "@mantine/core";
export default function SkeletonDetailBisnis() {
return <>
<Box>
<Grid>
<Grid.Col span={6}>
<Skeleton w={"100%"} height={200} radius="md" />
</Grid.Col>
<Grid.Col span={6}>
<Box>
{[...Array(4)].map((_, index) => (
<Box key={index} py={5}>
<Grid align="center">
<Grid.Col span={2}>
<Skeleton w={25} h={25} />
</Grid.Col>
<Grid.Col span={10}>
<Skeleton w={"100%"} h={15} />
</Grid.Col>
</Grid>
</Box>
))}
</Box>
</Grid.Col>
</Grid>
<Box mt={"md"}>
<Skeleton w={"30%"} h={15} my={10} />
<Skeleton w={"95%"} h={15} my={10} />
<Skeleton w={"95%"} h={15} my={10} />
<Skeleton w={"95%"} h={15} my={10} />
</Box>
</Box>
</>;
}