Fix QC Kak Inno 22 Des

Fix QC Kak Ayu 22 Des
Fix Tampilan Admin Mobile Device Menu Ekonomi
Fix Search -> useDebounced Menu Ekonomi
This commit is contained in:
2025-12-23 17:18:36 +08:00
parent 29065cb3e2
commit f0f201c853
75 changed files with 3023 additions and 1177 deletions

View File

@@ -142,7 +142,7 @@ function EditProgramKemiskinan() {
};
return (
<Box px={{ base: 'sm', md: 'lg' }} py="md">
<Box px={{ base: 0, md: 'lg' }} py="xs">
{/* Header */}
<Group mb="md">
<Button

View File

@@ -50,7 +50,7 @@ function DetailProgramKemiskinan() {
const data = programState.findUnique.data;
return (
<Box py={10}>
<Box px={{ base: 0, md: 'lg' }} py="xs">
{/* Tombol Kembali */}
<Button
variant="subtle"
@@ -64,7 +64,7 @@ function DetailProgramKemiskinan() {
{/* Card utama */}
<Paper
withBorder
w={{ base: "100%", md: "60%" }}
w={{ base: "100%", md: "70%" }}
bg={colors['white-1']}
p="lg"
radius="md"

View File

@@ -71,7 +71,7 @@ function CreateProgramKemiskinan() {
};
return (
<Box px={{ base: 'sm', md: 'lg' }} py="md">
<Box px={{ base: 0, md: 'lg' }} py="xs">
{/* Header dengan tombol back */}
<Group mb="md">
<Button

View File

@@ -1,18 +1,43 @@
'use client'
/* eslint-disable @typescript-eslint/no-explicit-any */
import colors from '@/con/colors';
import { Box, Button, Center, Group, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import {
Box,
Button,
Center,
Group,
Pagination,
Paper,
Skeleton,
Stack,
Table,
TableTbody,
TableTd,
TableTh,
TableThead,
TableTr,
Text,
Title,
} from '@mantine/core';
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { CartesianGrid, Legend, Line, LineChart, Tooltip as RechartTooltip, XAxis, YAxis } from 'recharts';
import {
CartesianGrid,
Legend,
Line,
LineChart,
Tooltip as RechartTooltip,
XAxis,
YAxis,
} from 'recharts';
import { useProxy } from 'valtio/utils';
import HeaderSearch from '../../_com/header';
import programKemiskinanState from '../../_state/ekonomi/program-kemiskinan';
function ProgramKemiskinan() {
const [search, setSearch] = useState("");
const [search, setSearch] = useState('');
return (
<Box>
<HeaderSearch
@@ -32,21 +57,22 @@ function ListProgramKemiskinan({ search }: { search: string }) {
const router = useRouter();
const [lineChart, setLineChart] = useState<any[]>([]);
const [mounted, setMounted] = useState(false);
const [debouncedSearch] = useDebouncedValue(search, 1000);
const { data, page, totalPages, loading, load } = programState.findMany;
useShallowEffect(() => {
setMounted(true);
load(page, 10, search);
}, [page, search]);
load(page, 10, debouncedSearch);
}, [page, debouncedSearch]);
useEffect(() => {
if (data) {
const chartData = data
.filter(item => item.statistik)
.map(item => ({
.filter((item) => item.statistik)
.map((item) => ({
tahun: item.statistik?.tahun,
jumlah: Number(item.statistik?.jumlah)
jumlah: Number(item.statistik?.jumlah),
}))
.sort((a, b) => (a.tahun || 0) - (b.tahun || 0));
@@ -58,49 +84,90 @@ function ListProgramKemiskinan({ search }: { search: string }) {
if (loading || !data) {
return (
<Stack py={10}>
<Stack py={{ base: 'md', md: 'lg' }}>
<Skeleton height={600} radius="md" />
</Stack>
);
}
return (
<Box py={10}>
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
<Group justify="space-between" mb="md">
<Title order={4}>Daftar Program Kemiskinan</Title>
<Button leftSection={<IconPlus size={18} />} color="blue" variant="light" onClick={() => router.push('/admin/ekonomi/program-kemiskinan/create')}>
<Box py={{ base: 'md', md: 'lg' }}>
{/* Daftar Program Kemiskinan */}
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
<Title order={4} lh={1.2}>
Daftar Program Kemiskinan
</Title>
<Button
leftSection={<IconPlus size={18} />}
color="blue"
variant="light"
onClick={() => router.push('/admin/ekonomi/program-kemiskinan/create')}
>
Tambah Baru
</Button>
</Group>
<Box style={{ overflowX: 'auto' }}>
<Table highlightOnHover>
{/* Desktop Table */}
<Box visibleFrom="md">
<Table
highlightOnHover
miw={0}
style={{
tableLayout: 'fixed',
width: '100%',
}}
>
<TableThead>
<TableTr>
<TableTh style={{ width: '30%' }}>Judul Program</TableTh>
<TableTh style={{ width: '40%' }}>Deskripsi Singkat</TableTh>
<TableTh style={{ width: '20%' }}>Jumlah Masyarakat Miskin</TableTh>
<TableTh style={{ width: '10%' }}>Aksi</TableTh>
<TableTh style={{ width: '30%' }}>
<Text fz="sm" fw={600} lh={1.4}>
Judul Program
</Text>
</TableTh>
<TableTh style={{ width: '40%' }}>
<Text fz="sm" fw={600} lh={1.4}>
Deskripsi Singkat
</Text>
</TableTh>
<TableTh style={{ width: '20%' }}>
<Text fz="sm" fw={600} lh={1.4}>
Jumlah Masyarakat Miskin
</Text>
</TableTh>
<TableTh style={{ width: '10%' }}>
<Text fz="sm" fw={600} lh={1.4}>
Aksi
</Text>
</TableTh>
</TableTr>
</TableThead>
<TableTbody>
{filteredData.length > 0 ? (
filteredData.map(item => (
filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd>
<Text fw={500} truncate lineClamp={1}>{item.nama}</Text>
<Text fw={500} fz="md" lh={1.45} truncate lineClamp={1}>
{item.nama}
</Text>
</TableTd>
<TableTd>
<Text fz="sm" truncate lineClamp={2} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
<Text fz="sm" lh={1.45} truncate lineClamp={2} c="dark.9" dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
</TableTd>
<TableTd>
<Text fz="md" lh={1.45} fw={500}>
{item.statistik?.jumlah || '-'}
</Text>
</TableTd>
<TableTd>{item.statistik?.jumlah || '-'}</TableTd>
<TableTd>
<Button
variant="light"
color="blue"
onClick={() => router.push(`/admin/ekonomi/program-kemiskinan/${item.id}`)}
fz="sm"
lh={1.4}
>
<IconDeviceImac size={20} />
<IconDeviceImac size={18} />
<Text ml={5}>Detail</Text>
</Button>
</TableTd>
@@ -110,7 +177,9 @@ function ListProgramKemiskinan({ search }: { search: string }) {
<TableTr>
<TableTd colSpan={4}>
<Center py={20}>
<Text color="dimmed">Tidak ada data program kemiskinan yang cocok</Text>
<Text c="dimmed" fz="sm" lh={1.4}>
Tidak ada data program kemiskinan yang cocok
</Text>
</Center>
</TableTd>
</TableTr>
@@ -118,6 +187,61 @@ function ListProgramKemiskinan({ search }: { search: string }) {
</TableTbody>
</Table>
</Box>
{/* Mobile Cards */}
<Box hiddenFrom="md">
<Stack gap="md">
{filteredData.length > 0 ? (
filteredData.map((item) => (
<Paper key={item.id} withBorder p="md" radius="sm">
<Stack gap={4}>
<Box>
<Text fz="sm" fw={600} lh={1.4}>
Judul Program
</Text>
<Text fz="sm" fw={500} lh={1.4}>
{item.nama}
</Text>
</Box>
<Box>
<Text fz="sm" fw={600} lh={1.4}>
Deskripsi Singkat
</Text>
<Text fz="sm" fw={500} lh={1.4} c="dark.9" dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
</Box>
<Box>
<Text fz="sm" fw={600} lh={1.4}>
Jumlah Masyarakat Miskin
</Text>
<Text fz="sm" fw={500} lh={1.4}>
{item.statistik?.jumlah || '-'}
</Text>
</Box>
<Box>
<Button
fullWidth
variant="light"
color="blue"
onClick={() => router.push(`/admin/ekonomi/program-kemiskinan/${item.id}`)}
fz="sm"
lh={1.4}
>
<IconDeviceImac size={18} />
<Text ml={5}>Detail</Text>
</Button>
</Box>
</Stack>
</Paper>
))
) : (
<Center py={20}>
<Text c="dimmed" fz="sm" lh={1.4}>
Tidak ada data program kemiskinan yang cocok
</Text>
</Center>
)}
</Stack>
</Box>
</Paper>
{/* Pagination */}
@@ -137,25 +261,45 @@ function ListProgramKemiskinan({ search }: { search: string }) {
</Center>
{/* Chart */}
<Box py={10}>
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
<Title pb={10} order={3}>Grafik Berdasarkan Responden</Title>
<Box pt={{ base: 'md', md: 'lg' }}>
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
<Title order={4} lh={1.2} pb={{ base: 'sm', md: 'md' }}>
Grafik Berdasarkan Responden
</Title>
{mounted && lineChart.length > 0 ? (
<Box style={{ width: '100%', overflowX: 'auto' }}>
<LineChart width={820} height={300} data={lineChart}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="tahun" />
<YAxis />
<RechartTooltip
formatter={(value: any, name: string) => [`${value} orang`, name]}
labelFormatter={(label: any) => `Tahun: ${label}`}
/>
<Legend />
<Line type="monotone" dataKey="jumlah" name="Jumlah per Tahun" stroke={colors['blue-button']} />
</LineChart>
<Box>
<Box
component="div"
miw={{ base: 320, md: 820 }}
mx="auto"
style={{ overflowX: 'auto' }}
>
<LineChart
width={Math.max(320, lineChart.length * 60)}
height={300}
data={lineChart}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="tahun" />
<YAxis />
<RechartTooltip
formatter={(value: any) => [`${value} orang`, 'Jumlah']}
labelFormatter={(label: any) => `Tahun: ${label}`}
/>
<Legend />
<Line
type="monotone"
dataKey="jumlah"
name="Jumlah per Tahun"
stroke={colors['blue-button']}
/>
</LineChart>
</Box>
</Box>
) : (
<Text c='dimmed'>Belum ada data untuk ditampilkan dalam grafik</Text>
<Text c="dimmed" fz={{ base: 'xs', md: 'sm' }} lh={1.4}>
Belum ada data untuk ditampilkan dalam grafik
</Text>
)}
</Paper>
</Box>
@@ -163,4 +307,4 @@ function ListProgramKemiskinan({ search }: { search: string }) {
);
}
export default ProgramKemiskinan;
export default ProgramKemiskinan;