Fix QC Kak Ayu 15 Des
Fix QC Kak Inno 15 Des Fix UI User Font Size, Font Weight, Line Height Fix UI Admin Font Size, Font Weight, Line Height & UI Mobile
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Box, Paper, Text, ColorSwatch, Flex, Skeleton } from '@mantine/core';
|
||||
import { Stack, Box, Paper, Text, ColorSwatch, Flex, Skeleton, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
import { BarChart } from '@mantine/charts';
|
||||
@@ -32,23 +32,47 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }} >
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
c={colors["blue-button"]}
|
||||
fw="bold"
|
||||
lh={1.2}
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Demografi Pekerjaan
|
||||
</Title>
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
c="black"
|
||||
style={{ lineHeight: 1.5 }}
|
||||
>
|
||||
Desa Darmasaba memiliki komposisi penduduk yang beragam dalam sektor pekerjaan
|
||||
</Text>
|
||||
<Text ta={'center'} fz={'h4'}>Desa Darmasaba memiliki komposisi penduduk yang beragam dalam sektor pekerjaan</Text>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<Paper p={'xl'}>
|
||||
<Box style={{overflowX: 'scroll'}}>
|
||||
<Text pb={5} fw={'bold'} fz={'h4'}>Statistik Demografi Pekerjaan Di Desa Darmasaba</Text>
|
||||
<Box style={{ overflowX: 'auto' }} w={"100%"}>
|
||||
<Text
|
||||
pb={5}
|
||||
fw={'bold'}
|
||||
fz={{ base: 'md', md: 'lg' }}
|
||||
lh={1.2}
|
||||
c="black"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Statistik Demografi Pekerjaan Di Desa Darmasaba
|
||||
</Text>
|
||||
<BarChart
|
||||
type='stacked'
|
||||
p={10}
|
||||
mb={50}
|
||||
h={400}
|
||||
w={Math.max(data.length * 120, 800)} // auto lebar sesuai jumlah data
|
||||
w={Math.max(data.length * 120, 800)}
|
||||
data={data.map((item) => ({
|
||||
id: item.id,
|
||||
Pekerjaan: item.pekerjaan,
|
||||
@@ -62,28 +86,45 @@ function Page() {
|
||||
]}
|
||||
tickLine="y"
|
||||
xAxisProps={{
|
||||
angle: -45, // Rotate labels by -45 degrees
|
||||
textAnchor: 'end', // Anchor text to the end for better alignment
|
||||
height: 100, // Increase height for rotated labels
|
||||
interval: 0, // Show all labels
|
||||
angle: -45,
|
||||
textAnchor: 'end',
|
||||
height: 100,
|
||||
interval: 0,
|
||||
style: {
|
||||
fontSize: '12px', // Adjust font size if needed
|
||||
fontSize: '12px',
|
||||
overflow: 'visible',
|
||||
whiteSpace: 'nowrap'
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: 1.4,
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'}>
|
||||
<Box>
|
||||
<Flex gap={{base: 7, md: 5}} align={'center'}>
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Laki-Laki</Text>
|
||||
<Flex gap={{ base: 7, md: 5 }} align={'center'}>
|
||||
<Text
|
||||
fw={'bold'}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.2}
|
||||
c="black"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Laki-Laki
|
||||
</Text>
|
||||
<ColorSwatch color="#5082EE" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{base: 7, md: 5}} align={'center'}>
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Perempuan</Text>
|
||||
<Flex gap={{ base: 7, md: 5 }} align={'center'}>
|
||||
<Text
|
||||
fw={'bold'}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.2}
|
||||
c="black"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Perempuan
|
||||
</Text>
|
||||
<ColorSwatch color="#6EDF9C" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
@@ -95,4 +136,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -2,7 +2,7 @@
|
||||
import jumlahPendudukMiskin from '@/app/admin/(dashboard)/_state/ekonomi/jumlah-penduduk-miskin';
|
||||
import colors from '@/con/colors';
|
||||
import { BarChart } from '@mantine/charts';
|
||||
import { Box, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { Box, Paper, Skeleton, Stack, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
@@ -17,13 +17,10 @@ function Page() {
|
||||
const state = useProxy(jumlahPendudukMiskin)
|
||||
const [chartData, setChartData] = useState<JPMGrafik[]>([])
|
||||
|
||||
|
||||
useShallowEffect(() => {
|
||||
state.findMany.load()
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (state.findMany.data) {
|
||||
setChartData(state.findMany.data.map((item) => ({
|
||||
@@ -48,20 +45,30 @@ function Page() {
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }} >
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Title
|
||||
order={1}
|
||||
ta={"center"}
|
||||
c={colors["blue-button"]}
|
||||
fw={"bold"}
|
||||
lh={1.1}
|
||||
>
|
||||
Jumlah Penduduk Miskin
|
||||
</Text>
|
||||
</Title>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<Paper p={'xl'}>
|
||||
<Text fz={'h3'}>Jumlah Data Penduduk Miskin</Text>
|
||||
<Text fw={"bold"} fz={'h1'}>
|
||||
<Title order={3} fw={'normal'} lh={1.1}>
|
||||
Jumlah Data Penduduk Miskin
|
||||
</Title>
|
||||
<Title order={2} fw={"bold"} lh={1.1}>
|
||||
{state.findMany.data?.reduce((sum, item) => sum + (Number(item.totalPoorPopulation) || 0), 0).toLocaleString()} Orang
|
||||
</Text>
|
||||
</Title>
|
||||
</Paper>
|
||||
<Paper p={'xl'}>
|
||||
<Text pb={10} fw={'bold'} fz={'h4'}>Jumlah Penduduk Miskin Per Tahun</Text>
|
||||
<Title order={3} pb={10} fw={'bold'} lh={1.1}>
|
||||
Jumlah Penduduk Miskin Per Tahun
|
||||
</Title>
|
||||
<BarChart
|
||||
h={300}
|
||||
data={chartData}
|
||||
@@ -79,4 +86,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -3,7 +3,7 @@
|
||||
import grafikNganggur from '@/app/admin/(dashboard)/_state/ekonomi/usia-kerja-nganggur';
|
||||
import colors from '@/con/colors';
|
||||
import { PieChart } from '@mantine/charts';
|
||||
import { Box, Center, ColorSwatch, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { Box, Center, ColorSwatch, Flex, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
@@ -56,7 +56,7 @@ function Page() {
|
||||
}
|
||||
}, [stateGrafikNganggurPendidikan.findMany.data])
|
||||
|
||||
if (!stateGrafikNganggur.findMany.data) {
|
||||
if (!stateGrafikNganggur.findMany.data || !stateGrafikNganggurPendidikan.findMany.data) {
|
||||
return (
|
||||
<Box>
|
||||
<Skeleton h={500} />
|
||||
@@ -64,114 +64,151 @@ function Page() {
|
||||
)
|
||||
}
|
||||
|
||||
if (!stateGrafikNganggur.findMany.data) {
|
||||
return (
|
||||
<Box>
|
||||
<Skeleton h={500} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="22" style={{ overflow: 'auto' }}>
|
||||
<Box px={{ base: 'md', md: 50, lg: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 50, lg: 100 }} >
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Box px={{ base: 'md', md: 50, lg: 100 }}>
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
c={colors["blue-button"]}
|
||||
fw="bold"
|
||||
style={{ lineHeight: 1.15 }}
|
||||
>
|
||||
Jumlah Penduduk Usia Kerja Yang Menganggur
|
||||
</Text>
|
||||
</Title>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 50, lg: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<Paper p={'lg'}>
|
||||
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Usia</Text>
|
||||
{mounted && donutGrafikNganggurData.length > 0 ? (<Box style={{ width: '100%', height: 'auto', minHeight: 200 }}>
|
||||
<Box w="100%" maw={{ base: '100%', md: 400 }} mx="auto">
|
||||
<PieChart
|
||||
w="100%"
|
||||
h={250} // lebih kecil biar aman di mobile
|
||||
withLabelsLine
|
||||
labelsPosition="outside"
|
||||
labelsType="percent"
|
||||
withLabels
|
||||
data={donutGrafikNganggurData}
|
||||
withTooltip
|
||||
tooltipDataSource="segment"
|
||||
/>
|
||||
<Title
|
||||
order={2}
|
||||
fw="bold"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Pengangguran Berdasarkan Usia
|
||||
</Title>
|
||||
{mounted && donutGrafikNganggurData.length > 0 ? (
|
||||
<Box style={{ width: '100%', height: 'auto', minHeight: 200 }}>
|
||||
<Box w="100%" maw={{ base: '100%', md: 400 }} mx="auto">
|
||||
<PieChart
|
||||
w="100%"
|
||||
h={250}
|
||||
withLabelsLine
|
||||
labelsPosition="outside"
|
||||
labelsType="percent"
|
||||
withLabels
|
||||
data={donutGrafikNganggurData}
|
||||
withTooltip
|
||||
tooltipDataSource="segment"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>) : <Skeleton h={500} />}
|
||||
) : (
|
||||
<Skeleton h={500} />
|
||||
)}
|
||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'} wrap="wrap">
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>18-25</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
18-25
|
||||
</Text>
|
||||
<ColorSwatch color="#4b6Ef5" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>26-35</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
26-35
|
||||
</Text>
|
||||
<ColorSwatch color="#14b885" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>36-45</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
36-45
|
||||
</Text>
|
||||
<ColorSwatch color="#E6A03B" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>46+</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
46+
|
||||
</Text>
|
||||
<ColorSwatch color="#DB524D" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Paper>
|
||||
<Paper p={'lg'}>
|
||||
<Text fw={'bold'} fz={'h3'}>Pengangguran Berdasarkan Pendidikan</Text>
|
||||
{mounted2 && donutGrafikNganggurDataPendidikan.length > 0 ? (<Center>
|
||||
<Box w="100%" style={{ maxWidth: 400, margin: "0 auto" }}>
|
||||
<PieChart
|
||||
w="100%"
|
||||
h="min(250px, 50vh)" // lebih kecil biar aman di mobile
|
||||
withLabelsLine
|
||||
labelsPosition="outside"
|
||||
labelsType="percent"
|
||||
withLabels
|
||||
data={donutGrafikNganggurDataPendidikan}
|
||||
withTooltip
|
||||
tooltipDataSource="segment"
|
||||
/>
|
||||
</Box>
|
||||
</Center>) : <Skeleton h={500} />}
|
||||
<Title
|
||||
order={2}
|
||||
fw="bold"
|
||||
style={{ lineHeight: 1.2 }}
|
||||
>
|
||||
Pengangguran Berdasarkan Pendidikan
|
||||
</Title>
|
||||
{mounted2 && donutGrafikNganggurDataPendidikan.length > 0 ? (
|
||||
<Center>
|
||||
<Box w="100%" style={{ maxWidth: 400, margin: "0 auto" }}>
|
||||
<PieChart
|
||||
w="100%"
|
||||
h="min(250px, 50vh)"
|
||||
withLabelsLine
|
||||
labelsPosition="outside"
|
||||
labelsType="percent"
|
||||
withLabels
|
||||
data={donutGrafikNganggurDataPendidikan}
|
||||
withTooltip
|
||||
tooltipDataSource="segment"
|
||||
/>
|
||||
</Box>
|
||||
</Center>
|
||||
) : (
|
||||
<Skeleton h={500} />
|
||||
)}
|
||||
<Flex pb={30} justify={'center'} gap={'xl'} align={'center'} wrap="wrap">
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>SD</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
SD
|
||||
</Text>
|
||||
<ColorSwatch color="#4b6Ef5" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>SMP</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
SMP
|
||||
</Text>
|
||||
<ColorSwatch color="#14b885" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>SMA/SMK</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
SMA/SMK
|
||||
</Text>
|
||||
<ColorSwatch color="#E6A03B" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>D3</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
D3
|
||||
</Text>
|
||||
<ColorSwatch color="#DB524D" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 5, md: 8 }} align={'center'} wrap="wrap">
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>S1</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} style={{ lineHeight: 1.45 }}>
|
||||
S1
|
||||
</Text>
|
||||
<ColorSwatch color="#1018A8FF" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
@@ -183,4 +220,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -36,7 +36,6 @@ function Page() {
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
if (state.findMany.data) {
|
||||
// Set chart data
|
||||
setChartData(state.findMany.data.map((item) => ({
|
||||
id: item.id,
|
||||
bulan: item.month,
|
||||
@@ -44,7 +43,6 @@ function Page() {
|
||||
takberpendidikan: Number(item.uneducatedUnemployment),
|
||||
})));
|
||||
|
||||
// Calculate yearly totals
|
||||
const currentYearData = state.findMany.data.filter(item => item.year === currentYear);
|
||||
if (currentYearData.length > 0) {
|
||||
const yearlyTotal = {
|
||||
@@ -72,30 +70,37 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }} >
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Title
|
||||
order={1}
|
||||
ta={"center"}
|
||||
c={colors["blue-button"]}
|
||||
fw={"bold"}
|
||||
lh={1.2}
|
||||
>
|
||||
Jumlah Pengangguran
|
||||
</Text>
|
||||
</Title>
|
||||
<Group py={20} align='center' justify='space-between'>
|
||||
<Text fz={'h4'} fw={"bold"}>DATA PENGANGGURAN DESA</Text>
|
||||
<Title order={2} fw={"bold"} lh={1.2}>
|
||||
DATA PENGANGGURAN DESA
|
||||
</Title>
|
||||
</Group>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<SimpleGrid
|
||||
cols={1}
|
||||
pb={20}
|
||||
>
|
||||
<SimpleGrid cols={1} pb={20}>
|
||||
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="md">
|
||||
{/* Total Unemployment Card */}
|
||||
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||
<Flex direction="column" gap="md">
|
||||
<IconUserOff size={35} color={colors['blue-button']} />
|
||||
<Text fz="h4" fw={600}>Total Pengangguran</Text>
|
||||
<Text fz="h2" fw={700} c={colors['blue-button']}>
|
||||
<Title order={3} fw={600} lh={1.2}>
|
||||
Total Pengangguran
|
||||
</Title>
|
||||
<Text fz={{ base: 'lg', md: 'xl' }} fw={700} c={colors['blue-button']} lh={1.2}>
|
||||
{yearlyData?.total.toLocaleString() || 0} Orang
|
||||
</Text>
|
||||
<Text fz="sm" c="dimmed">
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed" lh={1.4}>
|
||||
Total data tahun {currentYear}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -105,11 +110,13 @@ function Page() {
|
||||
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||
<Flex direction="column" gap="md">
|
||||
<IconSchool size={35} color="#5082EE" />
|
||||
<Text fz="h4" fw={600}>Pengangguran Terdidik</Text>
|
||||
<Text fz="h2" fw={700} c="#5082EE">
|
||||
<Title order={3} fw={600} lh={1.2}>
|
||||
Pengangguran Terdidik
|
||||
</Title>
|
||||
<Text fz={{ base: 'lg', md: 'xl' }} fw={700} c="#5082EE" lh={1.2}>
|
||||
{yearlyData?.educated.toLocaleString() || 0} Orang
|
||||
</Text>
|
||||
<Text fz="sm" c="dimmed">
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed" lh={1.4}>
|
||||
{yearlyData ?
|
||||
<>
|
||||
{((yearlyData.educated / yearlyData.total) * 100).toFixed(1)}%
|
||||
@@ -123,11 +130,13 @@ function Page() {
|
||||
<Paper px={25} py={'lg'} bg={colors['white-1']} shadow="md">
|
||||
<Flex direction="column" gap="md">
|
||||
<IconSchoolOff size={35} color="#DA524C" />
|
||||
<Text fz="h4" fw={600}>Pengangguran Tidak Terdidik</Text>
|
||||
<Text fz="h2" fw={700} c="#DA524C">
|
||||
<Title order={3} fw={600} lh={1.2}>
|
||||
Pengangguran Tidak Terdidik
|
||||
</Title>
|
||||
<Text fz={{ base: 'lg', md: 'xl' }} fw={700} c="#DA524C" lh={1.2}>
|
||||
{yearlyData?.uneducated.toLocaleString() || 0} Orang
|
||||
</Text>
|
||||
<Text fz="sm" c="dimmed">
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed" lh={1.4}>
|
||||
{yearlyData ?
|
||||
<>
|
||||
{((yearlyData.uneducated / yearlyData.total) * 100).toFixed(1)}%
|
||||
@@ -142,13 +151,17 @@ function Page() {
|
||||
<Flex pb={30} justify={'flex-end'} gap={'xl'} align={'center'}>
|
||||
<Box>
|
||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Berpendidikan</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Pengangguran Berpendidikan
|
||||
</Text>
|
||||
<ColorSwatch color="#5082EE" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={{ base: 0, md: 5 }} align={'center'}>
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }}>Pengangguran Tak Berpendidikan</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Pengangguran Tak Berpendidikan
|
||||
</Text>
|
||||
<ColorSwatch color="#DA524C" size={30} />
|
||||
</Flex>
|
||||
</Box>
|
||||
@@ -156,15 +169,24 @@ function Page() {
|
||||
{!mounted || chartData.length === 0 ? (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={3}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
|
||||
<Text c='dimmed'>Belum ada data untuk ditampilkan dalam grafik</Text>
|
||||
<Title order={3} pb={10} lh={1.2}>
|
||||
Data Pengangguran Terdidik dan Tidak Terdidik
|
||||
</Title>
|
||||
<Text c='dimmed' fz={{ base: 'xs', md: 'sm' }} lh={1.4}>
|
||||
Belum ada data untuk ditampilkan dalam grafik
|
||||
</Text>
|
||||
</Paper>
|
||||
</Box>
|
||||
) : (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 550, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={4}>Data Pengangguran Terdidik dan Tidak Terdidik</Title>
|
||||
<Box w={{ base: '100%', md: '70%' }}>
|
||||
<Title order={3} pb={10} lh={1.2}>
|
||||
Data Pengangguran Terdidik dan Tidak Terdidik
|
||||
</Title>
|
||||
<Box
|
||||
w={{ base: '100%', md: '70%' }}
|
||||
style={{ overflowX: "auto" }}
|
||||
>
|
||||
<BarChart
|
||||
h={450}
|
||||
data={chartData}
|
||||
@@ -178,32 +200,55 @@ function Page() {
|
||||
</Paper>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
</Paper>
|
||||
<Paper p={'lg'}>
|
||||
<Text fw={'bold'} fz={'h4'}>Detail Data Pengangguran</Text>
|
||||
<Table striped highlightOnHover>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh ta={'center'}>Bulan</TableTh>
|
||||
<TableTh ta={'center'}>Total</TableTh>
|
||||
<TableTh ta={'center'}>Terdidik</TableTh>
|
||||
<TableTh ta={'center'}>Tidak Terdidik</TableTh>
|
||||
<TableTh ta={'center'}>Perubahan</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{state.findMany.data?.map((item, index) => (
|
||||
<TableTr key={item?.id ? String(item.id) : `row-${index}`}>
|
||||
<TableTd ta={'center'}>{item.month}</TableTd>
|
||||
<TableTd ta={'center'}>{item.totalUnemployment}</TableTd>
|
||||
<TableTd ta={'center'}>{item.educatedUnemployment}</TableTd>
|
||||
<TableTd ta={'center'}>{item.uneducatedUnemployment}</TableTd>
|
||||
<TableTd ta={'center'}>{item.percentageChange}%</TableTd>
|
||||
<Title order={2} fw={'bold'} fz={{ base: 'md', md: 'lg' }} lh={1.2}>
|
||||
Detail Data Pengangguran
|
||||
</Title>
|
||||
<Box style={{ overflowX: 'auto' }}>
|
||||
<Table striped highlightOnHover>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Bulan
|
||||
</TableTh>
|
||||
<TableTh ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Total
|
||||
</TableTh>
|
||||
<TableTh ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Terdidik
|
||||
</TableTh>
|
||||
<TableTh ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Tidak Terdidik
|
||||
</TableTh>
|
||||
<TableTh ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
Perubahan
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{state.findMany.data?.map((item, index) => (
|
||||
<TableTr key={item?.id ? String(item.id) : `row-${index}`}>
|
||||
<TableTd ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
{item.month}
|
||||
</TableTd>
|
||||
<TableTd ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
{item.totalUnemployment}
|
||||
</TableTd>
|
||||
<TableTd ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
{item.educatedUnemployment}
|
||||
</TableTd>
|
||||
<TableTd ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
{item.uneducatedUnemployment}
|
||||
</TableTd>
|
||||
<TableTd ta={'center'} fz={{ base: 'sm', md: 'md' }} lh={1.45}>
|
||||
{item.percentageChange}%
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Box>
|
||||
@@ -211,4 +256,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import lowonganKerjaState from '@/app/admin/(dashboard)/_state/ekonomi/lowongan-kerja';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Group, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { Box, Button, Center, Group, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack, IconBrandWhatsapp, IconBriefcase, IconCurrencyDollar, IconMapPin, IconPhone } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
@@ -33,18 +33,25 @@ function DetailLowonganKerjaUser() {
|
||||
);
|
||||
}
|
||||
|
||||
const formatRupiah = (value: number) =>
|
||||
new Intl.NumberFormat("id-ID", {
|
||||
style: "currency",
|
||||
currency: "IDR",
|
||||
minimumFractionDigits: 0,
|
||||
}).format(value);
|
||||
|
||||
return (
|
||||
<Stack bg={colors.Bg} py="xl" px={{ base: 'md', md: 100 }} align="center">
|
||||
<Box w={{ base: '100%', md: '70%' }}>
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="blue"
|
||||
leftSection={<IconArrowBack size={20} />}
|
||||
mb="md"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="blue"
|
||||
leftSection={<IconArrowBack size={20} />}
|
||||
mb="md"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
|
||||
<Paper
|
||||
radius="lg"
|
||||
@@ -54,11 +61,17 @@ function DetailLowonganKerjaUser() {
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<Stack gap="lg">
|
||||
{/* Judul */}
|
||||
<Text fz={{ base: '1.6rem', md: '2rem' }} fw={700} c={colors['blue-button']}>
|
||||
{/* Judul Posisi - H1 */}
|
||||
<Title
|
||||
order={1}
|
||||
c={colors['blue-button']}
|
||||
style={{ lineHeight: 1.15 }}
|
||||
>
|
||||
{data.posisi}
|
||||
</Text>
|
||||
<Text c="dimmed" fz="sm">
|
||||
</Title>
|
||||
|
||||
{/* Tanggal Posting - Caption */}
|
||||
<Text c="dimmed" fz={{ base: 12, md: 'sm' }} lh={1.4}>
|
||||
Diposting: {new Date(data.createdAt).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
@@ -70,44 +83,72 @@ function DetailLowonganKerjaUser() {
|
||||
<Stack gap="sm" mt="md">
|
||||
<Group gap="xs">
|
||||
<IconBriefcase size={20} color={colors['blue-button']} />
|
||||
<Text fz="md" fw={600}>{data.namaPerusahaan}</Text>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
fw={600}
|
||||
lh={1.5}
|
||||
>
|
||||
{data.namaPerusahaan}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
<IconMapPin size={20} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.lokasi}</Text>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
>
|
||||
{data.lokasi}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
<IconPhone size={20} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.notelp}</Text>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
>
|
||||
{data.notelp}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
<IconCurrencyDollar size={20} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.gaji || '-'}</Text>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
>
|
||||
{formatRupiah(Number(data.gaji)) || '-'}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
<IconBriefcase size={20} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.tipePekerjaan}</Text>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
>
|
||||
{data.tipePekerjaan}
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
{/* Deskripsi Pekerjaan - H2 */}
|
||||
<Box>
|
||||
<Text fw={600} fz="lg" mb={4}>
|
||||
<Title order={2} mb={8} style={{ lineHeight: 1.2 }}>
|
||||
Deskripsi Pekerjaan
|
||||
</Text>
|
||||
</Title>
|
||||
<Text
|
||||
fz="sm"
|
||||
fz={{ base: 'xs', md: 'sm' }}
|
||||
lh={1.6}
|
||||
style={{ wordBreak: 'break-word' }}
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Kualifikasi - H2 */}
|
||||
<Box>
|
||||
<Text fw={600} fz="lg" mb={4}>
|
||||
<Title order={2} mb={8} style={{ lineHeight: 1.2 }}>
|
||||
Kualifikasi
|
||||
</Text>
|
||||
</Title>
|
||||
<Text
|
||||
fz="sm"
|
||||
fz={{ base: 'xs', md: 'sm' }}
|
||||
lh={1.6}
|
||||
style={{ wordBreak: 'break-word' }}
|
||||
dangerouslySetInnerHTML={{ __html: data.kualifikasi || '-' }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import lowonganKerjaState from '@/app/admin/(dashboard)/_state/ekonomi/lowongan-kerja';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Flex, Group, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Button, Center, Flex, Group, Pagination, Paper, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { useDebouncedValue } from '@mantine/hooks';
|
||||
import { IconBriefcase, IconClock, IconMapPin, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -53,17 +53,19 @@ function Page() {
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }} pb={80}>
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Title order={1} ta="center" c={colors["blue-button"]} fw="bold" lh={1.15}>
|
||||
Lowongan Kerja Lokal
|
||||
</Text>
|
||||
</Title>
|
||||
<Group justify='center'>
|
||||
<TextInput
|
||||
radius={'xl'}
|
||||
w={{ base: 500, md: 700 }}
|
||||
w={{ base: '100%', md: 700 }}
|
||||
placeholder='Cari Pekerjaan'
|
||||
leftSection={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={1.5}
|
||||
/>
|
||||
</Group>
|
||||
</Box>
|
||||
@@ -80,30 +82,42 @@ function Page() {
|
||||
<Paper key={k} p={'xl'}>
|
||||
<Stack gap={'md'}>
|
||||
<Box>
|
||||
<Flex gap={'xl'} align={'center'}>
|
||||
<IconBriefcase color={colors['blue-button']} size={50} />
|
||||
<Flex gap={{ base: 'md', md: 'xl' }} align={'center'}>
|
||||
<IconBriefcase color={colors['blue-button']} size={40} />
|
||||
<Box>
|
||||
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>{v.posisi}</Text>
|
||||
<Text fz={'h4'}>{v.namaPerusahaan}</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'lg', md: 'h4' }} c={colors['blue-button']} lh={1.3}>
|
||||
{v.posisi}
|
||||
</Text>
|
||||
<Text fz={{ base: 'md', md: 'h4' }} lh={1.5}>
|
||||
{v.namaPerusahaan}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={'xl'} align={'center'}>
|
||||
<IconMapPin color={colors['blue-button']} size={50} />
|
||||
<Text fz={'h4'}>{v.lokasi}</Text>
|
||||
<Flex gap={{ base: 'md', md: 'xl' }} align={'center'}>
|
||||
<IconMapPin color={colors['blue-button']} size={40} />
|
||||
<Text fz={{ base: 'md', md: 'h4' }} lh={1.5}>
|
||||
{v.lokasi}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex gap={'xl'} align={'center'}>
|
||||
<IconClock color={colors['blue-button']} size={50} />
|
||||
<Flex gap={{ base: 'md', md: 'xl' }} align={'center'}>
|
||||
<IconClock color={colors['blue-button']} size={40} />
|
||||
<Box>
|
||||
<Text fw={'bold'} fz={'h4'} c={colors['blue-button']}>Full Time</Text>
|
||||
<Text fz={'h4'}>{formatCurrency(v.gaji)}</Text>
|
||||
<Text fw={'bold'} fz={{ base: 'md', md: 'h4' }} c={colors['blue-button']} lh={1.3}>
|
||||
Full Time
|
||||
</Text>
|
||||
<Text fz={{ base: 'sm', md: 'h4' }} lh={1.5}>
|
||||
{formatCurrency(v.gaji)}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Button onClick={() => router.push(`/darmasaba/ekonomi/lowongan-kerja-lokal/${v.id}`)}>Detail</Button>
|
||||
<Button onClick={() => router.push(`/darmasaba/ekonomi/lowongan-kerja-lokal/${v.id}`)} fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
Detail
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)
|
||||
@@ -123,4 +137,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, Text, Image, Skeleton, Group, Badge, Divider } from '@mantine/core';
|
||||
import { IconArrowBack, IconMapPin, IconPhone, IconStar } from '@tabler/icons-react';
|
||||
import { Box, Button, Paper, Stack, Text, Image, Skeleton, Group, Badge, Divider, Title } from '@mantine/core';
|
||||
import { IconArrowBack, IconBrandWhatsapp, IconMapPin, IconPhone, IconStar } from '@tabler/icons-react';
|
||||
import { useRouter, useParams } from 'next/navigation';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
@@ -31,14 +31,16 @@ function DetailProdukPasarUser() {
|
||||
<Box py={20}>
|
||||
{/* Tombol kembali */}
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Button
|
||||
variant="subtle"
|
||||
onClick={() => router.back()}
|
||||
leftSection={<IconArrowBack size={20} color={colors['blue-button']} />}
|
||||
mb={15}
|
||||
>
|
||||
Kembali ke daftar produk
|
||||
</Button>
|
||||
<Button
|
||||
variant="subtle"
|
||||
onClick={() => router.back()}
|
||||
leftSection={<IconArrowBack size={20} color={colors['blue-button']} />}
|
||||
mb={15}
|
||||
>
|
||||
<Text fz={{ base: 'md', md: 'lg' }} lh={1.5}>
|
||||
Kembali ke daftar produk
|
||||
</Text>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Paper
|
||||
@@ -65,26 +67,31 @@ function DetailProdukPasarUser() {
|
||||
<Box
|
||||
h={300}
|
||||
bg="gray.1"
|
||||
display="flex"
|
||||
style={{ alignItems: 'center', justifyContent: 'center', borderRadius: 'md' }}
|
||||
style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', borderRadius: 'var(--mantine-radius-md)' }}
|
||||
>
|
||||
<Text c="dimmed">Tidak ada gambar</Text>
|
||||
<Text c="dimmed" fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
Tidak ada gambar
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Detail Produk */}
|
||||
<Stack gap="xs">
|
||||
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
|
||||
<Title order={2} lh={1.1} c={colors['blue-button']}>
|
||||
{data.nama || 'Produk Tanpa Nama'}
|
||||
</Text>
|
||||
</Title>
|
||||
<Group>
|
||||
<Badge color="green" size="lg" radius="md">
|
||||
Rp {data.harga?.toLocaleString('id-ID')}
|
||||
<Text c={"white"} fz={{ base: 'sm', md: 'md' }} fw={600} lh={1.4}>
|
||||
Rp {data.harga?.toLocaleString('id-ID')}
|
||||
</Text>
|
||||
</Badge>
|
||||
{data.rating && (
|
||||
<Group gap={4}>
|
||||
<IconStar size={18} color="#FFD43B" />
|
||||
<Text fz="md" fw={500}>{data.rating}</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} fw={500} lh={1.5}>
|
||||
{data.rating}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
</Group>
|
||||
@@ -95,16 +102,20 @@ function DetailProdukPasarUser() {
|
||||
{/* Info Tambahan */}
|
||||
<Stack gap="sm">
|
||||
<Box>
|
||||
<Text fz="lg" fw={600}>Kategori</Text>
|
||||
<Title order={3} lh={1.15}>
|
||||
Kategori
|
||||
</Title>
|
||||
<Group gap="xs" mt={4}>
|
||||
{data.KategoriToPasar && data.KategoriToPasar.length > 0 ? (
|
||||
data.KategoriToPasar.map((kategori) => (
|
||||
<Badge key={kategori.id} color="blue" variant="light">
|
||||
<Badge key={kategori.id} color="blue" variant="light" fz={{ base: 'xs', md: 'sm' }} lh={1.4}>
|
||||
{kategori.kategori.nama}
|
||||
</Badge>
|
||||
))
|
||||
) : (
|
||||
<Text fz="sm" c="dimmed">Tidak ada kategori</Text>
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed" lh={1.5}>
|
||||
Tidak ada kategori
|
||||
</Text>
|
||||
)}
|
||||
</Group>
|
||||
</Box>
|
||||
@@ -112,14 +123,18 @@ function DetailProdukPasarUser() {
|
||||
{data.alamatUsaha && (
|
||||
<Group gap={6}>
|
||||
<IconMapPin size={18} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.alamatUsaha}</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
{data.alamatUsaha}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
|
||||
{data.kontak && (
|
||||
<Group gap={6}>
|
||||
<IconPhone size={18} color={colors['blue-button']} />
|
||||
<Text fz="md">{data.kontak}</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
{data.kontak}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
@@ -128,8 +143,10 @@ function DetailProdukPasarUser() {
|
||||
|
||||
{/* Deskripsi */}
|
||||
<Box>
|
||||
<Text fz="lg" fw={600}>Deskripsi Produk</Text>
|
||||
<Text fz="md" c="dimmed" mt={4}>
|
||||
<Title order={3} lh={1.15}>
|
||||
Deskripsi Produk
|
||||
</Title>
|
||||
<Text fz={{ base: 'sm', md: 'md' }} c="dimmed" mt={4} lh={1.5}>
|
||||
Tidak ada deskripsi.
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -144,8 +161,11 @@ function DetailProdukPasarUser() {
|
||||
component="a"
|
||||
href={`https://wa.me/${data.kontak.replace(/[^0-9]/g, '')}`}
|
||||
target="_blank"
|
||||
leftSection={<IconBrandWhatsapp/>}
|
||||
>
|
||||
Hubungi Penjual via WhatsApp
|
||||
<Text c={"white"} fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
Hubungi Penjual via WhatsApp
|
||||
</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
@@ -154,4 +174,4 @@ function DetailProdukPasarUser() {
|
||||
);
|
||||
}
|
||||
|
||||
export default DetailProdukPasarUser;
|
||||
export default DetailProdukPasarUser;
|
||||
@@ -7,7 +7,7 @@ import { IconBrandWhatsapp, IconMapPinFilled, IconSearch, IconStarFilled } from
|
||||
import { motion } from 'motion/react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
|
||||
function Page() {
|
||||
@@ -30,8 +30,8 @@ function Page() {
|
||||
|
||||
const filteredData = selectedCategory
|
||||
? data?.filter(item =>
|
||||
item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory)
|
||||
)
|
||||
item.KategoriToPasar?.some(kategori => kategori.kategoriId === selectedCategory)
|
||||
)
|
||||
: data;
|
||||
|
||||
useShallowEffect(() => {
|
||||
@@ -55,7 +55,7 @@ function Page() {
|
||||
<Box>
|
||||
<Grid align="center" px={{ base: 'md', md: 100 }}>
|
||||
<GridCol span={{ base: 12, md: 9 }}>
|
||||
<Title order={1} c={colors["blue-button"]} fw="bold">
|
||||
<Title order={1} c={colors["blue-button"]} fw="bold" lh={1.15}>
|
||||
Pasar Desa
|
||||
</Title>
|
||||
</GridCol>
|
||||
@@ -71,7 +71,14 @@ function Page() {
|
||||
</GridCol>
|
||||
</Grid>
|
||||
|
||||
<Text px={{ base: 'md', md: 100 }} pt={20} ta="justify" fz={{ base: 'sm', md: 'md' }}>
|
||||
<Text
|
||||
px={{ base: 'md', md: 100 }}
|
||||
pt={20}
|
||||
ta="justify"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.55 }}
|
||||
c="black"
|
||||
>
|
||||
Pasar Desa Online adalah media promosi untuk membantu warga memasarkan dan memperkenalkan produk mereka.
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -92,6 +99,9 @@ function Page() {
|
||||
searchable
|
||||
nothingFoundMessage="Tidak ada kategori ditemukan"
|
||||
style={{ width: '100%' }}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.55 }}
|
||||
c="black"
|
||||
/>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
@@ -114,15 +124,29 @@ function Page() {
|
||||
style={{ objectFit: 'cover' }}
|
||||
loading="lazy"
|
||||
/>
|
||||
<Text py="sm" fw="bold" fz={{ base: 'md', md: 'lg' }}>
|
||||
<Text
|
||||
py="sm"
|
||||
fw="bold"
|
||||
fz={{ base: 'md', md: 'lg' }}
|
||||
lh={{ base: 1.3, md: 1.25 }}
|
||||
c="black"
|
||||
>
|
||||
{v.nama}
|
||||
</Text>
|
||||
<Text fz={{ base: 'sm', md: 'md' }}>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.55 }}
|
||||
c="black"
|
||||
>
|
||||
Rp {v.harga.toLocaleString('id-ID')}
|
||||
</Text>
|
||||
<Flex py="sm" gap="md">
|
||||
<Flex py="sm" gap="md" align="center">
|
||||
<IconStarFilled size={20} color="#EBCB09" />
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} ml={2}>
|
||||
<Text
|
||||
fz={{ base: 'xs', md: 'sm' }}
|
||||
lh={{ base: 1.4, md: 1.45 }}
|
||||
c="black"
|
||||
>
|
||||
{v.rating}
|
||||
</Text>
|
||||
</Flex>
|
||||
@@ -130,7 +154,11 @@ function Page() {
|
||||
<Box>
|
||||
<Flex gap="md" align="center">
|
||||
<IconMapPinFilled size={20} color="red" />
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} ml={2}>
|
||||
<Text
|
||||
fz={{ base: 'xs', md: 'sm' }}
|
||||
lh={{ base: 1.4, md: 1.45 }}
|
||||
c="black"
|
||||
>
|
||||
{v.alamatUsaha}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
@@ -69,48 +69,47 @@ function Page() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||
<Stack pos="relative" bg={colors.Bg} py={{ base: 'xl', md: 'xl' }} gap={'22'}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Grid align='center'>
|
||||
<Grid align="center">
|
||||
<GridCol span={{ base: 12, md: 9 }}>
|
||||
<Title
|
||||
order={1}
|
||||
c={colors["blue-button"]}
|
||||
fw={"bold"}
|
||||
fz={{ base: '28px', md: '32px' }}
|
||||
lh={{ base: '1.2', md: '1.25' }}
|
||||
fw="bold"
|
||||
lh={{ base: 1.2, md: 1.2 }}
|
||||
>
|
||||
Program Kemiskinan
|
||||
</Title>
|
||||
</GridCol>
|
||||
<GridCol span={{ base: 12, md: 3 }}>
|
||||
<TextInput
|
||||
radius={"lg"}
|
||||
placeholder='Cari Program'
|
||||
radius="lg"
|
||||
placeholder="Cari Program"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
leftSection={<IconSearch size={20} />}
|
||||
w={{ base: "50%", md: "100%" }}
|
||||
w="100%"
|
||||
/>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
<Text
|
||||
fz={{ base: '14px', md: '16px' }}
|
||||
lh={{ base: '1.5', md: '1.6' }}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.6 }}
|
||||
c="black"
|
||||
ta={{ base: 'left', md: 'left' }}
|
||||
pt={20}
|
||||
ta="left"
|
||||
pt={{ base: 'sm', md: 20 }}
|
||||
>
|
||||
Berbagai program bantuan untuk mengurangi kemiskinan dan meningkatkan kesejahteraan masyarakat
|
||||
</Text>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<Stack gap={'lg'} justify="center">
|
||||
<SimpleGrid
|
||||
pb={10}
|
||||
pb={{ base: 'md', md: 10 }}
|
||||
cols={{
|
||||
base: 1,
|
||||
md: 2
|
||||
@@ -118,20 +117,19 @@ function Page() {
|
||||
>
|
||||
{state.findMany.data.map(v => {
|
||||
return (
|
||||
<Paper p={'xl'} key={v.id}>
|
||||
<Paper p={{ base: 'lg', md: 'xl' }} key={v.id}>
|
||||
<Title
|
||||
order={3}
|
||||
fw={'bold'}
|
||||
fw="bold"
|
||||
c={colors['blue-button']}
|
||||
fz={{ base: '18px', md: '20px' }}
|
||||
lh={{ base: '1.3', md: '1.35' }}
|
||||
lh={{ base: 1.2, md: 1.2 }}
|
||||
>
|
||||
{v.nama}
|
||||
</Title>
|
||||
<Text
|
||||
fz={{ base: '14px', md: '16px' }}
|
||||
lh={{ base: '1.5', md: '1.6' }}
|
||||
c={'black'}
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.6 }}
|
||||
c="black"
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||
/>
|
||||
@@ -139,7 +137,7 @@ function Page() {
|
||||
)
|
||||
})}
|
||||
</SimpleGrid>
|
||||
<Center my={10}>
|
||||
<Center my={{ base: 'md', md: 10 }}>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
@@ -147,16 +145,15 @@ function Page() {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
}}
|
||||
total={totalPages}
|
||||
my={"md"}
|
||||
my="md"
|
||||
/>
|
||||
</Center>
|
||||
<Paper p={'xl'}>
|
||||
<Paper p={{ base: 'lg', md: 'xl' }}>
|
||||
<Title
|
||||
order={3}
|
||||
fw={'bold'}
|
||||
fw="bold"
|
||||
c={colors['blue-button']}
|
||||
fz={{ base: '18px', md: '20px' }}
|
||||
lh={{ base: '1.3', md: '1.35' }}
|
||||
lh={{ base: 1.2, md: 1.2 }}
|
||||
mb="md"
|
||||
>
|
||||
Statistik Kemiskinan Masyarakat
|
||||
@@ -166,7 +163,7 @@ function Page() {
|
||||
<Box w="100%" style={{ overflowX: 'auto' }}>
|
||||
<Center>
|
||||
<RechartsLineChart
|
||||
width={Math.min(800, window.innerWidth - 100)}
|
||||
width={Math.min(800, typeof window !== 'undefined' ? window.innerWidth - 100 : 800)}
|
||||
height={400}
|
||||
data={statistikData}
|
||||
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||
@@ -175,10 +172,12 @@ function Page() {
|
||||
<XAxis
|
||||
dataKey="tahun"
|
||||
label={{ value: 'Tahun', position: 'insideBottomRight', offset: -5 }}
|
||||
tick={{ fontSize: 12 }}
|
||||
/>
|
||||
<YAxis
|
||||
label={{ value: 'Jumlah', angle: -90, position: 'insideLeft' }}
|
||||
domain={[0, 'auto']}
|
||||
tick={{ fontSize: 12 }}
|
||||
/>
|
||||
<Tooltip
|
||||
formatter={(value) => [`${value} orang`, 'Jumlah']}
|
||||
@@ -199,9 +198,9 @@ function Page() {
|
||||
) : (
|
||||
<Box p="md" ta="center" bg="gray.0" style={{ borderRadius: '8px' }}>
|
||||
<Text
|
||||
fz={{ base: '12px', md: '14px' }}
|
||||
fz={{ base: 'xs', md: 'sm' }}
|
||||
c="dimmed"
|
||||
lh={{ base: '1.4', md: '1.5' }}
|
||||
lh={{ base: 1.4, md: 1.4 }}
|
||||
>
|
||||
{state.findMany.loading
|
||||
? 'Memuat data statistik...'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Box, Text, Paper, Skeleton, Center } from '@mantine/core';
|
||||
import { Stack, Box, Text, Paper, Skeleton, Center, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
import { BarChart } from '@mantine/charts';
|
||||
@@ -28,16 +28,15 @@ function Page() {
|
||||
)
|
||||
}
|
||||
|
||||
// Add this check before the return statement
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap={22}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<BackButton />
|
||||
<Text fz={{ base: 'h1', md: '2.5rem' }} c={colors['blue-button']} fw="bold">
|
||||
<Title order={1} c={colors['blue-button']} fw="bold">
|
||||
Sektor Unggulan Desa Darmasaba
|
||||
</Text>
|
||||
<Text c="dimmed" mt="md">
|
||||
</Title>
|
||||
<Text c="dimmed" mt="md" fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
Data sektor unggulan belum tersedia
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -53,32 +52,49 @@ function Page() {
|
||||
Ton: item.value,
|
||||
}));
|
||||
|
||||
const chartWidth = Math.max(600, chartData.length * 150); // contoh: 150px per bar
|
||||
const chartWidth = Math.max(600, chartData.length * 150);
|
||||
|
||||
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 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }} >
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Title ta="center" order={1} c={colors['blue-button']} fw="bold">
|
||||
Sektor Unggulan Desa Darmasaba
|
||||
</Title>
|
||||
<Text
|
||||
ta="center"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.6 }}
|
||||
mt="sm"
|
||||
>
|
||||
Desa Darmasaba dikenal sebagai desa dengan potensi unggulan di sektor pertanian dan peternakan
|
||||
</Text>
|
||||
<Text ta={'center'} fz={'h4'}> Desa Darmasaba dikenal sebagai desa dengan potensi unggulan di sektor pertanian dan peternakan</Text>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'} justify='center'>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Stack gap="lg" justify="center">
|
||||
{data.map((v, k) => {
|
||||
return (
|
||||
<Paper p={'xl'} key={k}>
|
||||
<Text fw={'bold'} fz={'h4'}>{v.name}</Text>
|
||||
<Text fz={'h4'} ta={'justify'} style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: v.description || '' }} />
|
||||
<Paper p="xl" key={k}>
|
||||
<Title order={3} fw="bold">
|
||||
{v.name}
|
||||
</Title>
|
||||
<Text
|
||||
ta="justify"
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh={{ base: 1.5, md: 1.6 }}
|
||||
style={{ wordBreak: 'break-word', whiteSpace: 'normal' }}
|
||||
dangerouslySetInnerHTML={{ __html: v.description || '' }}
|
||||
/>
|
||||
</Paper>
|
||||
)
|
||||
);
|
||||
})}
|
||||
<Box style={{ width: '100%', overflowX: 'auto' }}>
|
||||
<Paper p="xl">
|
||||
<Text pb={10} fw="bold" fz="h4">Statistik Sektor Unggulan Darmasaba</Text>
|
||||
<Title order={3} fw="bold" pb="md">
|
||||
Statistik Sektor Unggulan Darmasaba
|
||||
</Title>
|
||||
<Box style={{ width: '100%', overflowX: 'auto', maxWidth: `${chartWidth}px` }}>
|
||||
<Center>
|
||||
<BarChart
|
||||
@@ -98,7 +114,7 @@ function Page() {
|
||||
yAxisLabel="Ton"
|
||||
style={{
|
||||
fontFamily: 'inherit',
|
||||
fontSize: '12px', // ukuran font lebih kecil di mobile
|
||||
fontSize: '12px',
|
||||
}}
|
||||
/>
|
||||
</Center>
|
||||
@@ -111,4 +127,4 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Page;
|
||||
@@ -0,0 +1,174 @@
|
||||
'use client';
|
||||
import stateStrukturBumDes from '@/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Box,
|
||||
Divider,
|
||||
Group,
|
||||
Image,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function DetailPegawaiBumdes() {
|
||||
const statePegawai = useProxy(stateStrukturBumDes.pegawai);
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
|
||||
useShallowEffect(() => {
|
||||
stateStrukturBumDes.posisiOrganisasi.findMany.load();
|
||||
statePegawai.findUnique.load(params?.id as string);
|
||||
}, []);
|
||||
|
||||
if (!statePegawai.findUnique.data) {
|
||||
return (
|
||||
<Stack py="lg">
|
||||
<Skeleton height={500} radius="md" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const data = statePegawai.findUnique.data;
|
||||
|
||||
return (
|
||||
<Box px={{ base: 'md', md: 100 }} py="xl">
|
||||
{/* Back button */}
|
||||
<Group mb="lg" px={{ base: 'md', md: 100 }}>
|
||||
<Box
|
||||
onClick={() => router.back()}
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<IconArrowBack size={22} color={colors['blue-button']} />
|
||||
<Text fz={{ base: 'sm', md: 'md' }} lh="1.4" fw={500} c={colors['blue-button']}>
|
||||
Kembali
|
||||
</Text>
|
||||
</Box>
|
||||
</Group>
|
||||
|
||||
<Paper
|
||||
w={{ base: '100%', md: '70%' }}
|
||||
mx="auto"
|
||||
p="xl"
|
||||
radius="lg"
|
||||
shadow="sm"
|
||||
bg="white"
|
||||
style={{ border: '1px solid #eaeaea' }}
|
||||
>
|
||||
<Stack align="center" gap="md">
|
||||
{/* Foto Profil */}
|
||||
<Image
|
||||
src={data.image?.link || '/placeholder-profile.png'}
|
||||
alt={data.namaLengkap || 'Foto Profil'}
|
||||
w={160}
|
||||
h={160}
|
||||
radius={100}
|
||||
fit="cover"
|
||||
style={{ border: `2px solid ${colors['blue-button']}` }}
|
||||
loading="lazy"
|
||||
/>
|
||||
|
||||
{/* Nama & Jabatan */}
|
||||
<Stack align="center" gap={2}>
|
||||
<Title
|
||||
order={2}
|
||||
c={colors['blue-button']}
|
||||
fw={700}
|
||||
fz={{ base: 'xl', md: '28px' }}
|
||||
lh="1.2"
|
||||
ta="center"
|
||||
>
|
||||
{data.namaLengkap || '-'} {data.gelarAkademik || ''}
|
||||
</Title>
|
||||
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh="1.4"
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
>
|
||||
{data.posisi?.nama || 'Posisi tidak tersedia'}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Divider my="lg" />
|
||||
|
||||
{/* Informasi Detail */}
|
||||
<Stack gap="md">
|
||||
<InfoRow label="Email" value={data.email} />
|
||||
<InfoRow label="Telepon" value={data.telepon} />
|
||||
<InfoRow label="Alamat" value={data.alamat} multiline />
|
||||
<InfoRow
|
||||
label="Tanggal Masuk"
|
||||
value={
|
||||
data.tanggalMasuk
|
||||
? new Date(data.tanggalMasuk).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
: '-'
|
||||
}
|
||||
/>
|
||||
<InfoRow
|
||||
label="Status"
|
||||
value={data.isActive ? 'Aktif' : 'Tidak Aktif'}
|
||||
valueColor={data.isActive ? 'green' : 'red'}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
/* Komponen Baris Informasi */
|
||||
function InfoRow({
|
||||
label,
|
||||
value,
|
||||
valueColor,
|
||||
multiline = false,
|
||||
}: {
|
||||
label: string;
|
||||
value?: string | null;
|
||||
valueColor?: string;
|
||||
multiline?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Box>
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
fw={600}
|
||||
lh="1.3"
|
||||
c="dark"
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
fz={{ base: 'sm', md: 'md' }}
|
||||
lh="1.5"
|
||||
c={valueColor || 'dimmed'}
|
||||
style={{
|
||||
whiteSpace: multiline ? 'normal' : 'nowrap',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{value || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default DetailPegawaiBumdes;
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
|
||||
import stateStrukturBumDes from '@/app/admin/(dashboard)/_state/ekonomi/struktur-organisasi/struktur-organisasi'
|
||||
import colors from '@/con/colors'
|
||||
import {
|
||||
@@ -32,12 +31,13 @@ import {
|
||||
IconZoomOut,
|
||||
} from '@tabler/icons-react'
|
||||
import { debounce } from 'lodash'
|
||||
import { useTransitionRouter } from 'next-view-transitions'
|
||||
import { OrganizationChart } from 'primereact/organizationchart'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useProxy } from 'valtio/utils'
|
||||
import BackButton from '../../desa/layanan/_com/BackButto'
|
||||
import '../../ppid/struktur-ppid/struktur.css'
|
||||
import { useMediaQuery } from '@mantine/hooks'
|
||||
import { useTransitionRouter } from 'next-view-transitions'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
@@ -49,14 +49,16 @@ export default function Page() {
|
||||
paddingBottom: 48,
|
||||
}}
|
||||
>
|
||||
<Box px={{ base: 'md', md: 100 }} py="xl">
|
||||
<Box px={{ base: 'md', md: 100 }} py={"xl"}>
|
||||
<BackButton />
|
||||
|
||||
<Stack align="center" gap="xl" mt="xl">
|
||||
<Title
|
||||
order={1}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
fz={{ base: 28, md: 36 }}
|
||||
fz={{ base: 28, md: 36, lg: 44 }}
|
||||
lh={{ base: 1.05, md: 1.03 }}
|
||||
>
|
||||
Struktur Organisasi & SK Pengurus BumDes
|
||||
</Title>
|
||||
@@ -75,14 +77,18 @@ export default function Page() {
|
||||
}
|
||||
|
||||
function StrukturOrganisasiBumDes() {
|
||||
const router = useTransitionRouter()
|
||||
const stateOrganisasi: any = useProxy(stateStrukturBumDes.pegawai)
|
||||
const router = useTransitionRouter()
|
||||
const chartContainerRef = useRef<HTMLDivElement>(null)
|
||||
const [scale, setScale] = useState(1)
|
||||
const [isFullscreen, setFullscreen] = useState(false)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
|
||||
// debounce pencarian
|
||||
const debouncedSearch = useRef(
|
||||
debounce((value: string) => setSearchQuery(value), 1000)
|
||||
debounce((value: string) => {
|
||||
setSearchQuery(value)
|
||||
}, 1000)
|
||||
).current
|
||||
|
||||
useEffect(() => {
|
||||
@@ -90,8 +96,7 @@ function StrukturOrganisasiBumDes() {
|
||||
}, [])
|
||||
|
||||
const isLoading =
|
||||
!stateOrganisasi.findMany.data &&
|
||||
stateOrganisasi.findMany.loading !== false
|
||||
!stateOrganisasi.findMany.data && stateOrganisasi.findMany.loading !== false
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -149,7 +154,7 @@ function StrukturOrganisasiBumDes() {
|
||||
)
|
||||
}
|
||||
|
||||
// 📊 susun struktur organisasi
|
||||
// 🧩 buat struktur organisasi
|
||||
const posisiMap = new Map<string, any>()
|
||||
const aktifPegawai = data.filter((p: any) => p.isActive)
|
||||
|
||||
@@ -183,7 +188,6 @@ function StrukturOrganisasiBumDes() {
|
||||
name: pegawai?.namaLengkap || 'Belum Ditugaskan',
|
||||
title: node.nama || 'Tanpa Jabatan',
|
||||
image: pegawai?.image?.link || '/img/default.png',
|
||||
description: node.deskripsi || '',
|
||||
},
|
||||
children: node.children?.map(toOrgChartFormat) || [],
|
||||
}
|
||||
@@ -208,7 +212,7 @@ function StrukturOrganisasiBumDes() {
|
||||
chartData = filterNodes(chartData)
|
||||
}
|
||||
|
||||
// 🔍 fullscreen dan zoom control
|
||||
// 🎬 fullscreen & zoom control
|
||||
const toggleFullscreen = () => {
|
||||
if (!document.fullscreenElement) {
|
||||
chartContainerRef.current?.requestFullscreen()
|
||||
@@ -225,7 +229,7 @@ function StrukturOrganisasiBumDes() {
|
||||
|
||||
return (
|
||||
<Stack align="center" mt="xl">
|
||||
{/* 🧭 Kontrol atas */}
|
||||
{/* 🔍 Controls */}
|
||||
<Paper
|
||||
shadow="xs"
|
||||
w={{
|
||||
@@ -244,6 +248,7 @@ function StrukturOrganisasiBumDes() {
|
||||
overflowX: 'auto' // ⬅️ untuk mencegah overflow
|
||||
}}
|
||||
>
|
||||
|
||||
<Stack gap="sm">
|
||||
<Group justify='center'>
|
||||
<TextInput
|
||||
@@ -360,165 +365,163 @@ function StrukturOrganisasiBumDes() {
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* 🧩 Chart Container */}
|
||||
<Center style={{ width: '100%' }}>
|
||||
<Box
|
||||
ref={chartContainerRef}
|
||||
{/* 🧩 Chart Container */}
|
||||
<Center style={{ width: '100%' }}>
|
||||
<Box
|
||||
ref={chartContainerRef}
|
||||
style={{
|
||||
overflowX: 'auto',
|
||||
overflowY: 'auto',
|
||||
width: '100%',
|
||||
maxWidth: '100%',
|
||||
padding: '32px 16px',
|
||||
transition: 'transform 0.2s ease',
|
||||
}}
|
||||
>
|
||||
<Box style={{
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: 'center top',
|
||||
display: 'inline-block', // 👈 agar tidak memenuhi lebar parent
|
||||
minWidth: 'min-content', // 👈 penting agar chart tidak dipaksa muat di width 100%
|
||||
}}>
|
||||
<OrganizationChart
|
||||
value={chartData}
|
||||
nodeTemplate={(node) => <NodeCard node={node} router={router} />}
|
||||
className="p-organizationchart p-organizationchart-horizontal"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Center>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
function NodeCard({ node, router }: any) {
|
||||
const imageSrc = node?.data?.image || '/img/default.png'
|
||||
const name = node?.data?.name || 'Tanpa Nama'
|
||||
const title = node?.data?.title || 'Tanpa Jabatan'
|
||||
const hasId = Boolean(node?.data?.id)
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
|
||||
return (
|
||||
<Transition mounted transition="pop" duration={300}>
|
||||
{(styles) => (
|
||||
<Card
|
||||
shadow="md"
|
||||
radius="xl"
|
||||
withBorder
|
||||
style={{
|
||||
...styles,
|
||||
width: '100%',
|
||||
maxWidth: isMobile ? 200 : 240, // lebih kecil di mobile
|
||||
minHeight: isMobile ? 240 : 280,
|
||||
padding: isMobile ? 16 : 20,
|
||||
background: 'linear-gradient(135deg, rgba(28,110,164,0.15) 0%, rgba(255,255,255,0.95) 100%)',
|
||||
borderColor: 'rgba(28, 110, 164, 0.3)',
|
||||
borderWidth: 2,
|
||||
transition: 'all 0.3s ease',
|
||||
cursor: hasId ? 'pointer' : 'default',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (hasId) {
|
||||
e.currentTarget.style.transform = 'translateY(-4px)'
|
||||
e.currentTarget.style.boxShadow = '0 8px 24px rgba(28, 110, 164, 0.25)'
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (hasId) {
|
||||
e.currentTarget.style.transform = 'translateY(0)'
|
||||
e.currentTarget.style.boxShadow = ''
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Stack align="center" gap={12}>
|
||||
{/* Photo */}
|
||||
<Box
|
||||
style={{
|
||||
width: 96,
|
||||
height: 96,
|
||||
borderRadius: '50%',
|
||||
overflow: 'hidden',
|
||||
border: '3px solid rgba(28, 110, 164, 0.4)',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||||
background: 'white',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={name}
|
||||
width={96}
|
||||
height={96}
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
style={{
|
||||
overflowX: 'auto',
|
||||
overflowY: 'auto',
|
||||
width: '100%',
|
||||
maxWidth: '100%',
|
||||
padding: '32px 16px',
|
||||
transition: 'transform 0.2s ease',
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Name */}
|
||||
<Text
|
||||
fw={700}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
lineClamp={2}
|
||||
fz={{ base: 13, md: 15 }}
|
||||
lh={1.2}
|
||||
style={{
|
||||
minHeight: 40,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
|
||||
{/* Title/Position */}
|
||||
<Text
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
fw={500}
|
||||
lineClamp={2}
|
||||
fz={{ base: 12, md: 13 }}
|
||||
lh={1.3}
|
||||
style={{
|
||||
minHeight: 32,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
{/* Detail Button */}
|
||||
{hasId && (
|
||||
<Button
|
||||
variant="gradient"
|
||||
gradient={{ from: 'blue', to: 'cyan' }}
|
||||
size="xs"
|
||||
fullWidth
|
||||
mt={8}
|
||||
radius="md"
|
||||
onClick={() =>
|
||||
router.push(`/darmasaba/ekonomi/struktur-organisasi-dan-sk-pengurus-bumdesa/${node.data.id}`)
|
||||
}
|
||||
style={{
|
||||
height: 32,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<Box style={{
|
||||
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: 'center top',
|
||||
display: 'inline-block', // 👈 agar tidak memenuhi lebar parent
|
||||
minWidth: 'min-content', // 👈 penting agar chart tidak dipaksa muat di width 100%
|
||||
}}>
|
||||
<OrganizationChart
|
||||
value={chartData}
|
||||
nodeTemplate={(node) => <NodeCard node={node} router={router} />}
|
||||
className="p-organizationchart p-organizationchart-horizontal"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Center>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
function NodeCard({ node, router }: any) {
|
||||
const imageSrc = node?.data?.image || '/img/default.png'
|
||||
const name = node?.data?.name || 'Tanpa Nama'
|
||||
const title = node?.data?.title || 'Tanpa Jabatan'
|
||||
const hasId = Boolean(node?.data?.id)
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
|
||||
return (
|
||||
<Transition mounted transition="pop" duration={300}>
|
||||
{(styles) => (
|
||||
<Card
|
||||
shadow="md"
|
||||
radius="xl"
|
||||
withBorder
|
||||
|
||||
style={{
|
||||
...styles,
|
||||
width: '100%',
|
||||
maxWidth: isMobile ? 200 : 240, // lebih kecil di mobile
|
||||
minHeight: isMobile ? 240 : 280,
|
||||
padding: isMobile ? 16 : 20,
|
||||
background: 'linear-gradient(135deg, rgba(28,110,164,0.15) 0%, rgba(255,255,255,0.95) 100%)',
|
||||
borderColor: 'rgba(28, 110, 164, 0.3)',
|
||||
borderWidth: 2,
|
||||
transition: 'all 0.3s ease',
|
||||
cursor: hasId ? 'pointer' : 'default',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (hasId) {
|
||||
e.currentTarget.style.transform = 'translateY(-4px)'
|
||||
e.currentTarget.style.boxShadow = '0 8px 24px rgba(28, 110, 164, 0.25)'
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (hasId) {
|
||||
e.currentTarget.style.transform = 'translateY(0)'
|
||||
e.currentTarget.style.boxShadow = ''
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Stack align="center" gap={12}>
|
||||
{/* Photo */}
|
||||
<Box
|
||||
style={{
|
||||
width: 96,
|
||||
height: 96,
|
||||
borderRadius: '50%',
|
||||
overflow: 'hidden',
|
||||
border: '3px solid rgba(28, 110, 164, 0.4)',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||||
background: 'white',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={name}
|
||||
width={96}
|
||||
height={96}
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
style={{
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Name */}
|
||||
<Text
|
||||
fw={700}
|
||||
ta="center"
|
||||
c={colors['blue-button']}
|
||||
lineClamp={2}
|
||||
fz={{ base: 13, md: 15 }}
|
||||
lh={1.2}
|
||||
style={{
|
||||
minHeight: 40,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
|
||||
{/* Title/Position */}
|
||||
<Text
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
fw={500}
|
||||
lineClamp={2}
|
||||
fz={{ base: 12, md: 13 }}
|
||||
lh={1.3}
|
||||
style={{
|
||||
minHeight: 32,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
{/* Detail Button */}
|
||||
{hasId && (
|
||||
<Button
|
||||
variant="gradient"
|
||||
gradient={{ from: 'blue', to: 'cyan' }}
|
||||
size="xs"
|
||||
fullWidth
|
||||
mt={8}
|
||||
radius="md"
|
||||
onClick={() =>
|
||||
router.push(`/darmasaba/ppid/struktur-ppid/${node.data.id}`)
|
||||
}
|
||||
style={{
|
||||
height: 32,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<Text fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Card>
|
||||
<Text c={"white"} fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
</Stack>
|
||||
</Card>
|
||||
)}
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box } from '@mantine/core';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import React, { Suspense } from 'react';
|
||||
import LayoutTabs from './_lib/layoutTabs';
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const segments = pathname.split('/').filter(Boolean);
|
||||
const isDetailPage = segments.length === 5; // [darmasaba, desa, berita, kategori, id]
|
||||
|
||||
if (isDetailPage) {
|
||||
// Tampilkan tanpa tab menu
|
||||
return (
|
||||
<Box bg={colors.Bg}>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<LayoutTabs>
|
||||
|
||||
@@ -517,7 +517,7 @@ function NodeCard({ node, router }: any) {
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
<Text fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||
<Text c={"white"} fz={{ base: 12, md: 13 }} lh={1} ta="center">Lihat Detail</Text>
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user