- QC User & Admin Menu Pendidikan V
- Fix SubMenu : - Beasiswa Desa ( Baca Selengkapnya terdapatkan konten ) V - Info Sekolah ( Kategori Menyesuaikan Dengan Datanya ) V - Perpustakaan Digital ( V - Kategori Menyesuaikan Dengan Datanya V - Saat Mau minjam muncul modal data diri peminjam buku V - Ada Status Peminjamannya V )
This commit is contained in:
@@ -1,11 +1,24 @@
|
||||
'use client'
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ActionIcon, Box, Flex, Grid, GridCol, Stack, Tabs, TabsList, TabsTab, Text, TextInput } from '@mantine/core';
|
||||
import { IconSearch, IconUser } from '@tabler/icons-react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||
import BackButton from '../../../desa/layanan/_com/BackButto';
|
||||
'use client';
|
||||
|
||||
import perpustakaanDigitalState from '@/app/admin/(dashboard)/_state/pendidikan/perpustakaan-digital';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
GridCol,
|
||||
Stack,
|
||||
Tabs,
|
||||
TabsList,
|
||||
TabsTab,
|
||||
Text,
|
||||
TextInput
|
||||
} from '@mantine/core';
|
||||
import { IconSearch } from '@tabler/icons-react';
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSnapshot } from 'valtio';
|
||||
import BackButton from '../../../desa/layanan/_com/BackButto';
|
||||
|
||||
|
||||
type LayoutBukuProps = {
|
||||
placeholder?: string;
|
||||
@@ -15,7 +28,7 @@ type LayoutBukuProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
function LayoutTabs({
|
||||
export default function LayoutTabs({
|
||||
placeholder = 'Cari buku digital...',
|
||||
searchIcon = <IconSearch size={20} />,
|
||||
children,
|
||||
@@ -23,6 +36,7 @@ function LayoutTabs({
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const snap = useSnapshot(perpustakaanDigitalState);
|
||||
|
||||
const activeTab = pathname.split('/').pop() || 'semua';
|
||||
const initialSearch = searchParams.get('search') || '';
|
||||
@@ -30,6 +44,11 @@ function LayoutTabs({
|
||||
const [searchTimeout, setSearchTimeout] = useState<number | null>(null);
|
||||
const [activeTabState, setActiveTabState] = useState(activeTab);
|
||||
|
||||
// 🟦 Ambil kategori buku saat mount
|
||||
useEffect(() => {
|
||||
perpustakaanDigitalState.kategoriBuku.findMany.load();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveTabState(activeTab);
|
||||
}, [activeTab]);
|
||||
@@ -51,7 +70,9 @@ function LayoutTabs({
|
||||
if (value) params.set('search', value);
|
||||
|
||||
router.push(
|
||||
`/darmasaba/pendidikan/perpustakaan-digital/${activeTab}${params.toString() ? `?${params.toString()}` : ''}`
|
||||
`/darmasaba/pendidikan/perpustakaan-digital/${activeTab}${
|
||||
params.toString() ? `?${params.toString()}` : ''
|
||||
}`
|
||||
);
|
||||
};
|
||||
|
||||
@@ -63,41 +84,40 @@ function LayoutTabs({
|
||||
}
|
||||
};
|
||||
|
||||
// 🟩 Tabs dinamis berdasarkan kategori dari state
|
||||
const kategoriTabs =
|
||||
snap.kategoriBuku.findMany.data?.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.name.toLowerCase().replace(/\s+/g, '-'),
|
||||
href: `/darmasaba/pendidikan/perpustakaan-digital/${encodeURIComponent(item.name.toLowerCase().replace(/\s+/g, '-'))}`,
|
||||
})) ?? [];
|
||||
|
||||
const tabs = [
|
||||
{ label: 'Semua', value: 'semua', href: '/darmasaba/pendidikan/perpustakaan-digital/semua' },
|
||||
{ label: 'Dokumenter', value: 'dokumenter', href: '/darmasaba/pendidikan/perpustakaan-digital/dokumenter' },
|
||||
{ label: 'Sayuran', value: 'sayuran', href: '/darmasaba/pendidikan/perpustakaan-digital/sayuran' },
|
||||
{ label: 'Dongeng', value: 'dongeng', href: '/darmasaba/pendidikan/perpustakaan-digital/dongeng' },
|
||||
...kategoriTabs,
|
||||
];
|
||||
|
||||
const handleTabChange = (value: string | null) => {
|
||||
if (!value) return;
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
router.push(`/darmasaba/pendidikan/perpustakaan-digital/${value}${params.toString() ? `?${params.toString()}` : ''}`);
|
||||
router.push(
|
||||
`/darmasaba/pendidikan/perpustakaan-digital/${value}${
|
||||
params.toString() ? `?${params.toString()}` : ''
|
||||
}`
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack pos="relative" bg="var(--mantine-color-gray-0)" py="xl" gap="22">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Flex justify="space-between" align="center">
|
||||
<BackButton />
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
component={Link}
|
||||
href="/login"
|
||||
radius="xl"
|
||||
size="lg"
|
||||
aria-label="Masuk ke akun"
|
||||
>
|
||||
<IconUser size={26} stroke={1.5} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<Box pb={20}>
|
||||
<Text ta="center" fz={{ base: '1.6rem', md: '2.4rem' }} fw={700} c={colors['blue-button']}>
|
||||
Perpustakaan Digital Darmasaba
|
||||
</Text>
|
||||
|
||||
<Tabs color="blue" variant="pills" value={activeTabState} onChange={handleTabChange}>
|
||||
<Box px={{ base: 'md', md: 100 }} py="md" bg="var(--mantine-color-gray-1)" style={{ borderRadius: 16 }}>
|
||||
<Grid align="center" gutter="md">
|
||||
@@ -116,6 +136,7 @@ function LayoutTabs({
|
||||
))}
|
||||
</TabsList>
|
||||
</GridCol>
|
||||
|
||||
<GridCol span={{ base: 12, md: 3 }}>
|
||||
<TextInput
|
||||
radius="xl"
|
||||
@@ -130,11 +151,10 @@ function LayoutTabs({
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
{children}
|
||||
</Tabs>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default LayoutTabs;
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
'use client';
|
||||
|
||||
import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor';
|
||||
import perpustakaanDigitalState from '@/app/admin/(dashboard)/_state/pendidikan/perpustakaan-digital';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Button,
|
||||
Divider,
|
||||
Group,
|
||||
Image,
|
||||
Modal,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
} from '@mantine/core';
|
||||
import { DateInput } from '@mantine/dates';
|
||||
import {
|
||||
IconArrowRight,
|
||||
IconBook2,
|
||||
IconUser
|
||||
} from '@tabler/icons-react';
|
||||
import { useEffect } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useSnapshot } from 'valtio';
|
||||
|
||||
|
||||
export interface ModalPeminjamanProps {
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
buku: {
|
||||
id: string;
|
||||
judul: string;
|
||||
deskripsi?: string;
|
||||
image?: { link?: string };
|
||||
kategori?: { name?: string };
|
||||
} | null;
|
||||
}
|
||||
|
||||
export default function ModalPeminjaman({
|
||||
opened,
|
||||
onClose,
|
||||
buku,
|
||||
}: ModalPeminjamanProps) {
|
||||
const snap = useSnapshot(perpustakaanDigitalState.peminjamanBuku);
|
||||
|
||||
// reset form setiap modal dibuka
|
||||
useEffect(() => {
|
||||
if (opened && buku) {
|
||||
perpustakaanDigitalState.peminjamanBuku.create.form = {
|
||||
...perpustakaanDigitalState.peminjamanBuku.create.form,
|
||||
bukuId: buku.id,
|
||||
nama: '',
|
||||
noTelp: '',
|
||||
alamat: '',
|
||||
tanggalPinjam: '',
|
||||
batasKembali: '',
|
||||
tanggalKembali: '',
|
||||
catatan: '',
|
||||
};
|
||||
}
|
||||
}, [opened, buku]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!buku) return toast.error('Data buku tidak ditemukan');
|
||||
await perpustakaanDigitalState.peminjamanBuku.create.create();
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
opened={opened}
|
||||
onClose={onClose}
|
||||
centered
|
||||
size="lg"
|
||||
radius="xl"
|
||||
title={<Text fw={700}>Formulir Peminjaman Buku</Text>}
|
||||
>
|
||||
{buku ? (
|
||||
<Stack>
|
||||
{/* --- Info Buku --- */}
|
||||
<Group align="flex-start">
|
||||
<Image
|
||||
src={buku.image?.link || '/placeholder-book.jpg'}
|
||||
alt={buku.judul}
|
||||
w={100}
|
||||
radius="md"
|
||||
/>
|
||||
<Stack gap={4}>
|
||||
<Group>
|
||||
<IconBook2 size={18} color={colors['blue-button']} />
|
||||
<Text fw={700}>{buku.judul}</Text>
|
||||
</Group>
|
||||
|
||||
{buku.kategori?.name && (
|
||||
<Badge color="cyan" variant="light">
|
||||
{buku.kategori.name}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
<Text fz="sm" c="dimmed" lineClamp={3} dangerouslySetInnerHTML={{ __html: buku.deskripsi || 'Tidak ada deskripsi' }} />
|
||||
</Stack>
|
||||
</Group>
|
||||
|
||||
<Divider my="sm" />
|
||||
|
||||
{/* --- Form Input --- */}
|
||||
<TextInput
|
||||
label="Nama Peminjam"
|
||||
placeholder="Masukkan nama lengkap"
|
||||
leftSection={<IconUser size={16} />}
|
||||
value={snap.create.form.nama}
|
||||
onChange={(e) =>
|
||||
(perpustakaanDigitalState.peminjamanBuku.create.form.nama = e.currentTarget.value)
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="No Telp"
|
||||
placeholder="Masukkan no telp"
|
||||
leftSection={<IconUser size={16} />}
|
||||
value={snap.create.form.noTelp}
|
||||
onChange={(e) =>
|
||||
(perpustakaanDigitalState.peminjamanBuku.create.form.noTelp = e.currentTarget.value)
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder="Masukkan alamat"
|
||||
leftSection={<IconUser size={16} />}
|
||||
value={snap.create.form.alamat}
|
||||
onChange={(e) =>
|
||||
(perpustakaanDigitalState.peminjamanBuku.create.form.alamat = e.currentTarget.value)
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<DateInput
|
||||
label="Tanggal Pinjam"
|
||||
placeholder="Pilih tanggal pinjam"
|
||||
value={
|
||||
snap.create.form.tanggalPinjam
|
||||
? new Date(snap.create.form.tanggalPinjam)
|
||||
: null
|
||||
}
|
||||
onChange={(date) => {
|
||||
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalPinjam =
|
||||
date ? new Date(date).toISOString() : '';
|
||||
}}
|
||||
required
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Text>Catatan</Text>
|
||||
<CreateEditor
|
||||
value={snap.create.form.catatan}
|
||||
onChange={(e) =>
|
||||
(perpustakaanDigitalState.peminjamanBuku.create.form.catatan = e)
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<DateInput
|
||||
label="Tanggal Kembali"
|
||||
placeholder="Pilih tanggal kembali"
|
||||
value={
|
||||
snap.create.form.tanggalKembali
|
||||
? new Date(snap.create.form.tanggalKembali)
|
||||
: null
|
||||
}
|
||||
onChange={(date) => {
|
||||
perpustakaanDigitalState.peminjamanBuku.create.form.tanggalKembali =
|
||||
date ? new Date(date).toISOString() : '';
|
||||
}}
|
||||
required
|
||||
/>
|
||||
|
||||
<DateInput
|
||||
label="Batas Pengembalian"
|
||||
placeholder="Pilih tanggal kembali"
|
||||
value={
|
||||
snap.create.form.batasKembali
|
||||
? new Date(snap.create.form.batasKembali)
|
||||
: null
|
||||
}
|
||||
onChange={(date) => {
|
||||
perpustakaanDigitalState.peminjamanBuku.create.form.batasKembali =
|
||||
date ? new Date(date).toISOString() : '';
|
||||
}}
|
||||
required
|
||||
/>
|
||||
|
||||
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
loading={snap.create.loading}
|
||||
disabled={
|
||||
!snap.create.form.nama ||
|
||||
!snap.create.form.tanggalPinjam ||
|
||||
!snap.create.form.batasKembali ||
|
||||
!snap.create.form.tanggalKembali
|
||||
}
|
||||
rightSection={<IconArrowRight size={16} />}
|
||||
radius="xl"
|
||||
>
|
||||
Pinjam Buku
|
||||
</Button>
|
||||
</Stack>
|
||||
) : (
|
||||
<Text c="dimmed" ta="center">
|
||||
Tidak ada data buku yang dipilih
|
||||
</Text>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user