Sinkronisasi UI & API Admin - User Submenu Demografi Pekerjaan, Menu Ekonomi

This commit is contained in:
2025-08-22 01:10:18 +08:00
parent 760ba4b6d2
commit 8469ebd2e1
5 changed files with 117 additions and 260 deletions

View File

@@ -143,8 +143,8 @@ function ListDemografiPekerjaan({ search }: { search: string }) {
dataKey="pekerjaan" dataKey="pekerjaan"
type="stacked" type="stacked"
series={[ series={[
{ name: 'lakiLaki', color: 'red.6', label: 'Laki - Laki' }, { name: 'lakiLaki', color: '#5082EE', label: 'Laki - Laki' },
{ name: 'perempuan', color: 'orange.6', label: 'Perempuan' }, { name: 'perempuan', color: '#6EDF9C', label: 'Perempuan' },
]} ]}
/> />
</Box> </Box>

View File

@@ -2,15 +2,16 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
'use client' 'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Box, Button, Group, Paper, Stack, TextInput, Title } from '@mantine/core'; import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react'; import { IconArrowBack } from '@tabler/icons-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';
import { useProxy } from 'valtio/utils'; import { useProxy } from 'valtio/utils';
import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa'; import grafikSektorUnggulan from '../../../_state/ekonomi/sektor-unggulan-desa';
import CreateEditor from '../../../_com/createEditor';
function CreateSektorUnggulanDesa() { function CreateSektorUnggulanDesa() {
const stateGrafik= useProxy(grafikSektorUnggulan); const stateGrafik = useProxy(grafikSektorUnggulan);
const [chartData, setChartData] = useState<any[]>([]); const [chartData, setChartData] = useState<any[]>([]);
const router = useRouter() const router = useRouter()
@@ -54,15 +55,15 @@ function CreateSektorUnggulanDesa() {
stateGrafik.create.form.name = val.currentTarget.value; stateGrafik.create.form.name = val.currentTarget.value;
}} }}
/> />
<TextInput <Box>
label="Deskripsi Sektor Unggulan" <Text fw={"bold"} fz={"sm"}>Deskripsi Sektor Ungggulan</Text>
type="text" <CreateEditor
value={stateGrafik.create.form.description} value={stateGrafik.create.form.description}
placeholder="Masukkan deskripsi sektor unggulan" onChange={(val) => {
onChange={(val) => { stateGrafik.create.form.description = val;
stateGrafik.create.form.description = val.currentTarget.value; }}
}} />
/> </Box>
<TextInput <TextInput
label="Jumlah" label="Jumlah"
type="number" type="number"

View File

@@ -1,6 +1,6 @@
'use client' 'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core'; import { Box, Button, Paper, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
import { IconDeviceImac, IconSearch } from '@tabler/icons-react'; import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
import HeaderSearch from '../../_com/header'; import HeaderSearch from '../../_com/header';
import JudulList from '../../_com/judulList'; import JudulList from '../../_com/judulList';
@@ -30,7 +30,7 @@ function SektorUnggulanDesa() {
function ListSektorUnggulanDesa({ search }: { search: string }) { function ListSektorUnggulanDesa({ search }: { search: string }) {
const router = useRouter(); const router = useRouter();
const state = useProxy(grafikSektorUnggulan); const state = useProxy(grafikSektorUnggulan);
const [chartData, setChartData] = useState<{id: string; name: string; description: string | null; value: number | null}[]>([]); const [chartData, setChartData] = useState<{ id: string; name: string; description: string | null; value: number | null }[]>([]);
const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready const [mounted, setMounted] = useState(false); // untuk memastikan DOM sudah ready
const isTablet = useMediaQuery('(max-width: 1024px)') const isTablet = useMediaQuery('(max-width: 1024px)')
const isMobile = useMediaQuery('(max-width: 768px)') const isMobile = useMediaQuery('(max-width: 768px)')
@@ -61,38 +61,41 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
}, [state.findMany.data]); }, [state.findMany.data]);
return ( return (
<Box py={10}> <Box>
<Paper bg={colors['white-1']} p={'md'}> <Stack gap={"xs"}>
<JudulList <Paper bg={colors['white-1']} p={'md'}>
title='List Sektor Unggulan Desa' <JudulList
href='/admin/ekonomi/sektor-unggulan-desa/create' title='List Sektor Unggulan Desa'
/> href='/admin/ekonomi/sektor-unggulan-desa/create'
<Table striped withTableBorder withRowBorders> />
<TableThead> <Table striped withTableBorder withRowBorders>
<TableTr> <TableThead>
<TableTh>Nama Sektor Unggulan</TableTh> <TableTr>
<TableTh>Deskripsi Sektor Unggulan</TableTh> <TableTh>Nama Sektor Unggulan</TableTh>
<TableTh>Detail</TableTh> <TableTh>Deskripsi Sektor Unggulan</TableTh>
</TableTr> <TableTh>Detail</TableTh>
</TableThead>
<TableTbody>
{filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd>{item.name}</TableTd>
<TableTd>{item.description}</TableTd>
<TableTd>
<Button onClick={() => router.push(`/admin/ekonomi/sektor-unggulan-desa/${item.id}`)}>
<IconDeviceImac size={20} />
</Button>
</TableTd>
</TableTr> </TableTr>
))} </TableThead>
</TableTbody> <TableTbody>
</Table> {filteredData.map((item) => (
</Paper> <TableTr key={item.id}>
<TableTd>{item.name}</TableTd>
<TableTd>
<Text truncate={"end"} fz={'sm'} lineClamp={1} dangerouslySetInnerHTML={{ __html: item.description || '' }}></Text>
</TableTd>
<TableTd>
<Button onClick={() => router.push(`/admin/ekonomi/sektor-unggulan-desa/${item.id}`)}>
<IconDeviceImac size={20} />
</Button>
</TableTd>
</TableTr>
))}
</TableTbody>
</Table>
</Paper>
{/* Chart */} {/* Chart */}
{!mounted && !chartData ? ( {!mounted && !chartData ? (
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}> <Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
<Paper bg={colors['white-1']} p={'md'}> <Paper bg={colors['white-1']} p={'md'}>
<Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title> <Title pb={10} order={3}>Grafik Hasil Kepuasan Masyarakat</Title>
@@ -115,6 +118,7 @@ function ListSektorUnggulanDesa({ search }: { search: string }) {
</Paper> </Paper>
</Box> </Box>
)} )}
</Stack>
</Box> </Box>
); );
} }

