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:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user