Fix All Search Admin
This commit is contained in:
@@ -1,11 +1,23 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
'use client'
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
'use client';
|
||||
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, Select, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { IconArrowBack, IconDeviceFloppy } from '@tabler/icons-react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Group,
|
||||
Loader,
|
||||
Paper,
|
||||
Select,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { ChangeEvent, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
@@ -20,9 +32,13 @@ interface FormResponden {
|
||||
function EditResponden() {
|
||||
const router = useRouter();
|
||||
const params = useParams() as { id: string };
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const id = params.id;
|
||||
|
||||
// ✅ proxy asli untuk mutasi
|
||||
const state = indeksKepuasanState.responden;
|
||||
// ✅ snapshot untuk re-render (read-only)
|
||||
const snapshot = useProxy(indeksKepuasanState.responden);
|
||||
|
||||
const [formData, setFormData] = useState<FormResponden>({
|
||||
name: '',
|
||||
tanggal: '',
|
||||
@@ -31,59 +47,107 @@ function EditResponden() {
|
||||
kelompokUmurId: '',
|
||||
});
|
||||
|
||||
// Helper untuk membuat data Select dari state
|
||||
const mapSelectData = (data: any[] | null | undefined) =>
|
||||
(data || [])
|
||||
.filter(Boolean)
|
||||
.map((v: any) => ({
|
||||
value: v.id || '',
|
||||
label: typeof v.name === 'string' ? v.name : 'Tanpa Nama',
|
||||
}));
|
||||
const [originalData, setOriginalData] = useState<FormResponden>({
|
||||
name: '',
|
||||
tanggal: '',
|
||||
jenisKelaminId: '',
|
||||
ratingId: '',
|
||||
kelompokUmurId: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// Load opsi dropdown
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
// 🔹 Load data pilihan select
|
||||
const loadSelectOptions = useCallback(() => {
|
||||
indeksKepuasanState.jenisKelaminResponden.findMany.load();
|
||||
indeksKepuasanState.pilihanRatingResponden.findMany.load();
|
||||
indeksKepuasanState.kelompokUmurResponden.findMany.load();
|
||||
}, []);
|
||||
|
||||
const loadResponden = async () => {
|
||||
if (!id) return;
|
||||
// 🔹 Load data responden by ID
|
||||
const loadResponden = useCallback(async () => {
|
||||
if (!id) return;
|
||||
try {
|
||||
const data = await state.update.load(id);
|
||||
if (!data) return;
|
||||
|
||||
try {
|
||||
const data = await state.update.load(id);
|
||||
if (data) {
|
||||
state.update.id = id;
|
||||
const newForm = {
|
||||
name: data.name || '',
|
||||
tanggal: data.tanggal || '',
|
||||
jenisKelaminId: data.jenisKelaminId || '',
|
||||
ratingId: data.ratingId || '',
|
||||
kelompokUmurId: data.kelompokUmurId || '',
|
||||
};
|
||||
|
||||
// **formData lokal tetap controlled**, tidak overwrite tiap render
|
||||
setFormData({
|
||||
name: data.name || '',
|
||||
tanggal: data.tanggal || '',
|
||||
jenisKelaminId: data.jenisKelaminId || '',
|
||||
ratingId: data.ratingId || '',
|
||||
kelompokUmurId: data.kelompokUmurId || '',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading responden:", error);
|
||||
toast.error("Gagal memuat data responden");
|
||||
}
|
||||
};
|
||||
setFormData(newForm);
|
||||
setOriginalData(newForm);
|
||||
} catch (error) {
|
||||
console.error('Error loading responden:', error);
|
||||
toast.error('Gagal memuat data responden');
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
loadSelectOptions();
|
||||
loadResponden();
|
||||
}, [id, state.update]);
|
||||
|
||||
const handleChange = (field: keyof FormResponden) => (e: ChangeEvent<HTMLInputElement> | string | null) => {
|
||||
const value = typeof e === 'string' || e === null ? e || '' : e.currentTarget.value;
|
||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
}, [loadSelectOptions, loadResponden]);
|
||||
|
||||
// 🔹 Submit data
|
||||
const handleSubmit = async () => {
|
||||
state.update.id = id;
|
||||
state.update.form = { ...formData }; // hanya update global state saat submit
|
||||
await state.update.submit();
|
||||
router.push('/admin/ppid/ikm-desa-darmasaba/responden');
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
state.update.id = id;
|
||||
state.update.form = { ...formData }; // mutasi proxy asli ✅
|
||||
await state.update.submit();
|
||||
toast.success('Responden berhasil diperbarui!');
|
||||
router.push('/admin/ppid/indeks-kepuasan-masyarakat/responden');
|
||||
} catch (error) {
|
||||
console.error('Error updating responden:', error);
|
||||
toast.error('Gagal memperbarui responden');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 🔹 Reset form ke data awal
|
||||
const handleResetForm = () => {
|
||||
setFormData({ ...originalData });
|
||||
toast.info('Form dikembalikan ke data awal');
|
||||
};
|
||||
|
||||
// 🔹 Reusable Select component
|
||||
const ControlledSelect = ({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
error,
|
||||
placeholder = 'Pilih',
|
||||
loading = false,
|
||||
}: {
|
||||
label: string;
|
||||
value: string;
|
||||
onChange: (val: string) => void;
|
||||
options: { value: string; label: string }[];
|
||||
error?: string;
|
||||
placeholder?: string;
|
||||
loading?: boolean;
|
||||
}) => (
|
||||
<Select
|
||||
label={<Text fw="bold" fz="sm" mb={4}>{label}</Text>}
|
||||
value={value}
|
||||
onChange={(val) => onChange(val || '')}
|
||||
data={options}
|
||||
placeholder={placeholder}
|
||||
disabled={loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
radius="md"
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box px={{ base: 0, md: 'lg' }} py="xs">
|
||||
<Group mb="md">
|
||||
@@ -108,72 +172,72 @@ function EditResponden() {
|
||||
label="Nama Responden"
|
||||
placeholder="Masukkan nama responden"
|
||||
value={formData.name}
|
||||
onChange={handleChange('name')}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.currentTarget.value })}
|
||||
radius="md"
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Tanggal"
|
||||
type="date"
|
||||
value={formData.tanggal ? new Date(formData.tanggal).toISOString().split('T')[0] : ''}
|
||||
onChange={handleChange('tanggal')}
|
||||
onChange={(e) => setFormData({ ...formData, tanggal: e.currentTarget.value })}
|
||||
radius="md"
|
||||
required
|
||||
/>
|
||||
|
||||
<Select
|
||||
<ControlledSelect
|
||||
label="Jenis Kelamin"
|
||||
placeholder="Pilih jenis kelamin"
|
||||
value={formData.jenisKelaminId}
|
||||
onChange={handleChange('jenisKelaminId')}
|
||||
data={mapSelectData(indeksKepuasanState.jenisKelaminResponden.findMany.data)}
|
||||
disabled={indeksKepuasanState.jenisKelaminResponden.findMany.loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
radius="md"
|
||||
error={!formData.jenisKelaminId ? "Pilih jenis kelamin" : undefined}
|
||||
onChange={(val) => setFormData({ ...formData, jenisKelaminId: val })}
|
||||
options={(indeksKepuasanState.jenisKelaminResponden.findMany.data || [])
|
||||
.map((v) => ({ value: v.id || '', label: v.name || 'Tanpa Nama' }))}
|
||||
loading={indeksKepuasanState.jenisKelaminResponden.findMany.loading}
|
||||
error={!formData.jenisKelaminId ? 'Pilih jenis kelamin' : undefined}
|
||||
/>
|
||||
|
||||
<Select
|
||||
<ControlledSelect
|
||||
label="Rating"
|
||||
placeholder="Pilih rating"
|
||||
value={formData.ratingId}
|
||||
onChange={handleChange('ratingId')}
|
||||
data={mapSelectData(indeksKepuasanState.pilihanRatingResponden.findMany.data)}
|
||||
disabled={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
radius="md"
|
||||
error={!formData.ratingId ? "Pilih rating" : undefined}
|
||||
onChange={(val) => setFormData({ ...formData, ratingId: val })}
|
||||
options={(indeksKepuasanState.pilihanRatingResponden.findMany.data || [])
|
||||
.map((v) => ({ value: v.id || '', label: v.name || 'Tanpa Nama' }))}
|
||||
loading={indeksKepuasanState.pilihanRatingResponden.findMany.loading}
|
||||
error={!formData.ratingId ? 'Pilih rating' : undefined}
|
||||
/>
|
||||
|
||||
<Select
|
||||
<ControlledSelect
|
||||
label="Kelompok Umur"
|
||||
placeholder="Pilih kelompok umur"
|
||||
value={formData.kelompokUmurId}
|
||||
onChange={handleChange('kelompokUmurId')}
|
||||
data={mapSelectData(indeksKepuasanState.kelompokUmurResponden.findMany.data)}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
radius="md"
|
||||
error={!formData.kelompokUmurId ? "Pilih kelompok umur" : undefined}
|
||||
onChange={(val) => setFormData({ ...formData, kelompokUmurId: val })}
|
||||
options={(indeksKepuasanState.kelompokUmurResponden.findMany.data || [])
|
||||
.map((v) => ({ value: v.id || '', label: v.name || 'Tanpa Nama' }))}
|
||||
loading={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
error={!formData.kelompokUmurId ? 'Pilih kelompok umur' : undefined}
|
||||
/>
|
||||
|
||||
<Group justify="flex-end" mt="md">
|
||||
<Button variant="light" color="red" onClick={() => router.back()}>
|
||||
<Group justify="right">
|
||||
<Button
|
||||
variant="outline"
|
||||
color="gray"
|
||||
radius="md"
|
||||
size="md"
|
||||
onClick={handleResetForm}
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
leftSection={<IconDeviceFloppy size={20} />}
|
||||
onClick={handleSubmit}
|
||||
loading={state.update.loading}
|
||||
color={colors['blue-button']}
|
||||
radius="md"
|
||||
size="md"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
|
||||
color: '#fff',
|
||||
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
|
||||
}}
|
||||
>
|
||||
Simpan
|
||||
{isSubmitting ? <Loader size="sm" color="white" /> : 'Simpan'}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function DetailResponden() {
|
||||
stateDetail.delete.byId(selectedId)
|
||||
setModalHapus(false)
|
||||
setSelectedId(null)
|
||||
router.push("/admin/ppid/ikm-desa-darmasaba/responden")
|
||||
router.push("/admin/ppid/indeks-kepuasan-masyarakat/responden")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export default function DetailResponden() {
|
||||
variant="light"
|
||||
onClick={() => {
|
||||
if (stateDetail.findUnique.data) {
|
||||
router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${stateDetail.findUnique.data.id}/edit`);
|
||||
router.push(`/admin/ppid/indeks-kepuasan-masyarakat/responden/${stateDetail.findUnique.data.id}/edit`);
|
||||
}
|
||||
}}
|
||||
disabled={!stateDetail.findUnique.data}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
'use client'
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import grafikBerdasarkanJenisKelamin from '@/app/admin/(dashboard)/_state/ppid/indeks_kepuasan_masyarakat/grafikBerdasarkanJenisKelamin';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useState } from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Paper, Stack, Title, TextInput, Select, Text } from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import indeksKepuasanState from '@/app/admin/(dashboard)/_state/landing-page/indeks-kepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Loader, Paper, Select, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function RespondenCreate() {
|
||||
const router = useRouter();
|
||||
const stategrafikBerdasarkanResponden = useProxy(indeksKepuasanState.responden)
|
||||
const [donutData, setDonutData] = useState<any[]>([]);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const resetForm = () => {
|
||||
stategrafikBerdasarkanResponden.create.form = {
|
||||
@@ -35,6 +34,7 @@ function RespondenCreate() {
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
const id = await stategrafikBerdasarkanResponden.create.create();
|
||||
if (typeof id !== 'undefined') {
|
||||
@@ -45,13 +45,15 @@ function RespondenCreate() {
|
||||
}
|
||||
}
|
||||
resetForm();
|
||||
router.push("/admin/ppid/ikm-desa-darmasaba/responden");
|
||||
router.push("/admin/ppid/indeks-kepuasan-masyarakat/responden");
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Box px={{ base: 0, md: 'lg' }} py="xs">
|
||||
<Box>
|
||||
<Box mb={10}>
|
||||
<Button variant="subtle" onClick={() => router.back()}>
|
||||
<IconArrowBack size={20} />
|
||||
@@ -132,13 +134,32 @@ function RespondenCreate() {
|
||||
}
|
||||
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
<Group justify="right">
|
||||
{/* Tombol Batal */}
|
||||
<Button
|
||||
variant="outline"
|
||||
color="gray"
|
||||
radius="md"
|
||||
size="md"
|
||||
onClick={resetForm}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
|
||||
{/* Tombol Simpan */}
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
radius="md"
|
||||
size="md"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
|
||||
color: '#fff',
|
||||
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
|
||||
}}
|
||||
>
|
||||
{isSubmitting ? <Loader size="sm" color="white" /> : 'Simpan'}
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
'use client';
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -16,10 +20,7 @@ import {
|
||||
Text,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import indeksKepuasanState from '../../../_state/landing-page/indeks-kepuasan';
|
||||
|
||||
@@ -28,7 +29,7 @@ function Responden() {
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title="Responden"
|
||||
title="Data Responden"
|
||||
placeholder="Cari nama responden..."
|
||||
searchIcon={<IconSearch size={18} />}
|
||||
value={search}
|
||||
@@ -46,193 +47,182 @@ interface ListRespondenProps {
|
||||
function ListResponden({ search }: ListRespondenProps) {
|
||||
const state = useProxy(indeksKepuasanState.responden);
|
||||
const router = useRouter();
|
||||
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
|
||||
const { data, page, totalPages, loading, load } = state.findMany;
|
||||
|
||||
const filteredData = (data || []).filter((item) => {
|
||||
const keyword = search.toLowerCase();
|
||||
return item.name.toLowerCase().includes(keyword);
|
||||
});
|
||||
useShallowEffect(() => {
|
||||
load(page, 10, debouncedSearch);
|
||||
}, [page, debouncedSearch]);
|
||||
|
||||
const filteredData = data || [];
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py="xl">
|
||||
<Skeleton height={750} radius="lg" />
|
||||
<Stack py={{ base: 'md', md: 'lg' }}>
|
||||
<Skeleton height={650} radius="lg" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Paper withBorder bg="white" p={{ base: 'md', sm: 'lg' }} radius="md" shadow="sm">
|
||||
<Stack gap="md">
|
||||
<Title order={4} lh={1.2}>
|
||||
Data Responden
|
||||
</Title>
|
||||
<Box visibleFrom="md">
|
||||
<Table striped withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh ta="center">No</TableTh>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Tanggal</TableTh>
|
||||
<TableTh>Jenis Kelamin</TableTh>
|
||||
<TableTh ta="center">Aksi</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
</Table>
|
||||
</Box>
|
||||
<Text c="dimmed" ta="center" py="md" fz={{ base: 'sm', md: 'md' }} lh={1.4}>
|
||||
Belum ada data responden yang tersedia
|
||||
</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<Box py={{ base: 'md', md: 'lg' }}>
|
||||
<Paper p={{ base: 'md', md: 'lg' }} radius="lg" shadow="md" withBorder>
|
||||
<Stack align="center" gap="sm">
|
||||
<Title order={2} lh={1.2}>
|
||||
Data Responden
|
||||
</Title>
|
||||
<Text c="dimmed" ta="center" fz={{ base: 'sm', md: 'md' }} lh={1.5}>
|
||||
Belum ada data responden yang tersedia
|
||||
</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper withBorder bg="white" p={{ base: 'md', sm: 'lg' }} radius="md" shadow="sm">
|
||||
<Stack gap="md">
|
||||
<Title order={4} lh={1.2}>
|
||||
Data Responden
|
||||
</Title>
|
||||
|
||||
<Box>
|
||||
<Stack gap={'lg'}>
|
||||
{/* Desktop Table */}
|
||||
<Box visibleFrom="md">
|
||||
<Table striped withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh w="5%" ta="center">
|
||||
No
|
||||
</TableTh>
|
||||
<TableTh w="25%">Nama</TableTh>
|
||||
<TableTh w="25%">Tanggal</TableTh>
|
||||
<TableTh w="20%">Jenis Kelamin</TableTh>
|
||||
<TableTh w="15%" ta="center">
|
||||
Aksi
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.length === 0 ? (
|
||||
<Paper p="lg" radius="lg" shadow="md" withBorder>
|
||||
<Title order={4} size="lg" mb="md" lh={1.2}>
|
||||
Daftar Responden
|
||||
</Title>
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withRowBorders
|
||||
verticalSpacing="sm"
|
||||
>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTd colSpan={5}>
|
||||
<Text c="dimmed" ta="center" py="md" fz="sm" lh={1.4}>
|
||||
Tidak ada data yang cocok dengan pencarian
|
||||
</Text>
|
||||
</TableTd>
|
||||
<TableTh fz="sm" fw={600} w={60}>No</TableTh>
|
||||
<TableTh fz="sm" fw={600}>Nama</TableTh>
|
||||
<TableTh fz="sm" fw={600}>Tanggal</TableTh>
|
||||
<TableTh fz="sm" fw={600}>Jenis Kelamin</TableTh>
|
||||
<TableTh fz="sm" fw={600} w={120}>Aksi</TableTh>
|
||||
</TableTr>
|
||||
) : (
|
||||
filteredData.map((item, index) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd ta="center">{index + 1}</TableTd>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
{item.tanggal ? new Date(item.tanggal).toLocaleDateString('id-ID') : '-'}
|
||||
</TableTd>
|
||||
<TableTd>{item.jenisKelamin.name}</TableTd>
|
||||
<TableTd ta="center">
|
||||
<Button
|
||||
size="xs"
|
||||
radius="md"
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImacCog size={16} />}
|
||||
onClick={() =>
|
||||
router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${item.id}`)
|
||||
}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{filteredData.length === 0 ? (
|
||||
<TableTr>
|
||||
<TableTd colSpan={5}>
|
||||
<Text ta="center" c="dimmed" fz="sm" lh={1.5}>
|
||||
Tidak ditemukan data dengan kata kunci pencarian
|
||||
</Text>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))
|
||||
)}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
) : (
|
||||
filteredData.map((item, index) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd fz="md" lh={1.5}>{index + 1}</TableTd>
|
||||
<TableTd fz="md" lh={1.5}>{item.name}</TableTd>
|
||||
<TableTd fz="md" lh={1.5}>
|
||||
{item.tanggal
|
||||
? new Date(item.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
: '-'}
|
||||
</TableTd>
|
||||
<TableTd fz="md" lh={1.5}>{item.jenisKelamin.name}</TableTd>
|
||||
<TableTd>
|
||||
<Button
|
||||
size="xs"
|
||||
radius="md"
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImac size={16} />}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/admin/ppid/indeks-kepuasan-masyarakat/responden/${item.id}`
|
||||
)
|
||||
}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))
|
||||
)}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Mobile Card View */}
|
||||
{/* Mobile Cards */}
|
||||
<Box hiddenFrom="md">
|
||||
{filteredData.length === 0 ? (
|
||||
<Text c="dimmed" ta="center" py="md" fz="sm" lh={1.4}>
|
||||
Tidak ada data yang cocok dengan pencarian
|
||||
</Text>
|
||||
) : (
|
||||
<Stack gap="sm">
|
||||
{filteredData.map((item, index) => (
|
||||
<Paper key={item.id} withBorder p="sm" radius="md">
|
||||
<Stack gap="sm">
|
||||
<Title order={4} size="md" lh={1.2} px="md">
|
||||
Daftar Responden
|
||||
</Title>
|
||||
{filteredData.length === 0 ? (
|
||||
<Paper p="md" radius="lg" shadow="sm" mx="md">
|
||||
<Text ta="center" c="dimmed" fz="sm" lh={1.5}>
|
||||
Tidak ditemukan data dengan kata kunci pencarian
|
||||
</Text>
|
||||
</Paper>
|
||||
) : (
|
||||
filteredData.map((item) => (
|
||||
<Paper key={item.id} p="md" radius="lg" shadow="sm" mx="md">
|
||||
<Stack gap={'xs'}>
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} lh={1.4}>
|
||||
No
|
||||
</Text>
|
||||
<Text fz="sm" fw={500} lh={1.4}>
|
||||
{index + 1}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} lh={1.4}>
|
||||
Nama
|
||||
</Text>
|
||||
<Text fz="sm" fw={500} lh={1.4}>
|
||||
{item.name}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} lh={1.4}>
|
||||
Tanggal
|
||||
</Text>
|
||||
<Text fz="sm" fw={500} lh={1.4}>
|
||||
{item.tanggal
|
||||
? new Date(item.tanggal).toLocaleDateString('id-ID')
|
||||
: '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz="sm" fw={600} lh={1.4}>
|
||||
Jenis Kelamin
|
||||
</Text>
|
||||
<Text fz="sm" fw={500} lh={1.4}>
|
||||
{item.jenisKelamin.name}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box ta="center">
|
||||
<Button
|
||||
size="xs"
|
||||
radius="md"
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImacCog size={16} />}
|
||||
onClick={() =>
|
||||
router.push(`/admin/ppid/ikm-desa-darmasaba/responden/${item.id}`)
|
||||
}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
</Box>
|
||||
<Text fz="sm" c="dimmed" lh={1.4}>Nama</Text>
|
||||
<Text fz="md" lh={1.5}>{item.name}</Text>
|
||||
|
||||
<Text fz="sm" c="dimmed" lh={1.4}>Tanggal</Text>
|
||||
<Text fz="md" lh={1.5}>
|
||||
{item.tanggal
|
||||
? new Date(item.tanggal).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
})
|
||||
: '-'}
|
||||
</Text>
|
||||
|
||||
<Text fz="sm" c="dimmed" lh={1.4}>Jenis Kelamin</Text>
|
||||
<Text fz="md" lh={1.5}>{item.jenisKelamin.name}</Text>
|
||||
|
||||
<Button
|
||||
size="xs"
|
||||
radius="md"
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImac size={16} />}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/admin/ppid/indeks-kepuasan-masyarakat/responden/${item.id}`
|
||||
)
|
||||
}
|
||||
mt="xs"
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
))
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
{filteredData.length > 0 && (
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
total={totalPages}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}}
|
||||
size="md"
|
||||
radius="md"
|
||||
/>
|
||||
</Center>
|
||||
)}
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
total={totalPages}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}}
|
||||
size="md"
|
||||
radius="md"
|
||||
mt={{ base: 'md', md: 'lg' }}
|
||||
/>
|
||||
</Center>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user