fix(apbdes) landing page: fix APBDes component not displaying on darmasaba page
- Restore Apbdes component with full functionality (fetch data, year selector, tables, charts) - Fix realisasiTable.tsx: add missing items variable - Fix grafikRealisasi.tsx: dynamic year title instead of hardcoded 2026 - Add eslint-disable comments for TypeScript any types - Remove unused imports in paguTable.tsx - Integrate PaguTable, RealisasiTable, GrafikRealisasi into main Apbdes component - Component now fetches data from Valtio state and displays 3 tables + charts Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -2,12 +2,9 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes'
|
import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes'
|
||||||
import APBDesProgress from '@/app/darmasaba/(tambahan)/apbdes/lib/apbDesaProgress'
|
|
||||||
import { transformAPBDesData } from '@/app/darmasaba/(tambahan)/apbdes/lib/types'
|
|
||||||
import colors from '@/con/colors'
|
import colors from '@/con/colors'
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
BackgroundImage,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Center,
|
Center,
|
||||||
@@ -23,6 +20,9 @@ import { IconDownload } from '@tabler/icons-react'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useProxy } from 'valtio/utils'
|
import { useProxy } from 'valtio/utils'
|
||||||
|
import PaguTable from './lib/paguTable'
|
||||||
|
import RealisasiTable from './lib/realisasiTable'
|
||||||
|
import GrafikRealisasi from './lib/grafikRealisasi'
|
||||||
|
|
||||||
function Apbdes() {
|
function Apbdes() {
|
||||||
const state = useProxy(apbdes)
|
const state = useProxy(apbdes)
|
||||||
@@ -51,18 +51,17 @@ function Apbdes() {
|
|||||||
const dataAPBDes = state.findMany.data || []
|
const dataAPBDes = state.findMany.data || []
|
||||||
|
|
||||||
const years = Array.from(
|
const years = Array.from(
|
||||||
new Set(
|
new Set(
|
||||||
dataAPBDes
|
dataAPBDes
|
||||||
.map((item: any) => item?.tahun)
|
.map((item: any) => item?.tahun)
|
||||||
.filter((tahun): tahun is number => typeof tahun === 'number')
|
.filter((tahun): tahun is number => typeof tahun === 'number')
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.sort((a, b) => b - a)
|
||||||
.sort((a, b) => b - a)
|
.map(year => ({
|
||||||
.map(year => ({
|
value: year.toString(),
|
||||||
value: year.toString(),
|
label: `Tahun ${year}`,
|
||||||
label: `Tahun ${year}`,
|
}))
|
||||||
}))
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (years.length > 0 && !selectedYear) {
|
if (years.length > 0 && !selectedYear) {
|
||||||
@@ -71,7 +70,7 @@ function Apbdes() {
|
|||||||
}, [years, selectedYear])
|
}, [years, selectedYear])
|
||||||
|
|
||||||
const currentApbdes = dataAPBDes.length > 0
|
const currentApbdes = dataAPBDes.length > 0
|
||||||
? transformAPBDesData(dataAPBDes.find(item => item?.tahun?.toString() === selectedYear) || dataAPBDes[0])
|
? dataAPBDes.find((item: any) => item?.tahun?.toString() === selectedYear) || dataAPBDes[0]
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const data = (state.findMany.data || []).slice(0, 3)
|
const data = (state.findMany.data || []).slice(0, 3)
|
||||||
@@ -131,18 +130,22 @@ function Apbdes() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Progress */}
|
{/* Tabel & Grafik - Hanya tampilkan jika ada data */}
|
||||||
{currentApbdes ? (
|
{currentApbdes && currentApbdes.items?.length > 0 ? (
|
||||||
<APBDesProgress apbdesData={currentApbdes} />
|
<Stack gap="xl">
|
||||||
) : (
|
<PaguTable apbdesData={currentApbdes} />
|
||||||
|
<RealisasiTable apbdesData={currentApbdes} />
|
||||||
|
<GrafikRealisasi apbdesData={currentApbdes} />
|
||||||
|
</Stack>
|
||||||
|
) : currentApbdes ? (
|
||||||
<Box px={{ base: 'md', md: 100 }} py="md">
|
<Box px={{ base: 'md', md: 100 }} py="md">
|
||||||
<Text fz="sm" c="dimmed" ta="center" lh={1.5}>
|
<Text fz="sm" c="dimmed" ta="center" lh={1.5}>
|
||||||
Tidak ada data APBDes untuk tahun yang dipilih.
|
Tidak ada data item untuk tahun yang dipilih.
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
{/* GRID */}
|
{/* GRID - Card Preview */}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Center mx={{ base: 'md', md: 100 }} mih={200} pb="xl">
|
<Center mx={{ base: 'md', md: 100 }} mih={200} pb="xl">
|
||||||
<Loader size="lg" color="blue" />
|
<Loader size="lg" color="blue" />
|
||||||
@@ -165,14 +168,18 @@ function Apbdes() {
|
|||||||
spacing="lg"
|
spacing="lg"
|
||||||
pb="xl"
|
pb="xl"
|
||||||
>
|
>
|
||||||
{data.map((v, k) => (
|
{data.map((v: any, k: number) => (
|
||||||
<BackgroundImage
|
<Box
|
||||||
key={k}
|
key={k}
|
||||||
src={v.image?.link || ''}
|
|
||||||
h={360}
|
|
||||||
radius="xl"
|
|
||||||
pos="relative"
|
pos="relative"
|
||||||
style={{ overflow: 'hidden' }}
|
style={{
|
||||||
|
backgroundImage: `url(${v.image?.link || ''})`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
borderRadius: 16,
|
||||||
|
height: 360,
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Box pos="absolute" inset={0} bg="rgba(0,0,0,0.45)" style={{ borderRadius: 16 }} />
|
<Box pos="absolute" inset={0} bg="rgba(0,0,0,0.45)" style={{ borderRadius: 16 }} />
|
||||||
|
|
||||||
@@ -185,7 +192,7 @@ function Apbdes() {
|
|||||||
lh={1.35}
|
lh={1.35}
|
||||||
lineClamp={2}
|
lineClamp={2}
|
||||||
>
|
>
|
||||||
{v.name}
|
{v.name || `APBDes Tahun ${v.tahun}`}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
@@ -196,7 +203,7 @@ function Apbdes() {
|
|||||||
lh={1}
|
lh={1}
|
||||||
style={{ textShadow: '0 2px 8px rgba(0,0,0,0.6)' }}
|
style={{ textShadow: '0 2px 8px rgba(0,0,0,0.6)' }}
|
||||||
>
|
>
|
||||||
{v.jumlah}
|
{v.jumlah || '-'}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
@@ -212,7 +219,7 @@ function Apbdes() {
|
|||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Center>
|
</Center>
|
||||||
</Stack>
|
</Stack>
|
||||||
</BackgroundImage>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import { Paper, Title, Progress, Stack, Text } from '@mantine/core';
|
||||||
|
|
||||||
|
function Summary({ title, data }: any) {
|
||||||
|
if (!data || data.length === 0) return null;
|
||||||
|
|
||||||
|
const totalAnggaran = data.reduce((s: number, i: any) => s + i.anggaran, 0);
|
||||||
|
const totalRealisasi = data.reduce((s: number, i: any) => s + i.realisasi, 0);
|
||||||
|
|
||||||
|
const persen =
|
||||||
|
totalAnggaran > 0 ? (totalRealisasi / totalAnggaran) * 100 : 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<Text fw={600}>{title}</Text>
|
||||||
|
<Text>
|
||||||
|
Rp {totalRealisasi.toLocaleString('id-ID')} /
|
||||||
|
Rp {totalAnggaran.toLocaleString('id-ID')}
|
||||||
|
</Text>
|
||||||
|
<Progress value={persen} size="lg" radius="xl" />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function GrafikRealisasi({ apbdesData }: any) {
|
||||||
|
const items = apbdesData.items || [];
|
||||||
|
const tahun = apbdesData.tahun || new Date().getFullYear();
|
||||||
|
|
||||||
|
const pendapatan = items.filter((i: any) => i.tipe === 'pendapatan');
|
||||||
|
const belanja = items.filter((i: any) => i.tipe === 'belanja');
|
||||||
|
const pembiayaan = items.filter((i: any) => i.tipe === 'pembiayaan');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper withBorder p="md" radius="md">
|
||||||
|
<Title order={5} mb="md">
|
||||||
|
GRAFIK REALISASI APBDes {tahun}
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
<Stack>
|
||||||
|
<Summary title="Pendapatan" data={pendapatan} />
|
||||||
|
<Summary title="Belanja" data={belanja} />
|
||||||
|
<Summary title="Pembiayaan" data={pembiayaan} />
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
60
src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx
Normal file
60
src/app/darmasaba/_com/main-page/apbdes/lib/paguTable.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import { Paper, Table, Title } from '@mantine/core';
|
||||||
|
|
||||||
|
function Section({ title, data }: any) {
|
||||||
|
if (!data || data.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Td colSpan={2}>
|
||||||
|
<strong>{title}</strong>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
|
||||||
|
{data.map((item: any) => (
|
||||||
|
<Table.Tr key={item.id}>
|
||||||
|
<Table.Td>
|
||||||
|
{item.kode} - {item.uraian}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td ta="right">
|
||||||
|
Rp {item.anggaran.toLocaleString('id-ID')}
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PaguTable({ apbdesData }: any) {
|
||||||
|
const items = apbdesData.items || [];
|
||||||
|
|
||||||
|
const title =
|
||||||
|
apbdesData.tahun
|
||||||
|
? `PAGU APBDes Tahun ${apbdesData.tahun}`
|
||||||
|
: 'PAGU APBDes';
|
||||||
|
|
||||||
|
const pendapatan = items.filter((i: any) => i.tipe === 'pendapatan');
|
||||||
|
const belanja = items.filter((i: any) => i.tipe === 'belanja');
|
||||||
|
const pembiayaan = items.filter((i: any) => i.tipe === 'pembiayaan');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper withBorder p="md" radius="md">
|
||||||
|
<Title order={5} mb="md">{title}</Title>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Uraian</Table.Th>
|
||||||
|
<Table.Th ta="right">Anggaran (Rp)</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
<Section title="1) PENDAPATAN" data={pendapatan} />
|
||||||
|
<Section title="2) BELANJA" data={belanja} />
|
||||||
|
<Section title="3) PEMBIAYAAN" data={pembiayaan} />
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import { Paper, Table, Title, Badge } from '@mantine/core';
|
||||||
|
|
||||||
|
function Section({ title, data }: any) {
|
||||||
|
if (!data || data.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Td colSpan={3}>
|
||||||
|
<strong>{title}</strong>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
|
||||||
|
{data.map((item: any) => (
|
||||||
|
<Table.Tr key={item.id}>
|
||||||
|
<Table.Td>
|
||||||
|
{item.kode} - {item.uraian}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td ta="right">
|
||||||
|
Rp {item.realisasi.toLocaleString('id-ID')}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td ta="center">
|
||||||
|
<Badge
|
||||||
|
color={
|
||||||
|
item.persentase >= 100
|
||||||
|
? 'teal'
|
||||||
|
: item.persentase >= 60
|
||||||
|
? 'yellow'
|
||||||
|
: 'red'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item.persentase.toFixed(2)}%
|
||||||
|
</Badge>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RealisasiTable({ apbdesData }: any) {
|
||||||
|
const items = apbdesData.items || [];
|
||||||
|
|
||||||
|
const title =
|
||||||
|
apbdesData.tahun
|
||||||
|
? `REALISASI APBDes Tahun ${apbdesData.tahun}`
|
||||||
|
: 'REALISASI APBDes';
|
||||||
|
|
||||||
|
const pendapatan = items.filter((i: any) => i.tipe === 'pendapatan');
|
||||||
|
const belanja = items.filter((i: any) => i.tipe === 'belanja');
|
||||||
|
const pembiayaan = items.filter((i: any) => i.tipe === 'pembiayaan');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper withBorder p="md" radius="md">
|
||||||
|
<Title order={5} mb="md">{title}</Title>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<Table.Thead>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Th>Uraian</Table.Th>
|
||||||
|
<Table.Th ta="right">Realisasi (Rp)</Table.Th>
|
||||||
|
<Table.Th ta="center">%</Table.Th>
|
||||||
|
</Table.Tr>
|
||||||
|
</Table.Thead>
|
||||||
|
<Table.Tbody>
|
||||||
|
<Section title="1) PENDAPATAN" data={pendapatan} />
|
||||||
|
<Section title="2) BELANJA" data={belanja} />
|
||||||
|
<Section title="3) PEMBIAYAAN" data={pembiayaan} />
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user