Admin Fix Chart Bar PerMonth Submenu IKM, Menu PPID
This commit is contained in:
@@ -117,8 +117,48 @@ const responden = proxy({
|
|||||||
id: "",
|
id: "",
|
||||||
form: { ...defaultFormResponden },
|
form: { ...defaultFormResponden },
|
||||||
loading: false,
|
loading: false,
|
||||||
async byId() {
|
async load(id: string) {
|
||||||
// Method implementation if needed
|
if (!id) {
|
||||||
|
toast.warn("ID tidak valid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
responden.update.loading = true;
|
||||||
|
|
||||||
|
const response = await fetch(`/api/landingpage/responden/${id}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
if (result?.success) {
|
||||||
|
const data = result.data;
|
||||||
|
this.id = data.id;
|
||||||
|
this.form = {
|
||||||
|
name: data.name,
|
||||||
|
tanggal: data.tanggal,
|
||||||
|
jenisKelaminId: data.jenisKelaminId,
|
||||||
|
ratingId: data.ratingId,
|
||||||
|
kelompokUmurId: data.kelompokUmurId,
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw new Error(result?.message || "Gagal memuat data");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading responden:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
responden.update.loading = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async submit() {
|
async submit() {
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* 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 { PieChart } from '@mantine/charts'; // ✅ Ganti recharts dengan Mantine
|
import { PieChart, BarChart } from '@mantine/charts'; // ✅ Ganti recharts dengan Mantine
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Center,
|
Center,
|
||||||
@@ -25,12 +25,15 @@ interface ChartDataItem {
|
|||||||
label?: string;
|
label?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(indeksKepuasanState.responden);
|
const state = useProxy(indeksKepuasanState.responden);
|
||||||
const { data, loading } = state.findMany;
|
const { data, loading } = state.findMany;
|
||||||
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
const [donutDataJenisKelamin, setDonutDataJenisKelamin] = useState<ChartDataItem[]>([]);
|
||||||
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
const [donutDataRating, setDonutDataRating] = useState<ChartDataItem[]>([]);
|
||||||
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
const [donutDataKelompokUmur, setDonutDataKelompokUmur] = useState<ChartDataItem[]>([]);
|
||||||
|
const [barChartData, setBarChartData] = useState<Array<{ month: string; count: number }>>([]);
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@@ -69,6 +72,41 @@ function Page() {
|
|||||||
{ name: 'Dewasa', value: totalDewasa, color: '#10A85AFF' },
|
{ name: 'Dewasa', value: totalDewasa, color: '#10A85AFF' },
|
||||||
{ name: 'Lansia', value: totalLansia, color: '#FFA500' },
|
{ name: 'Lansia', value: totalLansia, color: '#FFA500' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Process data for bar chart (group by month)
|
||||||
|
const monthYearMap = new Map<string, number>();
|
||||||
|
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
// Try both createdAt and tanggal fields
|
||||||
|
const dateValue = item.tanggal || item.createdAt;
|
||||||
|
if (!dateValue) return;
|
||||||
|
|
||||||
|
const parsedDate = new Date(dateValue);
|
||||||
|
if (isNaN(parsedDate.getTime())) return;
|
||||||
|
|
||||||
|
const month = parsedDate.getMonth() + 1;
|
||||||
|
const year = parsedDate.getFullYear();
|
||||||
|
const monthYearKey = `${year}-${String(month).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
monthYearMap.set(monthYearKey, (monthYearMap.get(monthYearKey) || 0) + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert map to array and sort by date
|
||||||
|
const barData = Array.from(monthYearMap.entries())
|
||||||
|
.map(([key, count]) => {
|
||||||
|
const [year, month] = key.split('-');
|
||||||
|
const monthName = new Date(Number(year), Number(month) - 1, 1)
|
||||||
|
.toLocaleString('id-ID', { month: 'long' });
|
||||||
|
return {
|
||||||
|
month: `${monthName} ${year}`,
|
||||||
|
count,
|
||||||
|
sortKey: parseInt(`${year}${String(month).padStart(2, '0')}`, 10)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.sortKey - b.sortKey)
|
||||||
|
.map(({ month, count }) => ({ month, count }));
|
||||||
|
|
||||||
|
setBarChartData(barData);
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
@@ -92,105 +130,120 @@ function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
|
{/* Bar Chart - Data per Tanggal */}
|
||||||
|
<Paper bg={colors['white-1']} p="md" radius="md" mb="md">
|
||||||
|
<Title order={4} mb="md" ta="center">Jumlah Responden per Bulan</Title>
|
||||||
|
<Box h={300}>
|
||||||
|
<BarChart
|
||||||
|
h={300}
|
||||||
|
data={barChartData}
|
||||||
|
dataKey="month"
|
||||||
|
series={[{ name: 'count', color: colors['blue-button'] }]}
|
||||||
|
tickLine="y"
|
||||||
|
xAxisLabel="Bulan"
|
||||||
|
yAxisLabel="Jumlah Responden"
|
||||||
|
withTooltip
|
||||||
|
tooltipAnimationDuration={200}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
<SimpleGrid cols={{ base: 1, md: 3 }}>
|
||||||
{/* Chart Jenis Kelamin */}
|
{/* Chart Jenis Kelamin */}
|
||||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={4}>Jenis Kelamin</Title>
|
<Title order={4}>Jenis Kelamin</Title>
|
||||||
{donutDataJenisKelamin.every(item => item.value === 0) ? (
|
{donutDataJenisKelamin.every(item => item.value === 0) ? (
|
||||||
<Text c="dimmed" ta="center" my="md">
|
<Text c="dimmed" ta="center" my="md">
|
||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Box>
|
<Box>
|
||||||
<Center>
|
<Center>
|
||||||
<PieChart
|
<PieChart
|
||||||
withLabels
|
withLabels
|
||||||
withTooltip
|
withTooltip
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
size={250}
|
size={250}
|
||||||
data={donutDataJenisKelamin}
|
data={donutDataJenisKelamin}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Stack gap="sm" mt="md">
|
<Stack gap="sm" mt="md">
|
||||||
{donutDataJenisKelamin.map((entry) => (
|
{donutDataJenisKelamin.map((entry) => (
|
||||||
<Flex key={entry.name} gap="md" align="center">
|
<Flex key={entry.name} gap="md" align="center">
|
||||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Chart Rating */}
|
{/* Chart Rating */}
|
||||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={4}>Pilihan</Title>
|
<Title order={4}>Pilihan</Title>
|
||||||
{donutDataRating.every(item => item.value === 0) ? (
|
{donutDataRating.every(item => item.value === 0) ? (
|
||||||
<Text c="dimmed" ta="center" my="md">
|
<Text c="dimmed" ta="center" my="md">
|
||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Box>
|
<Box>
|
||||||
<Center>
|
<Center>
|
||||||
<PieChart
|
<PieChart
|
||||||
withLabels
|
withLabels
|
||||||
withTooltip
|
withTooltip
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
size={250}
|
size={250}
|
||||||
data={donutDataRating}
|
data={donutDataRating}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Stack gap="sm" mt="md">
|
<Stack gap="sm" mt="md">
|
||||||
{donutDataRating.map((entry) => (
|
{donutDataRating.map((entry) => (
|
||||||
<Flex key={entry.name} gap="md" align="center">
|
<Flex key={entry.name} gap="md" align="center">
|
||||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Chart Kelompok Umur */}
|
{/* Chart Kelompok Umur */}
|
||||||
<Paper bg={colors['white-1']} p="md" radius="md">
|
<Paper bg={colors['white-1']} p="md" radius="md">
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={4}>Umur</Title>
|
<Title order={4}>Umur</Title>
|
||||||
{donutDataKelompokUmur.every(item => item.value === 0) ? (
|
{donutDataKelompokUmur.every(item => item.value === 0) ? (
|
||||||
<Text c="dimmed" ta="center" my="md">
|
<Text c="dimmed" ta="center" my="md">
|
||||||
Belum ada data untuk ditampilkan dalam grafik
|
Belum ada data untuk ditampilkan dalam grafik
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Box>
|
<Box>
|
||||||
<Center>
|
<Center>
|
||||||
<PieChart
|
<PieChart
|
||||||
withLabels
|
withLabels
|
||||||
withTooltip
|
withTooltip
|
||||||
labelsType="percent"
|
labelsType="percent"
|
||||||
size={250}
|
size={250}
|
||||||
data={donutDataKelompokUmur}
|
data={donutDataKelompokUmur}
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
<Stack gap="sm" mt="md">
|
<Stack gap="sm" mt="md">
|
||||||
{donutDataKelompokUmur.map((entry) => (
|
{donutDataKelompokUmur.map((entry) => (
|
||||||
<Flex key={entry.name} gap="md" align="center">
|
<Flex key={entry.name} gap="md" align="center">
|
||||||
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
<Box bg={entry.color} w={20} h={20} style={{ flexShrink: 0 }} />
|
||||||
<Text size="sm">{entry.name}: {entry.value}</Text>
|
<Text size="sm">{entry.name}: {entry.value}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,35 +1,78 @@
|
|||||||
'use client'
|
'use client'
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useRouter, useParams } from 'next/navigation';
|
import { useRouter, useParams } from 'next/navigation';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Paper, Stack, Title, TextInput, Text, Select } from '@mantine/core';
|
import { Box, Button, Paper, Stack, Title, TextInput, Text, Select } from '@mantine/core';
|
||||||
import { IconArrowBack } from '@tabler/icons-react';
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
interface FormResponden {
|
||||||
|
name: string;
|
||||||
|
tanggal: string;
|
||||||
|
jenisKelaminId: string;
|
||||||
|
ratingId: string;
|
||||||
|
kelompokUmurId: string;
|
||||||
|
}
|
||||||
|
|
||||||
function EditResponden() {
|
function EditResponden() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const params = useParams() as { id: string }
|
const params = useParams() as { id: string }
|
||||||
const state = useProxy(indeksKepuasanState.responden)
|
const state = useProxy(indeksKepuasanState.responden)
|
||||||
const id = params.id
|
const id = params.id
|
||||||
|
const [formData, setFormData] = useState<FormResponden>({
|
||||||
|
name: '',
|
||||||
|
tanggal: '',
|
||||||
|
jenisKelaminId: '',
|
||||||
|
ratingId: '',
|
||||||
|
kelompokUmurId: '',
|
||||||
|
})
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
indeksKepuasanState.jenisKelaminResponden.findMany.load();
|
||||||
state.findUnique.load(id).then(() => {
|
indeksKepuasanState.pilihanRatingResponden.findMany.load();
|
||||||
const data = state.findUnique.data
|
indeksKepuasanState.kelompokUmurResponden.findMany.load();
|
||||||
|
|
||||||
|
const loadResponden = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await state.update.load(id);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
const formattedDate = data.tanggal && !isNaN(new Date(data.tanggal).getTime())
|
||||||
|
? new Date(data.tanggal).toISOString().split('T')[0]
|
||||||
|
: '';
|
||||||
|
// ⬇️ FIX PENTING: tambahkan ini
|
||||||
|
state.update.id = id;
|
||||||
|
|
||||||
state.update.form = {
|
state.update.form = {
|
||||||
name: data.name || '',
|
name: data.name,
|
||||||
tanggal: data.tanggal ? new Date(data.tanggal).toISOString() : new Date().toISOString(),
|
tanggal: formattedDate,
|
||||||
jenisKelaminId: data.jenisKelaminId || '',
|
jenisKelaminId: data.jenisKelaminId,
|
||||||
ratingId: data.ratingId || '',
|
ratingId: data.ratingId,
|
||||||
kelompokUmurId: data.kelompokUmurId || '',
|
kelompokUmurId: data.kelompokUmurId,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
setFormData({
|
||||||
|
name: data.name,
|
||||||
|
tanggal: data.tanggal,
|
||||||
|
jenisKelaminId: data.jenisKelaminId,
|
||||||
|
ratingId: data.ratingId,
|
||||||
|
kelompokUmurId: data.kelompokUmurId,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
} catch (error) {
|
||||||
|
console.error("Error loading program penghijauan:", error);
|
||||||
|
toast.error("Gagal memuat data program penghijauan");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [id])
|
|
||||||
|
loadResponden();
|
||||||
|
}, [params?.id]);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
state.update.id = id;
|
state.update.id = id;
|
||||||
@@ -51,74 +94,84 @@ function EditResponden() {
|
|||||||
label="Nama"
|
label="Nama"
|
||||||
type='text'
|
type='text'
|
||||||
placeholder="masukkan nama"
|
placeholder="masukkan nama"
|
||||||
value={state.update.form.name}
|
value={formData.name}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
state.update.form.name = val.currentTarget.value;
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
name: val.currentTarget.value
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Tanggal"
|
|
||||||
type="date"
|
type="date"
|
||||||
placeholder="masukkan tanggal"
|
value={formData.tanggal}
|
||||||
value={state.update.form.tanggal}
|
onChange={(e) => {
|
||||||
onChange={(val) => {
|
setFormData({
|
||||||
state.update.form.tanggal = val.currentTarget.value;
|
...formData,
|
||||||
|
tanggal: e.currentTarget.value, // ✅ sudah format YYYY-MM-DD
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
value={state.update.form.jenisKelaminId}
|
key={"jenisKelamin"}
|
||||||
onChange={(val) => {
|
label={<Text fw="bold" fz="sm">Jenis Kelamin</Text>}
|
||||||
state.update.form.jenisKelaminId = val || "";
|
placeholder="Pilih jenis kelamin"
|
||||||
}}
|
value={formData.jenisKelaminId}
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Jenis Kelamin</Text>}
|
onChange={(val) => setFormData({ ...formData, jenisKelaminId: val || "" })}
|
||||||
placeholder='Pilih jenis kelamin'
|
|
||||||
data={
|
data={
|
||||||
indeksKepuasanState.jenisKelaminResponden.findMany.data?.map((v) => ({
|
(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||||
value: v.id,
|
.filter(Boolean) // Hapus null/undefined
|
||||||
label: v.nama
|
.map((v) => ({
|
||||||
})) || []
|
value: v.id || '',
|
||||||
|
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading} // ✅ disable saat loading
|
||||||
clearable
|
clearable
|
||||||
searchable
|
searchable
|
||||||
required
|
required
|
||||||
error={!state.update.form.jenisKelaminId ? "Pilih jenis kelamin" : undefined}
|
error={!formData.jenisKelaminId ? "Pilih jenis kelamin" : undefined}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
value={state.update.form.ratingId}
|
key={"rating"}
|
||||||
onChange={(val) => {
|
value={formData.ratingId}
|
||||||
state.update.form.ratingId = val || "";
|
onChange={(val) => setFormData({ ...formData, ratingId: val || "" })}
|
||||||
}}
|
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Rating</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Rating</Text>}
|
||||||
placeholder='Pilih rating'
|
placeholder='Pilih rating'
|
||||||
data={
|
data={
|
||||||
indeksKepuasanState.pilihanRatingResponden.findMany.data?.map((v) => ({
|
(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||||
value: v.id,
|
.filter(Boolean)
|
||||||
label: v.nama
|
.map((v) => ({
|
||||||
})) || []
|
value: v.id || '',
|
||||||
|
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||||
clearable
|
clearable
|
||||||
searchable
|
searchable
|
||||||
required
|
required
|
||||||
error={!state.update.form.ratingId ? "Pilih rating" : undefined}
|
error={!formData.ratingId ? "Pilih rating" : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
value={state.update.form.kelompokUmurId}
|
key={"kelompokUmur"}
|
||||||
onChange={(val) => {
|
value={formData.kelompokUmurId}
|
||||||
state.update.form.kelompokUmurId = val || "";
|
onChange={(val) => setFormData({ ...formData, kelompokUmurId: val || "" })}
|
||||||
}}
|
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Kelompok Umur</Text>}
|
label={<Text fw={"bold"} fz={"sm"}>Kelompok Umur</Text>}
|
||||||
placeholder='Pilih kelompok umur'
|
placeholder='Pilih kelompok umur'
|
||||||
data={
|
data={
|
||||||
indeksKepuasanState.kelompokUmurResponden.findMany.data?.map((v) => ({
|
(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||||
value: v.id,
|
.filter(Boolean)
|
||||||
label: v.nama
|
.map((v) => ({
|
||||||
})) || []
|
value: v.id || '',
|
||||||
|
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama'
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||||
clearable
|
clearable
|
||||||
searchable
|
searchable
|
||||||
required
|
required
|
||||||
error={!state.update.form.kelompokUmurId ? "Pilih kelompok umur" : undefined}
|
error={!formData.kelompokUmurId ? "Pilih kelompok umur" : undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
import { ModalKonfirmasiHapus } from "@/app/admin/(dashboard)/_com/modalKonfirmasiHapus"
|
import { ModalKonfirmasiHapus } from "@/app/admin/(dashboard)/_com/modalKonfirmasiHapus"
|
||||||
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan"
|
import indeksKepuasanState from "@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan"
|
||||||
import colors from "@/con/colors"
|
import colors from "@/con/colors"
|
||||||
import { Box, Button, Paper, Skeleton, Stack, Text } from "@mantine/core"
|
import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from "@mantine/core"
|
||||||
import { useShallowEffect } from "@mantine/hooks"
|
import { useShallowEffect } from "@mantine/hooks"
|
||||||
import { IconArrowBack } from "@tabler/icons-react"
|
import { IconArrowBack, IconEdit, IconX } from "@tabler/icons-react"
|
||||||
import { useRouter, useParams } from "next/navigation"
|
import { useRouter, useParams } from "next/navigation"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useProxy } from "valtio/utils"
|
import { useProxy } from "valtio/utils"
|
||||||
|
|
||||||
export default function DetailResponden(){
|
export default function DetailResponden() {
|
||||||
const [modalHapus, setModalHapus] = useState(false)
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
const stateDetail = useProxy(indeksKepuasanState.responden)
|
const stateDetail = useProxy(indeksKepuasanState.responden)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -30,17 +30,17 @@ export default function DetailResponden(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!stateDetail.findUnique.data){
|
if (!stateDetail.findUnique.data) {
|
||||||
return(
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Skeleton h={500} />
|
<Skeleton h={500} />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return(
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box mb={10}>
|
<Box mb={10}>
|
||||||
<Button variant="subtle" onClick={() => router.back()}>
|
<Button variant="subtle" onClick={() => router.back()}>
|
||||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -57,9 +57,9 @@ export default function DetailResponden(){
|
|||||||
<Box>
|
<Box>
|
||||||
<Text fz={"lg"} fw={"bold"}>Tanggal</Text>
|
<Text fz={"lg"} fw={"bold"}>Tanggal</Text>
|
||||||
<Text fz={"lg"}>{
|
<Text fz={"lg"}>{
|
||||||
stateDetail.findUnique.data?.tanggal
|
stateDetail.findUnique.data?.tanggal
|
||||||
? new Date(stateDetail.findUnique.data.tanggal).toLocaleDateString('id-ID')
|
? new Date(stateDetail.findUnique.data.tanggal).toLocaleDateString('id-ID')
|
||||||
: '-'
|
: '-'
|
||||||
}</Text>
|
}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -74,6 +74,31 @@ export default function DetailResponden(){
|
|||||||
<Text fz={"lg"} fw={"bold"}>Kelompok Umur</Text>
|
<Text fz={"lg"} fw={"bold"}>Kelompok Umur</Text>
|
||||||
<Text fz={"lg"}>{stateDetail.findUnique.data?.kelompokUmur?.name}</Text>
|
<Text fz={"lg"}>{stateDetail.findUnique.data?.kelompokUmur?.name}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Flex gap={"xs"} mt={10}>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (stateDetail.findUnique.data) {
|
||||||
|
setSelectedId(stateDetail.findUnique.data.id);
|
||||||
|
setModalHapus(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={stateDetail.delete.loading || !stateDetail.findUnique.data}
|
||||||
|
color={"red"}
|
||||||
|
>
|
||||||
|
<IconX size={20} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (stateDetail.findUnique.data) {
|
||||||
|
router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${stateDetail.findUnique.data.id}/edit`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={!stateDetail.findUnique.data}
|
||||||
|
color={"green"}
|
||||||
|
>
|
||||||
|
<IconEdit size={20} />
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -85,7 +110,7 @@ export default function DetailResponden(){
|
|||||||
onClose={() => setModalHapus(false)}
|
onClose={() => setModalHapus(false)}
|
||||||
onConfirm={handleHapus}
|
onConfirm={handleHapus}
|
||||||
text="Apakah anda yakin ingin menghapus responden ini?"
|
text="Apakah anda yakin ingin menghapus responden ini?"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user