Sinkronisasi UI & API Admin - User Submenu Berita
This commit is contained in:
133
src/app/darmasaba/(pages)/desa/berita/_lib/layoutTabs.tsx
Normal file
133
src/app/darmasaba/(pages)/desa/berita/_lib/layoutTabs.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Container, Grid, GridCol, Stack, Tabs, TabsList, TabsPanel, TabsTab, Text, TextInput } from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons-react';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import BackButton from '../../layanan/_com/BackButto';
|
||||
|
||||
type HeaderSearchProps = {
|
||||
placeholder?: string;
|
||||
searchIcon?: React.ReactNode;
|
||||
value?: string;
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
function LayoutTabsBerita({
|
||||
children,
|
||||
placeholder = "pencarian",
|
||||
searchIcon = <IconSearch size={20} />,
|
||||
value,
|
||||
onChange }: HeaderSearchProps) {
|
||||
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const tabs = [
|
||||
{
|
||||
label: "Semua",
|
||||
value: "semua",
|
||||
href: "/darmasaba/desa/berita/semua"
|
||||
},
|
||||
{
|
||||
label: "Budaya",
|
||||
value: "budaya",
|
||||
href: "/darmasaba/desa/berita/budaya"
|
||||
},
|
||||
{
|
||||
label: "Pemerintahan",
|
||||
value: "pemerintahan",
|
||||
href: "/darmasaba/desa/berita/pemerintahan"
|
||||
},
|
||||
{
|
||||
label: "Ekonomi",
|
||||
value: "ekonomi",
|
||||
href: "/darmasaba/desa/berita/ekonomi"
|
||||
},
|
||||
{
|
||||
label: "Pembangunan",
|
||||
value: "pembangunan",
|
||||
href: "/darmasaba/desa/berita/pembangunan"
|
||||
},
|
||||
{
|
||||
label: "Sosial",
|
||||
value: "sosial",
|
||||
href: "/darmasaba/desa/berita/sosial"
|
||||
},
|
||||
{
|
||||
label: "Teknologi",
|
||||
value: "teknologi",
|
||||
href: "/darmasaba/desa/berita/teknologi"
|
||||
},
|
||||
|
||||
];
|
||||
const curentTab = tabs.find(tab => tab.href === pathname)
|
||||
const [activeTab, setActiveTab] = useState<string | null>(curentTab?.value || tabs[0].value);
|
||||
|
||||
const handleTabChange = (value: string | null) => {
|
||||
const tab = tabs.find(t => t.value === value)
|
||||
if (tab) {
|
||||
router.push(tab.href)
|
||||
}
|
||||
setActiveTab(value)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const match = tabs.find(tab => tab.href === pathname)
|
||||
if (match) {
|
||||
setActiveTab(match.value)
|
||||
}
|
||||
}, [pathname])
|
||||
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||
{/* Header */}
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container size="lg" px="md">
|
||||
<Stack align="center" gap="0" >
|
||||
<Text fz={{ base: "2rem", md: "3.4rem" }} c={colors["blue-button"]} fw="bold" ta="center">
|
||||
Portal Berita Darmasaba
|
||||
</Text>
|
||||
<Text ta="center" px="md">
|
||||
Temukan berbagai potensi dan keunggulan yang dimiliki Desa Darmasaba
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
<Tabs color={colors['blue-button']} variant="pills" defaultValue="semua" value={activeTab} onChange={handleTabChange}>
|
||||
<Box px={{ base: "md", md: 100 }} py="md" bg={colors['BG-trans']} >
|
||||
<Grid>
|
||||
<GridCol span={{ base: 12, md: 9, lg: 8, xl: 9 }}>
|
||||
<TabsList>
|
||||
{tabs.map((e, i) => (
|
||||
<TabsTab key={i} value={e.value}>{e.label}</TabsTab>
|
||||
))}
|
||||
</TabsList>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 12, md: 3, lg: 4, xl: 3 }}>
|
||||
<TextInput
|
||||
radius="lg"
|
||||
placeholder={placeholder}
|
||||
leftSection={searchIcon}
|
||||
w="100%"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</Box>
|
||||
{tabs.map((e, i) => (
|
||||
<TabsPanel key={i} value={e.value}>
|
||||
{/* Konten dummy, bisa diganti tergantung routing */}
|
||||
<></>
|
||||
</TabsPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default LayoutTabsBerita;
|
||||
12
src/app/darmasaba/(pages)/desa/berita/layout.tsx
Normal file
12
src/app/darmasaba/(pages)/desa/berita/layout.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import LayoutTabsBerita from './_lib/layoutTabs';
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<LayoutTabsBerita>
|
||||
{children}
|
||||
</LayoutTabsBerita>
|
||||
);
|
||||
}
|
||||
|
||||
export default Layout;
|
||||
@@ -1,102 +0,0 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Container, Grid, GridCol, Stack, Tabs, TabsList, TabsPanel, TabsTab, Text, TextInput } from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons-react';
|
||||
import BackButton from '../layanan/_com/BackButto';
|
||||
import Budaya from './(tabs)/budaya';
|
||||
import Ekonomi from './(tabs)/ekonomi';
|
||||
import Pemerintahan from './(tabs)/pemerintahan';
|
||||
import Semua from './(tabs)/semua';
|
||||
import Sosial from './(tabs)/sosial';
|
||||
import Teknologi from './(tabs)/teknologi';
|
||||
import Pembangunan from './(tabs)/pembangunan';
|
||||
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||
{/* Header */}
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container size="lg" px="md">
|
||||
<Stack align="center" gap="0" >
|
||||
<Text fz={{ base: "2rem", md: "3.4rem" }} c={colors["blue-button"]} fw="bold" ta="center">
|
||||
Portal Berita Darmasaba
|
||||
</Text>
|
||||
<Text ta="center" px="md">
|
||||
Temukan berbagai potensi dan keunggulan yang dimiliki Desa Darmasaba
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
{/* Tabs Menu */}
|
||||
<Tabs color={colors['blue-button']} variant="pills" defaultValue="semua">
|
||||
<Box px={{ base: "md", md: 100 }} py="md" bg={colors['BG-trans']} >
|
||||
<Grid>
|
||||
<GridCol span={{ base: 12, md: 9, lg: 8, xl: 9 }}>
|
||||
<TabsList>
|
||||
<TabsTab value="semua">
|
||||
Semua
|
||||
</TabsTab>
|
||||
<TabsTab value="pemerintahan">
|
||||
Pemerintahan
|
||||
</TabsTab>
|
||||
<TabsTab value="pembangunan" >
|
||||
Pembangunan
|
||||
</TabsTab>
|
||||
<TabsTab value="ekonomi" >
|
||||
Ekonomi
|
||||
</TabsTab>
|
||||
<TabsTab value="sosial" >
|
||||
Sosial
|
||||
</TabsTab>
|
||||
<TabsTab value="budaya" >
|
||||
Budaya
|
||||
</TabsTab>
|
||||
<TabsTab value="teknologi" >
|
||||
Teknologi
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 12, md: 3, lg: 4, xl: 3 }}>
|
||||
<TextInput
|
||||
w={{ base: "100%", md: "100%" }}
|
||||
radius="lg"
|
||||
placeholder="Cari Berita"
|
||||
leftSection={<IconSearch size={18} />}
|
||||
/>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
<TabsPanel value='semua'>
|
||||
<Semua />
|
||||
</TabsPanel>
|
||||
<TabsPanel value='pemerintahan'>
|
||||
<Pemerintahan />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="pembangunan" >
|
||||
<Pembangunan />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="ekonomi" >
|
||||
<Ekonomi />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="sosial" >
|
||||
<Sosial />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="budaya" >
|
||||
<Budaya />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="teknologi" >
|
||||
<Teknologi />
|
||||
</TabsPanel>
|
||||
|
||||
</Tabs>
|
||||
|
||||
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
128
src/app/darmasaba/(pages)/desa/berita/page2.txt
Normal file
128
src/app/darmasaba/(pages)/desa/berita/page2.txt
Normal file
@@ -0,0 +1,128 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Container, Grid, GridCol, Skeleton, Stack, Tabs, TabsList, TabsPanel, TabsTab, Text, TextInput } from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons-react';
|
||||
import BackButton from '../layanan/_com/BackButto';
|
||||
import Budaya from './budaya/page';
|
||||
import Ekonomi from './ekonomi/page';
|
||||
import Pemerintahan from './pemerintahan/page';
|
||||
import Semua from './semua/page';
|
||||
import Sosial from './sosial/page';
|
||||
import Teknologi from './teknologi/page';
|
||||
import Pembangunan from './pembangunan/page';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
||||
|
||||
|
||||
function Page() {
|
||||
const [selectedKategori, setSelectedKategori] = useState<string>('Semua');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const state = useProxy(stateDashboardBerita);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
state.kategoriBerita.findMany.load()
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await stateDashboardBerita.berita.findMany.load(1, 100);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const data = state.berita.findMany.data || [];
|
||||
|
||||
const categories = [...new Set(
|
||||
data
|
||||
.filter(item => item.kategoriBerita?.name)
|
||||
.map(item => item.kategoriBerita?.name)
|
||||
)];
|
||||
|
||||
const filteredData = selectedKategori === 'Semua'
|
||||
? data
|
||||
: data.filter(item => item.kategoriBerita?.name === selectedKategori);
|
||||
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22">
|
||||
{/* Header */}
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container size="lg" px="md">
|
||||
<Stack align="center" gap="0" >
|
||||
<Text fz={{ base: "2rem", md: "3.4rem" }} c={colors["blue-button"]} fw="bold" ta="center">
|
||||
Portal Berita Darmasaba
|
||||
</Text>
|
||||
<Text ta="center" px="md">
|
||||
Temukan berbagai potensi dan keunggulan yang dimiliki Desa Darmasaba
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
{/* Tabs Menu */}
|
||||
<Tabs color={colors['blue-button']} variant="pills" defaultValue="semua">
|
||||
<Box px={{ base: "md", md: 100 }} py="md" bg={colors['BG-trans']} >
|
||||
<Grid>
|
||||
<GridCol span={{ base: 12, md: 9, lg: 8, xl: 9 }}>
|
||||
<TabsList>
|
||||
{categories.map((kategori) => (
|
||||
<TabsTab key={kategori} value={kategori || ''}>
|
||||
{kategori}
|
||||
</TabsTab>
|
||||
))}
|
||||
</TabsList>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 12, md: 3, lg: 4, xl: 3 }}>
|
||||
{loading ? (
|
||||
<Skeleton height={42} />
|
||||
) : filteredData.length > 0 ? (
|
||||
<TextInput
|
||||
w={{ base: "100%", md: "100%" }}
|
||||
radius="lg"
|
||||
placeholder="Cari Berita"
|
||||
leftSection={<IconSearch size={18} />}
|
||||
/>
|
||||
) : (
|
||||
<Text>Tidak ada data</Text>
|
||||
)}
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
<TabsPanel value='semua'>
|
||||
<Semua />
|
||||
</TabsPanel>
|
||||
<TabsPanel value='pemerintahan'>
|
||||
<Pemerintahan />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="pembangunan" >
|
||||
<Pembangunan />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="ekonomi" >
|
||||
<Ekonomi />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="sosial" >
|
||||
<Sosial />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="budaya" >
|
||||
<Budaya />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="teknologi" >
|
||||
<Teknologi />
|
||||
</TabsPanel>
|
||||
|
||||
</Tabs>
|
||||
|
||||
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -8,7 +8,7 @@ function LambangDesa() {
|
||||
<Stack align='center' gap={0}>
|
||||
<Box pb={30}>
|
||||
<Center>
|
||||
<Image src={"/api/img/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
</Center>
|
||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Lambang Desa</Text>
|
||||
</Box>
|
||||
|
||||
@@ -7,7 +7,7 @@ function MaskotDesa() {
|
||||
<Stack align='center' gap={0}>
|
||||
<Box pb={30}>
|
||||
<Center>
|
||||
<Image src={"/api/img/pudak-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
<Image src={"/pudak-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
</Center>
|
||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Maskot Desa</Text>
|
||||
</Box>
|
||||
@@ -29,7 +29,7 @@ function MaskotDesa() {
|
||||
<Center>
|
||||
<Box>
|
||||
<Paper p={"lg"}>
|
||||
<Image src={"/api/img/pohonpudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Image src={"/pohonpudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Pohon Pudak</Text>
|
||||
</Paper>
|
||||
</Box>
|
||||
@@ -37,7 +37,7 @@ function MaskotDesa() {
|
||||
<Center>
|
||||
<Box>
|
||||
<Paper p={"lg"}>
|
||||
<Image src={"/api/img/bungapudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Image src={"/bungapudak.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Bunga Pudak</Text>
|
||||
</Paper>
|
||||
</Box>
|
||||
@@ -64,7 +64,7 @@ function MaskotDesa() {
|
||||
<Box>
|
||||
<Center>
|
||||
<Paper p={"lg"}>
|
||||
<Image src={"/api/img/tarisekar.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Image src={"/tarisekar.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Tari Sekar Pudak</Text>
|
||||
</Paper>
|
||||
</Center>
|
||||
@@ -72,7 +72,7 @@ function MaskotDesa() {
|
||||
<Box>
|
||||
<Center>
|
||||
<Paper p={"lg"}>
|
||||
<Image src={"/api/img/klimakstari.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Image src={"/klimakstari.png"} alt="" w={{ base: 150, md: 250 }} />
|
||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Pose Klimaks Tari </Text>
|
||||
<Text ta={"center"} fw={"bold"} c={colors["blue-button"]} fz={{ base: "md", md: "h3" }}>Sekar Pudak </Text>
|
||||
</Paper>
|
||||
|
||||
@@ -8,7 +8,7 @@ function SejarahDesa() {
|
||||
<Stack align='center' gap={0}>
|
||||
<Box pb={30}>
|
||||
<Center>
|
||||
<Image src={"/api/img/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
</Center>
|
||||
<Text c={colors['blue-button']} ta={"center"} fw={"bold"} fz={"2.5rem"}>Sejarah Desa</Text>
|
||||
</Box>
|
||||
|
||||
@@ -8,7 +8,7 @@ function VisimisiDesa() {
|
||||
<Box pb={30}>
|
||||
<Stack align='center' gap={0}>
|
||||
<Box pb={30}>
|
||||
<Image src={"/api/img/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
<Image src={"/darmasaba-icon.png"} alt="" w={{ base: 200, md: 300 }} />
|
||||
</Box>
|
||||
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
||||
<Text c={colors['blue-button']} ta={"center"} fw={"lighter"} fz={"2.5rem"}>Visi Desa</Text>
|
||||
|
||||
@@ -28,7 +28,7 @@ function Page() {
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Center>
|
||||
<Image src={"/api/img/darmasaba-icon.png"} w={{ base: 70, md: 100 }} alt='' />
|
||||
<Image src={"/darmasaba-icon.png"} w={{ base: 70, md: 100 }} alt='' />
|
||||
</Center>
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
Daftar Informasi Publik Desa Darmasaba
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
import stateStrukturPPID from '@/app/admin/(dashboard)/_state/ppid/struktur_ppid/struktur_PPID';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Box, Paper, Text, Image } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { Box, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { OrganizationChart } from 'primereact/organizationchart';
|
||||
import { useEffect } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
|
||||
function Page() {
|
||||
@@ -9,16 +15,107 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
Struktur PPID Desa Darmasaba
|
||||
</Text>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Paper p={"xl"} bg={colors['white-trans-1']}>
|
||||
<Image src={"/api/img/struktur-ppid.png"} alt='' />
|
||||
</Paper>
|
||||
</Box>
|
||||
<Title ta={"center"} fz={{ base: "2rem", md: "2.5rem", lg: "3rem", xl: "3.5rem" }} c={colors["blue-button"]} fw={"bold"}>Struktur PPID</Title>
|
||||
<StrukturOrganisasiPPID />
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
function StrukturOrganisasiPPID() {
|
||||
const stateOrganisasi = useProxy(stateStrukturPPID.pegawai)
|
||||
|
||||
useEffect(() => {
|
||||
stateOrganisasi.findMany.load()
|
||||
}, [])
|
||||
|
||||
if (!stateOrganisasi.findMany.data || stateOrganisasi.findMany.data.length === 0) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
// Step 1: Group pegawai berdasarkan posisiId
|
||||
const posisiMap = new Map<string, any>();
|
||||
|
||||
for (const pegawai of stateOrganisasi.findMany.data) {
|
||||
const posisiId = pegawai.posisi.id;
|
||||
if (!posisiMap.has(posisiId)) {
|
||||
posisiMap.set(posisiId, {
|
||||
...pegawai.posisi,
|
||||
pegawaiList: [],
|
||||
children: []
|
||||
});
|
||||
}
|
||||
posisiMap.get(posisiId)!.pegawaiList.push(pegawai);
|
||||
}
|
||||
|
||||
|
||||
// Step 2: Buat struktur pohon berdasarkan parentId
|
||||
const root: any[] = [];
|
||||
|
||||
posisiMap.forEach((posisi) => {
|
||||
if (posisi.parentId) {
|
||||
const parent = posisiMap.get(posisi.parentId);
|
||||
if (parent) {
|
||||
parent.children.push(posisi);
|
||||
}
|
||||
} else {
|
||||
root.push(posisi);
|
||||
}
|
||||
});
|
||||
|
||||
// Step 3: Ubah struktur ke format OrganizationChart
|
||||
function toOrgChartFormat(node: any): any {
|
||||
return {
|
||||
expanded: true,
|
||||
type: 'person',
|
||||
styleClass: 'p-person',
|
||||
data: {
|
||||
name: node.pegawaiList?.[0]?.namaLengkap || 'Tidak ada pegawai',
|
||||
status: node.nama,
|
||||
image: node.pegawaiList?.[0]?.image?.link || '/img/default.png'
|
||||
},
|
||||
children: node.children.map(toOrgChartFormat)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const chartData = root.map(toOrgChartFormat);
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors.grey} p="md" style={{ overflowX: 'auto' }}>
|
||||
<OrganizationChart style={{ color: colors['blue-button'] }} value={chartData} nodeTemplate={nodeTemplate} />
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function nodeTemplate(node: any) {
|
||||
const imageSrc = node?.data?.image || '/img/default.png';
|
||||
const name = node?.data?.name || 'Tanpa Nama';
|
||||
const status = node?.data?.status || 'Tidak ada deskripsi';
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} py={"xl"} gap={"22"}>
|
||||
<Stack align="center" gap={4}>
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={name}
|
||||
radius="xl"
|
||||
w={120}
|
||||
h={120}
|
||||
fit="cover"
|
||||
/>
|
||||
<Text fw={600} ta="center">{name}</Text>
|
||||
<Text size="sm" c="dimmed" ta="center">{status}</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
|
||||
Reference in New Issue
Block a user