View File

@@ -1,192 +1,32 @@
'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Stack, Box, Paper, Text, ColorSwatch, Flex } from '@mantine/core'; import { Stack, Box, Paper, Text, ColorSwatch, Flex, Skeleton } from '@mantine/core';
import React from 'react'; import React from 'react';
import BackButton from '../../desa/layanan/_com/BackButto'; import BackButton from '../../desa/layanan/_com/BackButto';
import { BarChart } from '@mantine/charts'; import { BarChart } from '@mantine/charts';
import { useProxy } from 'valtio/utils';
import grafikDemografiPekerjaan from '@/app/admin/(dashboard)/_state/ekonomi/demografi-pekerjaan';
import { useShallowEffect } from '@mantine/hooks';
const data = [
{
id: 1,
Pekerjaan: 'Guru',
laki: 2,
perempuan: 3
},
{
id: 2,
Pekerjaan: 'Belajar/Mahasiswa',
laki: 37,
perempuan: 38
},
{
id: 3,
Pekerjaan: 'Karyawan Bumdn',
laki: 1,
perempuan: 0
},
{
id: 4,
Pekerjaan: 'Buruh Tani/Perkebunan',
laki: 1,
perempuan: 0
},
{
id: 5,
Pekerjaan: 'Karyawan Swasta',
laki: 3,
perempuan: 17
},
{
id: 6,
Pekerjaan: 'Karyawan Honorer',
laki: 2,
perempuan: 1
},
{
id: 7,
Pekerjaan: 'Buruh Harian Lepas',
laki: 8,
perempuan: 5
},
{
id: 8,
Pekerjaan: 'Belum/Tidak Bekerja',
laki: 87,
perempuan: 44
},
{
id: 9,
Pekerjaan: ' Kepolisian RI (Polri)',
laki: 4,
perempuan: 0
},
{
id: 10,
Pekerjaan: 'Wiraswasta Mengurus Rumah Tangga',
laki: 1,
perempuan: 7
},
{
id: 11,
Pekerjaan: 'Dosen',
laki: 1,
perempuan: 1
},
{
id: 12,
Pekerjaan: 'Perangkat Desa',
laki: 17,
perempuan: 19
},
{
id: 13,
Pekerjaan: 'Nelayan',
laki: 3,
perempuan: 0
},
{
id: 14,
Pekerjaan: 'Penyuluh Pertanian',
laki: 33,
perempuan: 24
},
{
id: 15,
Pekerjaan: 'Tukang Las/Pandai Besi',
laki: 5,
perempuan: 0
},
{
id: 16,
Pekerjaan: 'Sopir/Driver',
laki: 10,
perempuan: 3
},
{
id: 17,
Pekerjaan: 'Teknisi/Listrik',
laki: 25,
perempuan: 0
},
{
id: 18,
Pekerjaan: 'Montir/Mekanik',
laki: 25,
perempuan: 0
},
{
id: 19,
Pekerjaan: 'Karyawan Hotel/Pariwisata',
laki: 2,
perempuan: 52
},
{
id: 20,
Pekerjaan: 'Pengrajin (Batik, Anyaman, Kayu)',
laki: 5,
perempuan: 25
},
{
id: 21,
Pekerjaan: 'Tukang Bangunan',
laki: 25,
perempuan: 5
},
{
id: 22,
Pekerjaan: 'Tukang Kayu/Furnitur',
laki: 25,
perempuan: 0
},
{
id: 23,
Pekerjaan: 'Penjahit',
laki: 2,
perempuan: 35
},
{
id: 24,
Pekerjaan: 'Pedagang Pasar',
laki: 25,
perempuan: 30
},
{
id: 25,
Pekerjaan: 'Warung Makan/Penjual Makanan',
laki: 15,
perempuan: 30
},
{
id: 26,
Pekerjaan: 'Satpam/Security',
laki: 20,
perempuan: 5
},
{
id: 27,
Pekerjaan: 'Pengusaha Kecil (UMKM)',
laki: 5,
perempuan: 20
},
{
id: 28,
Pekerjaan: 'Karyawan Restoran/Kafe',
laki: 5,
perempuan: 15
},
{
id: 29,
Pekerjaan: 'Freelancer',
laki: 20,
perempuan: 10
},
{
id: 30,
Pekerjaan: 'Fotografer',
laki: 25,
perempuan: 9
},
]
function Page() { function Page() {
const state = useProxy(grafikDemografiPekerjaan)
const {
data,
} = state.findMany
useShallowEffect(() => {
state.findMany.load()
}, [])
if (!data) {
return (
<Stack py={10}>
<Skeleton h={500} />
</Stack>
)
}
return ( return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}> <Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}> <Box px={{ base: 'md', md: 100 }}>
@@ -207,7 +47,13 @@ function Page() {
p={10} p={10}
mb={50} mb={50}
h={400} h={400}
data={data} w={150}
data={data.map((item) => ({
id: item.id,
Pekerjaan: item.pekerjaan,
laki: item.lakiLaki,
perempuan: item.perempuan,
}))}
dataKey="Pekerjaan" dataKey="Pekerjaan"
series={[ series={[
{ name: 'laki', color: '#5082EE' }, { name: 'laki', color: '#5082EE' },

View File

@@ -1,23 +1,33 @@
'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import { Stack, Box, Text, Paper } from '@mantine/core'; import { Stack, Box, Text, Paper, Skeleton } from '@mantine/core';
import React from 'react'; import React from 'react';
import BackButton from '../../desa/layanan/_com/BackButto'; import BackButton from '../../desa/layanan/_com/BackButto';
import { BarChart } from '@mantine/charts'; import { BarChart } from '@mantine/charts';
import { useProxy } from 'valtio/utils';
import grafikSektorUnggulan from '@/app/admin/(dashboard)/_state/ekonomi/sektor-unggulan-desa';
import { useShallowEffect } from '@mantine/hooks';
const data = [
{
id: 1,
sektor: 'Sektor Pertanian',
Ton: 20
},
{
id: 2,
sektor: 'Sektor Peternakan',
Ton: 5
},
]
function Page() { function Page() {
const state = useProxy(grafikSektorUnggulan)
const {
data,
loading,
} = state.findMany
useShallowEffect(() => {
state.findMany.load()
}, [])
if (loading || !data) {
return (
<Stack py={10}>
<Skeleton h={500} />
</Stack>
)
}
return ( return (
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}> <Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
<Box px={{ base: 'md', md: 100 }}> <Box px={{ base: 'md', md: 100 }}>
@@ -31,28 +41,24 @@ function Page() {
</Box> </Box>
<Box px={{ base: "md", md: 100 }}> <Box px={{ base: "md", md: 100 }}>
<Stack gap={'lg'} justify='center'> <Stack gap={'lg'} justify='center'>
<Paper p={'xl'}> {data.map((v, k) => {
<Text fw={'bold'} fz={'h4'}>Jumlah Penduduk Miskin Per Tahun</Text> return (
<Text fz={'h4'} ta={'justify'}> <Paper p={'xl'} key={k}>
Pertanian di Darmasaba berfokus pada padi, sayuran, dan hortikultura yang dikembangkan dengan metode pertanian <Text fw={'bold'} fz={'h4'}>{v.name}</Text>
organik serta sistem irigasi tradisional yang efisien. Keberlanjutan dalam pertanian juga didukung dengan pemanfaatan <Text fz={'h4'} ta={'justify'} dangerouslySetInnerHTML={{ __html: v.description || '' }} />
teknologi modern untuk meningkatkan produktivitas hasil panen. </Paper>
</Text> )
</Paper> })}
<Paper p={'xl'}>
<Text fw={'bold'} fz={'h4'}>Sektor Peternakan</Text>
<Text fz={'h4'} ta={'justify'}>
Di bidang peternakan, Desa Darmasaba memiliki potensi besar dalam pengembangan sapi, ayam, dan babi. Sistem
peternakan yang diterapkan mengutamakan pengelolaan pakan alami dan perawatan hewan yang sehat, sehingga
menghasilkan produk ternak berkualitas tinggi.
</Text>
</Paper>
<Paper p={'xl'}> <Paper p={'xl'}>
<Text pb={10} fw={'bold'} fz={'h4'}>Statistik Sektor Unggulan Darmasaba</Text> <Text pb={10} fw={'bold'} fz={'h4'}>Statistik Sektor Unggulan Darmasaba</Text>
<BarChart <BarChart
p={10} p={10}
h={300} h={300}
data={data} data={data.map((item) => ({
id: item.id,
sektor: item.name,
Ton: item.value,
}))}
dataKey="sektor" dataKey="sektor"
series={[ series={[
{ name: 'Ton', color: colors['blue-button'] }, { name: 'Ton', color: colors['blue-button'] },