fix tampilan admin menu inovasi, sisa menu lingkungan
This commit is contained in:
@@ -120,7 +120,7 @@ function Page() {
|
||||
|
||||
<Box>
|
||||
<Text fw={600} fz="lg" >Kronologi</Text>
|
||||
<Text fz="sm" c="dimmed">{data.kronologi || '-'}</Text>
|
||||
<Text fz="sm" c="dimmed" dangerouslySetInnerHTML={{ __html: data.kronologi || '-' }} />
|
||||
</Box>
|
||||
|
||||
<Divider />
|
||||
|
||||
@@ -55,27 +55,28 @@ function Page() {
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Flex justify="space-between" align="center">
|
||||
<BackButton />
|
||||
<Flex gap={"xs"} align={"center"}>
|
||||
<TextInput
|
||||
placeholder="Cari laporan"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<Button
|
||||
onClick={open}
|
||||
bg={colors['blue-button']}
|
||||
size="md"
|
||||
radius="md"
|
||||
>
|
||||
<IconPlus size={20} />
|
||||
</Button>
|
||||
</Flex>
|
||||
<TextInput
|
||||
placeholder="Cari laporan"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
Laporan Keamanan Lingkungan
|
||||
</Text>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Group justify="space-between">
|
||||
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||
Laporan Keamanan Lingkungan
|
||||
</Text>
|
||||
<Button
|
||||
onClick={open}
|
||||
bg={colors['blue-button']}
|
||||
size="md"
|
||||
radius="md"
|
||||
rightSection={<IconPlus size={20} />}
|
||||
>
|
||||
Tambah Laporan
|
||||
</Button>
|
||||
</Group>
|
||||
</Box>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Stack gap={'lg'}>
|
||||
|
||||
@@ -1,11 +1,129 @@
|
||||
import React from 'react';
|
||||
'use client'
|
||||
import pencegahanKriminalitasState from '@/app/admin/(dashboard)/_state/keamanan/pencegahan-kriminalitas';
|
||||
import { Box, Button, Card, Center, Group, Loader, Paper, Stack, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowLeft } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
|
||||
function DetailPencegahanKriminalitas() {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const kriminalitasState = useProxy(pencegahanKriminalitasState);
|
||||
|
||||
useShallowEffect(() => {
|
||||
kriminalitasState.findUnique.load(params?.id as string);
|
||||
}, []);
|
||||
|
||||
if (kriminalitasState.findUnique.loading) {
|
||||
return (
|
||||
<Center py="xl">
|
||||
<Loader size="lg" color="blue" />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
if (!kriminalitasState.findUnique.data) {
|
||||
return (
|
||||
<Center h={400}>
|
||||
<Stack align="center" gap="sm">
|
||||
<Text fz="lg" fw="bold" c="dimmed">Data tidak ditemukan</Text>
|
||||
<Button
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconArrowLeft size={18} />}
|
||||
onClick={() => router.push("/admin/keamanan/pencegahan-kriminalitas")}
|
||||
>
|
||||
Kembali ke daftar
|
||||
</Button>
|
||||
</Stack>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
const data = kriminalitasState.findUnique.data;
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Page
|
||||
</div>
|
||||
<Box py="md" px="md">
|
||||
<Group mb="md">
|
||||
<Button
|
||||
variant="light"
|
||||
color="blue"
|
||||
onClick={() => router.back()}
|
||||
leftSection={<IconArrowLeft size={20} />}
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<Card
|
||||
withBorder
|
||||
radius="xl"
|
||||
shadow="md"
|
||||
p="xl"
|
||||
bg="white"
|
||||
>
|
||||
<Stack gap="lg">
|
||||
<Title order={2} c="blue">Detail Pencegahan Kriminalitas</Title>
|
||||
|
||||
<Paper radius="lg" p="lg" withBorder>
|
||||
<Stack gap="lg">
|
||||
<Stack gap={4}>
|
||||
<Text fz="sm" c="dimmed">Judul</Text>
|
||||
<Text fz="lg" fw={600}>{data?.judul || '-'}</Text>
|
||||
</Stack>
|
||||
|
||||
<Stack gap={4}>
|
||||
<Text fz="sm" c="dimmed">Deskripsi Singkat</Text>
|
||||
{data?.deskripsiSingkat ? (
|
||||
<Text fz="md" dangerouslySetInnerHTML={{ __html: data.deskripsiSingkat }} />
|
||||
) : (
|
||||
<Text fz="sm" c="dimmed">Belum ada deskripsi singkat</Text>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Stack gap={4}>
|
||||
<Text fz="sm" c="dimmed">Deskripsi Lengkap</Text>
|
||||
{data?.deskripsi ? (
|
||||
<Text fz="md" dangerouslySetInnerHTML={{ __html: data.deskripsi }} />
|
||||
) : (
|
||||
<Text fz="sm" c="dimmed">Belum ada deskripsi</Text>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Stack gap={4}>
|
||||
<Text fz="sm" c="dimmed">Video</Text>
|
||||
{data?.linkVideo ? (
|
||||
<Box
|
||||
component="iframe"
|
||||
src={convertToEmbedUrl(data.linkVideo)}
|
||||
width="100%"
|
||||
h={{ base: 320, md: 450 }}
|
||||
allowFullScreen
|
||||
style={{ borderRadius: 12, border: 'none' }}
|
||||
/>
|
||||
) : (
|
||||
<Text fz="sm" c="dimmed">Belum ada video</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
|
||||
function convertToEmbedUrl(youtubeUrl: string): string {
|
||||
try {
|
||||
const url = new URL(youtubeUrl);
|
||||
const videoId = url.searchParams.get("v");
|
||||
if (!videoId) return youtubeUrl;
|
||||
return `https://www.youtube.com/embed/${videoId}`;
|
||||
} catch {
|
||||
return youtubeUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default DetailPencegahanKriminalitas;
|
||||
|
||||
@@ -1,11 +1,137 @@
|
||||
import React from 'react';
|
||||
'use client'
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Center,
|
||||
Group,
|
||||
Pagination,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
Tooltip,
|
||||
Button,
|
||||
Paper,
|
||||
} from '@mantine/core';
|
||||
import { IconSearch, IconArrowRight } from '@tabler/icons-react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import pencegahanKriminalitasState from '@/app/admin/(dashboard)/_state/keamanan/pencegahan-kriminalitas';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useState } from 'react';
|
||||
import HeaderSearch from '@/app/admin/(dashboard)/_com/header';
|
||||
|
||||
function PencegahanKriminalitas() {
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Page
|
||||
</div>
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title="Program Pencegahan Kriminalitas"
|
||||
placeholder="Cari program atau deskripsi..."
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPencegahanKriminalitas search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
function ListPencegahanKriminalitas({ search }: { search: string }) {
|
||||
const kriminalitasState = useProxy(pencegahanKriminalitasState);
|
||||
const router = useRouter();
|
||||
|
||||
const { data, page, totalPages, loading, load } = kriminalitasState.findMany;
|
||||
|
||||
useShallowEffect(() => {
|
||||
load(page, 6, search);
|
||||
}, [page, search]);
|
||||
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py="lg">
|
||||
<Skeleton height={300} radius="lg" />
|
||||
<Skeleton height={300} radius="lg" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box py="lg">
|
||||
<Stack>
|
||||
{data.length > 0 ? (
|
||||
data.map((item) => (
|
||||
<Card
|
||||
key={item.id}
|
||||
withBorder
|
||||
radius="lg"
|
||||
shadow="md"
|
||||
p="lg"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #ffffff 0%, #f9fbff 100%)',
|
||||
}}
|
||||
>
|
||||
<Stack gap="xs">
|
||||
<Title order={4} c="blue" style={{ fontWeight: 600 }}>
|
||||
{item.judul}
|
||||
</Title>
|
||||
<Text
|
||||
fz="sm"
|
||||
c="dimmed"
|
||||
lineClamp={2}
|
||||
dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat || '' }}
|
||||
/>
|
||||
<Group justify="flex-end" mt="sm">
|
||||
<Tooltip label="Lihat detail program" withArrow>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="gradient"
|
||||
gradient={{ from: 'blue', to: 'cyan' }}
|
||||
rightSection={<IconArrowRight size={18} />}
|
||||
onClick={() => router.push(`/darmasaba/keamanan/pencegahan-kriminalitas/${item.id}`)}
|
||||
>
|
||||
Lihat Detail
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<Paper withBorder radius="lg" p="xl" shadow="sm">
|
||||
<Center>
|
||||
<Stack align="center" gap="xs">
|
||||
<Text fz="lg" fw={500} c="dimmed">
|
||||
Belum ada program pencegahan kriminalitas
|
||||
</Text>
|
||||
<Text fz="sm" c="dimmed">
|
||||
Program akan ditampilkan di sini ketika tersedia
|
||||
</Text>
|
||||
</Stack>
|
||||
</Center>
|
||||
</Paper>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
{totalPages > 1 && (
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 6, search);
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="xl"
|
||||
color="blue"
|
||||
radius="lg"
|
||||
/>
|
||||
</Center>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default PencegahanKriminalitas;
|
||||
|
||||
@@ -3,55 +3,23 @@ import jadwalkegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_k
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
ActionIcon,
|
||||
Box,
|
||||
Button,
|
||||
Combobox,
|
||||
ComboboxChevron,
|
||||
ComboboxOption,
|
||||
ComboboxOptions,
|
||||
ComboboxTarget,
|
||||
Divider,
|
||||
Group,
|
||||
InputBase,
|
||||
InputPlaceholder,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Textarea,
|
||||
TextInput,
|
||||
useCombobox
|
||||
Text
|
||||
} from '@mantine/core';
|
||||
import { DateInput } from '@mantine/dates';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconCalendar, IconDownload, IconPhone, IconMail, IconUser } from '@tabler/icons-react';
|
||||
import { IconDownload, IconMail, IconPhone, IconUser } from '@tabler/icons-react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import CreatePendaftaran from '../create/page';
|
||||
|
||||
const layanan = [
|
||||
'Penimbangan',
|
||||
'Imunisasi',
|
||||
'Vitamin A',
|
||||
'Konsultasi Gizi',
|
||||
'Pemeriksaan Kesehatan'
|
||||
];
|
||||
|
||||
function Page() {
|
||||
const combobox = useCombobox({
|
||||
onDropdownClose: () => combobox.resetSelectedOption(),
|
||||
onDropdownOpen: (eventSource) => {
|
||||
if (eventSource === 'keyboard') {
|
||||
combobox.selectActiveOption();
|
||||
} else {
|
||||
combobox.updateSelectedOptionIndex('active');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const [value, setValue] = useState<string | null>('');
|
||||
const [dateInputOpened, setDateInputOpened] = useState(false);
|
||||
const params = useParams();
|
||||
const state = useProxy(jadwalkegiatanState);
|
||||
|
||||
@@ -59,20 +27,7 @@ function Page() {
|
||||
state.findUnique.load(params?.id as string);
|
||||
}, []);
|
||||
|
||||
const options = layanan.map((item) => (
|
||||
<ComboboxOption value={item} key={item} active={item === value}>
|
||||
<Group gap="xs">
|
||||
{item === value && <IconUser size={14} stroke={2} />}
|
||||
<span>{item}</span>
|
||||
</Group>
|
||||
</ComboboxOption>
|
||||
));
|
||||
|
||||
const pickerControl = (
|
||||
<ActionIcon onClick={() => setDateInputOpened(true)} variant="light" color="blue">
|
||||
<IconCalendar size={18} />
|
||||
</ActionIcon>
|
||||
);
|
||||
|
||||
if (!state.findUnique.data) {
|
||||
return (
|
||||
@@ -133,56 +88,7 @@ function Page() {
|
||||
<Text ta="justify" fz="md" dangerouslySetInnerHTML={{ __html: state.findUnique.data.dokumenjadwalkegiatan.content }} />
|
||||
</Stack>
|
||||
|
||||
<Stack gap="sm">
|
||||
<Text fz="lg" fw="bold">Formulir Pendaftaran</Text>
|
||||
<Divider />
|
||||
<Stack gap="md">
|
||||
<TextInput label="Nama Balita" placeholder="Masukkan nama balita" size="md" />
|
||||
<DateInput
|
||||
label="Tanggal Lahir"
|
||||
placeholder="dd/mm/yyyy"
|
||||
size="md"
|
||||
w={{ base: '100%', md: '85%', lg: '75%', xl: '50%' }}
|
||||
popoverProps={{ opened: dateInputOpened, onChange: setDateInputOpened }}
|
||||
rightSection={pickerControl}
|
||||
/>
|
||||
<TextInput label="Nama Orang Tua / Wali" placeholder="Masukkan nama orang tua / wali" size="md" />
|
||||
<TextInput label="Nomor Telepon" placeholder="Masukkan nomor telepon" size="md" />
|
||||
<TextInput label="Alamat" placeholder="Masukkan alamat lengkap" size="md" />
|
||||
<Box w={{ base: '100%', md: '85%', lg: '75%', xl: '50%' }}>
|
||||
<Text fz="sm" fw="bold" pb={4}>Pilih Layanan</Text>
|
||||
<Combobox
|
||||
store={combobox}
|
||||
resetSelectionOnOptionHover
|
||||
withinPortal={false}
|
||||
onOptionSubmit={(val) => {
|
||||
setValue(val);
|
||||
combobox.updateSelectedOptionIndex('active');
|
||||
}}
|
||||
>
|
||||
<ComboboxTarget targetType="button">
|
||||
<InputBase
|
||||
component="button"
|
||||
type="button"
|
||||
pointer
|
||||
rightSection={<ComboboxChevron />}
|
||||
rightSectionPointerEvents="none"
|
||||
onClick={() => combobox.toggleDropdown()}
|
||||
>
|
||||
{value || <InputPlaceholder>Pilih layanan</InputPlaceholder>}
|
||||
</InputBase>
|
||||
</ComboboxTarget>
|
||||
<Combobox.Dropdown>
|
||||
<ComboboxOptions>{options}</ComboboxOptions>
|
||||
</Combobox.Dropdown>
|
||||
</Combobox>
|
||||
</Box>
|
||||
<Textarea label="Catatan Khusus (Opsional)" placeholder="Masukkan catatan jika ada" size="md" />
|
||||
<Button size="md" radius="lg" bg={colors['blue-button']}>
|
||||
Daftar Sekarang
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<CreatePendaftaran />
|
||||
|
||||
<Paper p="lg" radius="md" bg={colors['blue-button-trans']} shadow="sm">
|
||||
<Stack gap="xs">
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import pendaftaranJadwalKegiatanState from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/pendafataranJadwalKegiatan';
|
||||
import colors from '@/con/colors';
|
||||
import { Button, Divider, Stack, Text, Textarea, TextInput } from '@mantine/core';
|
||||
import { useEffect } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function CreatePendaftaran() {
|
||||
const stateCreate = useProxy(pendaftaranJadwalKegiatanState);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
stateCreate.findMany.load();
|
||||
}, []);
|
||||
|
||||
const resetForm = () => {
|
||||
stateCreate.create.form = {
|
||||
name: '',
|
||||
alamat: '',
|
||||
tanggal: '',
|
||||
namaOrangtua: '',
|
||||
nomor: '',
|
||||
catatan: '',
|
||||
};
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await stateCreate.create.submit();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack gap="sm">
|
||||
<Text fz="lg" fw="bold">Formulir Pendaftaran</Text>
|
||||
<Divider />
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label="Nama Balita"
|
||||
placeholder="Masukkan nama balita"
|
||||
size="md"
|
||||
value={stateCreate.create.form.name}
|
||||
onChange={(e) => stateCreate.create.form.name = e.target.value}
|
||||
/>
|
||||
<TextInput
|
||||
type='date'
|
||||
label="Tanggal Lahir"
|
||||
placeholder="dd/mm/yyyy"
|
||||
size="md"
|
||||
w={{ base: '100%', md: '85%', lg: '75%', xl: '50%' }}
|
||||
value={stateCreate.create.form.tanggal}
|
||||
onChange={(e) => stateCreate.create.form.tanggal = e.target.value}
|
||||
/>
|
||||
<TextInput
|
||||
label="Nama Orang Tua / Wali"
|
||||
placeholder="Masukkan nama orang tua / wali"
|
||||
size="md"
|
||||
value={stateCreate.create.form.namaOrangtua}
|
||||
onChange={(e) => stateCreate.create.form.namaOrangtua = e.target.value}
|
||||
/>
|
||||
<TextInput
|
||||
label="Nomor Telepon"
|
||||
placeholder="Masukkan nomor telepon"
|
||||
size="md"
|
||||
value={stateCreate.create.form.nomor}
|
||||
onChange={(e) => stateCreate.create.form.nomor = e.target.value}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder="Masukkan alamat lengkap"
|
||||
size="md"
|
||||
value={stateCreate.create.form.alamat}
|
||||
onChange={(e) => stateCreate.create.form.alamat = e.target.value}
|
||||
/>
|
||||
<Textarea
|
||||
label="Catatan Khusus (Opsional)"
|
||||
placeholder="Masukkan catatan jika ada"
|
||||
size="md"
|
||||
value={stateCreate.create.form.catatan}
|
||||
onChange={(e) => stateCreate.create.form.catatan = e.target.value}
|
||||
/>
|
||||
<Button size="md" radius="lg" bg={colors['blue-button']} onClick={handleSubmit}>
|
||||
Daftar Sekarang
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreatePendaftaran;
|
||||
Reference in New Issue
Block a user