QC User & Admin Responsive : Menu Kesehatan - Ekonomi
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"name": "Pelayanan Penduduk Non-Permanent",
|
"name": "Pelayanan Penduduk Non-Permanent",
|
||||||
"deskripsi": "<p>Surat Keterangan Penduduk Non-Permanent adalah dokumen yang dikeluarkan oleh pihak berwenang untuk memberikan keterangan bahwa seseorang atau kelompok orang memiliki status penduduk non-permanent di suatu wilayah. Dokumen ini biasanya digunakan untuk keperluan administratif atau legal, seperti mendapatkan akses ke layanan kesehatan, pendidikan, atau pelayanan publik lainnya.</p>"
|
"deskripsi": "<p>Surat Keterangan Penduduk Non-Permanent adalah dokumen yang dikeluarkan oleh pihak berwenang untuk memberikan keterangan bahwa seseorang atau kelompok orang memiliki status penduduk non-permanent di suatu wilayah. Dokumen ini biasanya digunakan untuk keperluan administratif atau legal, seperti mendapatkan akses ke layanan kesehatan, pendidikan, atau pelayanan publik lainnya.</p>"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "edit",
|
||||||
"name": "Pelayanan Perizinan Berusaha Berbasis Risiko Melalui Sistem ONLINE SINGLE SUBMISSION (OSS)",
|
"name": "Pelayanan Perizinan Berusaha Berbasis Risiko Melalui Sistem ONLINE SINGLE SUBMISSION (OSS)",
|
||||||
"deskripsi": "<p>Penyelenggaraan Perizinan Berusaha Berbasis Risiko melalui Sistem Online Single Submission (OSS) merupakan pelaksanaan Undang-Undang Nomor 11 Tahun 2020 Tentang Cipta Kerja. OSS Berbasis Risiko wajib digunakan oleh Pelaku Usaha, Kementerian/Lembaga, Pemerintah Daerah, Administrator Kawasan Ekonomi Khusus (KEK), dan Badan Pengusahaan Kawasan Perdagangan Bebas Pelabuhan Bebas (KPBPB).Berdasarkan Peraturan Pemerintah Nomor 5 Tahun 2021 terdapat 1.702 kegiatan usaha yang terdiri atas 1.349 Klasifikasi Baku Lapangan Usaha Indonesia (KBLI) yang sudah diimplementasikan dalam Sistem OSS Berbasis Risiko.</p>",
|
"deskripsi": "<p>Penyelenggaraan Perizinan Berusaha Berbasis Risiko melalui Sistem Online Single Submission (OSS) merupakan pelaksanaan Undang-Undang Nomor 11 Tahun 2020 Tentang Cipta Kerja. OSS Berbasis Risiko wajib digunakan oleh Pelaku Usaha, Kementerian/Lembaga, Pemerintah Daerah, Administrator Kawasan Ekonomi Khusus (KEK), dan Badan Pengusahaan Kawasan Perdagangan Bebas Pelabuhan Bebas (KPBPB).Berdasarkan Peraturan Pemerintah Nomor 5 Tahun 2021 terdapat 1.702 kegiatan usaha yang terdiri atas 1.349 Klasifikasi Baku Lapangan Usaha Indonesia (KBLI) yang sudah diimplementasikan dalam Sistem OSS Berbasis Risiko.</p>",
|
||||||
"link" : "https://oss.go.id/"
|
"link" : "https://oss.go.id/"
|
||||||
|
|||||||
@@ -1167,6 +1167,7 @@ model KontakDarurat {
|
|||||||
deskripsi String
|
deskripsi String
|
||||||
image FileStorage @relation(fields: [imageId], references: [id])
|
image FileStorage @relation(fields: [imageId], references: [id])
|
||||||
imageId String
|
imageId String
|
||||||
|
whatsapp String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
@@ -1340,6 +1341,7 @@ model PasarDesa {
|
|||||||
harga Int
|
harga Int
|
||||||
rating Float
|
rating Float
|
||||||
alamatUsaha String
|
alamatUsaha String
|
||||||
|
kontak String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime @default(now())
|
deletedAt DateTime @default(now())
|
||||||
|
|||||||
@@ -581,33 +581,24 @@ const pelayananPerizinanBerusaha = proxy({
|
|||||||
findById: {
|
findById: {
|
||||||
data: null as pelayananPerizinanBerusahaForm | null,
|
data: null as pelayananPerizinanBerusahaForm | null,
|
||||||
loading: false,
|
loading: false,
|
||||||
initialize() {
|
|
||||||
pelayananPerizinanBerusaha.findById.data = {
|
|
||||||
id: "",
|
|
||||||
name: "",
|
|
||||||
deskripsi: "",
|
|
||||||
link: "",
|
|
||||||
} as pelayananPerizinanBerusahaForm;
|
|
||||||
},
|
|
||||||
async load(id: string) {
|
async load(id: string) {
|
||||||
try {
|
try {
|
||||||
pelayananPerizinanBerusaha.findById.loading = true;
|
this.loading = true;
|
||||||
const res = await fetch(
|
const response = await fetch(`/api/desa/layanan/pelayananperizinanberusaha/${id}`);
|
||||||
`/api/desa/layanan/pelayananperizinanberusaha/${id}`
|
if (!response.ok) {
|
||||||
);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
if (res.ok) {
|
|
||||||
const data = await res.json();
|
|
||||||
pelayananPerizinanBerusaha.findById.data = data.data ?? null;
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
"Failed to fetch pelayanan perizinan berusaha:",
|
|
||||||
res.statusText
|
|
||||||
);
|
|
||||||
pelayananPerizinanBerusaha.findById.data = null;
|
|
||||||
}
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
if (result?.success) {
|
||||||
|
this.data = result.data; // Make sure this matches your API response structure
|
||||||
|
}
|
||||||
|
return result?.data || null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching pelayanan perizinan berusaha:", error);
|
console.error('Error loading data:', error);
|
||||||
pelayananPerizinanBerusaha.findById.data = null;
|
toast.error('Gagal memuat data');
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const templatePasarDesaForm = z.object({
|
|||||||
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
imageId: z.string().min(1, "Gambar wajib dipilih"),
|
||||||
rating: z.number().min(1, "Rating minimal 1"),
|
rating: z.number().min(1, "Rating minimal 1"),
|
||||||
kategoriId: z.array(z.string()).min(1, "Minimal pilih satu kategori"),
|
kategoriId: z.array(z.string()).min(1, "Minimal pilih satu kategori"),
|
||||||
|
kontak: z.string().min(1, "Kontak wajib diisi"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultPasarDesaForm = {
|
const defaultPasarDesaForm = {
|
||||||
@@ -21,6 +22,7 @@ const defaultPasarDesaForm = {
|
|||||||
imageId: "",
|
imageId: "",
|
||||||
rating: 0,
|
rating: 0,
|
||||||
kategoriId: [] as string[],
|
kategoriId: [] as string[],
|
||||||
|
kontak: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const pasarDesa = proxy({
|
const pasarDesa = proxy({
|
||||||
@@ -188,6 +190,7 @@ const pasarDesa = proxy({
|
|||||||
imageId: data.imageId,
|
imageId: data.imageId,
|
||||||
rating: data.rating,
|
rating: data.rating,
|
||||||
kategoriId: data.kategoriId,
|
kategoriId: data.kategoriId,
|
||||||
|
kontak: data.kontak,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
@@ -225,6 +228,7 @@ const pasarDesa = proxy({
|
|||||||
imageId: this.form.imageId,
|
imageId: this.form.imageId,
|
||||||
rating: this.form.rating,
|
rating: this.form.rating,
|
||||||
kategoriId: this.form.kategoriId,
|
kategoriId: this.form.kategoriId,
|
||||||
|
kontak: this.form.kontak,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -336,6 +340,40 @@ const kategoriProduk = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// ✅ Versi findManyAll (ambil semua tanpa pagination)
|
||||||
|
findManyAll: {
|
||||||
|
data: null as
|
||||||
|
| Prisma.KategoriProdukGetPayload<{
|
||||||
|
omit: { isActive: true };
|
||||||
|
}>[]
|
||||||
|
| null,
|
||||||
|
loading: false,
|
||||||
|
search: "",
|
||||||
|
load: async (search = "") => {
|
||||||
|
kategoriProduk.findManyAll.loading = true;
|
||||||
|
kategoriProduk.findManyAll.search = search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query: any = {};
|
||||||
|
if (search) query.search = search;
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.ekonomi.kategoriproduk["find-many-all"].get({
|
||||||
|
query,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
kategoriProduk.findManyAll.data = res.data.data ?? [];
|
||||||
|
} else {
|
||||||
|
kategoriProduk.findManyAll.data = [];
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch kategori produk (all):", err);
|
||||||
|
kategoriProduk.findManyAll.data = [];
|
||||||
|
} finally {
|
||||||
|
kategoriProduk.findManyAll.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
findUnique: {
|
findUnique: {
|
||||||
data: null as Prisma.KategoriProdukGetPayload<{
|
data: null as Prisma.KategoriProdukGetPayload<{
|
||||||
omit: { isActive: true };
|
omit: { isActive: true };
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ const templateForm = z.object({
|
|||||||
name: z.string().min(3, "Judul minimal 3 karakter"),
|
name: z.string().min(3, "Judul minimal 3 karakter"),
|
||||||
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
deskripsi: z.string().min(3, "Deskripsi minimal 3 karakter"),
|
||||||
imageId: z.string().nonempty(),
|
imageId: z.string().nonempty(),
|
||||||
|
whatsapp: z.string().min(10, "Whatsapp minimal 10 karakter"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultForm = {
|
const defaultForm = {
|
||||||
name: "",
|
name: "",
|
||||||
deskripsi: "",
|
deskripsi: "",
|
||||||
imageId: "",
|
imageId: "",
|
||||||
|
whatsapp: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const kontakDarurat = proxy({
|
const kontakDarurat = proxy({
|
||||||
@@ -171,6 +173,7 @@ const kontakDarurat = proxy({
|
|||||||
name: data.name,
|
name: data.name,
|
||||||
deskripsi: data.deskripsi,
|
deskripsi: data.deskripsi,
|
||||||
imageId: data.imageId,
|
imageId: data.imageId,
|
||||||
|
whatsapp: data.whatsapp,
|
||||||
};
|
};
|
||||||
return data; // Return the loaded data
|
return data; // Return the loaded data
|
||||||
} else {
|
} else {
|
||||||
@@ -207,6 +210,7 @@ const kontakDarurat = proxy({
|
|||||||
name: this.form.name,
|
name: this.form.name,
|
||||||
deskripsi: this.form.deskripsi,
|
deskripsi: this.form.deskripsi,
|
||||||
imageId: this.form.imageId,
|
imageId: this.form.imageId,
|
||||||
|
whatsapp: this.form.whatsapp,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function PelayananPendudukNonPermanent() {
|
|||||||
radius="md"
|
radius="md"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.push(
|
router.push(
|
||||||
'/admin/desa/layanan/pelayanan_penduduk_non_permanent/edit'
|
`/admin/desa/layanan/pelayanan_penduduk_non_permanent/${data.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
@@ -8,6 +9,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Group,
|
Group,
|
||||||
Paper,
|
Paper,
|
||||||
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
@@ -21,66 +23,82 @@ import { useProxy } from 'valtio/utils';
|
|||||||
|
|
||||||
function EditPelayananPerizinanBerusaha() {
|
function EditPelayananPerizinanBerusaha() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const params = useParams();
|
const params = useParams<{ id: string }>();
|
||||||
const statePerizinanBerusaha = useProxy(
|
const id = params?.id; // ini langsung string
|
||||||
stateLayananDesa.pelayananPerizinanBerusaha
|
const state = useProxy(stateLayananDesa.pelayananPerizinanBerusaha);
|
||||||
);
|
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
deskripsi: '',
|
deskripsi: '',
|
||||||
link: '',
|
link: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// load data pertama kali
|
// Load data detail
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadPelayananPerizinan = async () => {
|
if (!id) {
|
||||||
const id = params?.id as string;
|
toast.error("ID tidak valid");
|
||||||
if (!id) return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await statePerizinanBerusaha.update.load(id);
|
setLoading(true);
|
||||||
|
const data = await state.findById.load(id);
|
||||||
if (data) {
|
if (data) {
|
||||||
setFormData({
|
setFormData({
|
||||||
name: data.name || '',
|
id: data.id,
|
||||||
deskripsi: data.deskripsi || '',
|
name: data.name || "",
|
||||||
link: data.link || '',
|
deskripsi: data.deskripsi || "",
|
||||||
|
link: data.link || "",
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
toast.error("Data tidak ditemukan");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading pelayanan perizinan berusaha:', error);
|
console.error("Error loading data:", error);
|
||||||
toast.error('Gagal memuat data pelayanan perizinan berusaha');
|
toast.error("Gagal memuat data");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
loadPelayananPerizinan();
|
|
||||||
}, [params?.id]);
|
loadData();
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
|
||||||
const handleChange =
|
const handleChange =
|
||||||
(field: keyof typeof formData) =>
|
(field: keyof typeof formData) =>
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[field]: value,
|
[field]: value,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const { name, deskripsi, link } = formData;
|
try {
|
||||||
if (statePerizinanBerusaha.findById.data) {
|
await state.update.update(formData);
|
||||||
const updatedData = {
|
|
||||||
...statePerizinanBerusaha.findById.data,
|
|
||||||
name,
|
|
||||||
deskripsi,
|
|
||||||
link,
|
|
||||||
};
|
|
||||||
await statePerizinanBerusaha.update.update(updatedData);
|
|
||||||
router.push('/admin/desa/layanan/pelayanan_perizinan_berusaha');
|
router.push('/admin/desa/layanan/pelayanan_perizinan_berusaha');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating pelayanan perizinan berusaha:', error);
|
||||||
|
toast.error('Terjadi kesalahan saat update data');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Stack align="center" justify="center" py="xl">
|
||||||
|
<Skeleton height={800} radius="md" />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
{/* Header Section */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
|
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
|
||||||
<Button
|
<Button
|
||||||
@@ -97,7 +115,7 @@ function EditPelayananPerizinanBerusaha() {
|
|||||||
</Title>
|
</Title>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Form Section */}
|
{/* Form */}
|
||||||
<Paper
|
<Paper
|
||||||
w={{ base: '100%', md: '50%' }}
|
w={{ base: '100%', md: '50%' }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
@@ -109,7 +127,6 @@ function EditPelayananPerizinanBerusaha() {
|
|||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
<Title order={3}>Edit Pelayanan Perizinan Berusaha</Title>
|
<Title order={3}>Edit Pelayanan Perizinan Berusaha</Title>
|
||||||
|
|
||||||
{/* Nama Field */}
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Judul"
|
label="Judul"
|
||||||
placeholder="Masukkan judul"
|
placeholder="Masukkan judul"
|
||||||
@@ -118,7 +135,6 @@ function EditPelayananPerizinanBerusaha() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Link Field */}
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Link"
|
label="Link"
|
||||||
placeholder="Masukkan link terkait"
|
placeholder="Masukkan link terkait"
|
||||||
@@ -126,7 +142,6 @@ function EditPelayananPerizinanBerusaha() {
|
|||||||
onChange={(e) => handleChange('link')(e.target.value)}
|
onChange={(e) => handleChange('link')(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Deskripsi Field */}
|
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={6}>Deskripsi</Title>
|
<Title order={6}>Deskripsi</Title>
|
||||||
<EditEditor
|
<EditEditor
|
||||||
@@ -135,23 +150,20 @@ function EditPelayananPerizinanBerusaha() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Action Buttons */}
|
|
||||||
<Group>
|
<Group>
|
||||||
<Button
|
<Button
|
||||||
bg={colors['blue-button']}
|
bg={colors['blue-button']}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
loading={statePerizinanBerusaha.update.loading}
|
loading={state.update.loading}
|
||||||
disabled={!formData.name}
|
disabled={!formData.name}
|
||||||
>
|
>
|
||||||
{statePerizinanBerusaha.update.loading
|
{state.update.loading ? 'Menyimpan...' : 'Simpan Perubahan'}
|
||||||
? 'Menyimpan...'
|
|
||||||
: 'Simpan Perubahan'}
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
disabled={statePerizinanBerusaha.update.loading}
|
disabled={state.update.loading}
|
||||||
>
|
>
|
||||||
Batal
|
Batal
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import {
|
import {
|
||||||
@@ -19,35 +20,58 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconEdit } from '@tabler/icons-react';
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useEffect, useState } from 'react';
|
||||||
import { useState } from 'react';
|
|
||||||
import stateLayananDesa from '../../../_state/desa/layananDesa';
|
import stateLayananDesa from '../../../_state/desa/layananDesa';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
function PerizinanBerusaha() {
|
function PerizinanBerusaha() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pelayananPerizinanBerusaha = useProxy(
|
const pelayananPerizinanBerusaha = useProxy(
|
||||||
stateLayananDesa.pelayananPerizinanBerusaha
|
stateLayananDesa.pelayananPerizinanBerusaha
|
||||||
);
|
);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState('');
|
||||||
const [active, setActive] = useState(1);
|
const [active, setActive] = useState(1);
|
||||||
const nextStep = () =>
|
const nextStep = () =>
|
||||||
setActive((current) => (current < 6 ? current + 1 : current));
|
setActive((current) => (current < 6 ? current + 1 : current));
|
||||||
const prevStep = () =>
|
const prevStep = () =>
|
||||||
setActive((current) => (current > 0 ? current - 1 : current));
|
setActive((current) => (current > 0 ? current - 1 : current));
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useEffect(() => {
|
||||||
pelayananPerizinanBerusaha.findById.load('1');
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
// You should get the ID from your router query or params
|
||||||
|
const id = '1'; // Replace with actual ID or get from URL params
|
||||||
|
await pelayananPerizinanBerusaha.findById.load(id);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Gagal memuat data');
|
||||||
|
console.error('Error:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!pelayananPerizinanBerusaha.findById.data) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Stack align="center" justify="center" py="xl">
|
<Stack align="center" justify="center" py="xl">
|
||||||
<Skeleton radius="md" height={800} />
|
<Skeleton height={800} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error || !pelayananPerizinanBerusaha.findById.data) {
|
||||||
|
return (
|
||||||
|
<Center h={200}>
|
||||||
|
<Text>{error || 'Data tidak ditemukan'}</Text>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const data = pelayananPerizinanBerusaha.findById.data;
|
const data = pelayananPerizinanBerusaha.findById.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -69,7 +93,7 @@ function PerizinanBerusaha() {
|
|||||||
radius="md"
|
radius="md"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.push(
|
router.push(
|
||||||
'/admin/desa/layanan/pelayanan_perizinan_berusaha/edit'
|
`/admin/desa/layanan/pelayanan_perizinan_berusaha/${data.id}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -183,3 +207,4 @@ function PerizinanBerusaha() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default PerizinanBerusaha;
|
export default PerizinanBerusaha;
|
||||||
|
|
||||||
|
|||||||
@@ -44,39 +44,37 @@ function EditSuratKeterangan() {
|
|||||||
const [previewImage2, setPreviewImage2] = useState<string | null>(null);
|
const [previewImage2, setPreviewImage2] = useState<string | null>(null);
|
||||||
|
|
||||||
// load data awal
|
// load data awal
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadSurat = async () => {
|
const loadSurat = async () => {
|
||||||
const id = params?.id as string;
|
const id = params?.id as string;
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await stateSurat.edit.load(id);
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await stateSurat.edit.load(id);
|
|
||||||
if (data) {
|
|
||||||
// merge style -> isi hanya field kosong
|
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
name: prev.name || data.name || '',
|
...{
|
||||||
deskripsi: prev.deskripsi || data.deskripsi || '',
|
name: prev.name || data.name || "",
|
||||||
imageId: prev.imageId || data.imageId || '',
|
deskripsi: prev.deskripsi || data.deskripsi || "",
|
||||||
image2Id: prev.image2Id || data.image2Id || '',
|
imageId: prev.imageId || data.imageId || "",
|
||||||
|
image2Id: prev.image2Id || data.image2Id || "",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (data.image?.link && !previewImage) {
|
if (data.image?.link && !previewImage) setPreviewImage(data.image.link);
|
||||||
setPreviewImage(data.image.link);
|
if (data.image2?.link && !previewImage2) setPreviewImage2(data.image2.link);
|
||||||
}
|
} catch (error) {
|
||||||
if (data.image2?.link && !previewImage2) {
|
console.error("Error loading surat:", error);
|
||||||
setPreviewImage2(data.image2.link);
|
toast.error("Gagal memuat data surat");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
};
|
||||||
console.error("Error loading surat:", error);
|
|
||||||
toast.error("Gagal memuat data surat");
|
loadSurat();
|
||||||
}
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
};
|
}, [params?.id]);
|
||||||
|
|
||||||
loadSurat();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [params?.id]);
|
|
||||||
|
|
||||||
|
|
||||||
// handler untuk submit
|
// handler untuk submit
|
||||||
|
|||||||
@@ -8,17 +8,15 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Paper,
|
Paper,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
Tooltip,
|
Tooltip
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconArrowBack } from '@tabler/icons-react';
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState, useCallback } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
|
||||||
|
|
||||||
function EditPelayananTelunjukSakti() {
|
function EditPelayananTelunjukSakti() {
|
||||||
const stateTelunjukDesa = useProxy(stateLayananDesa.pelayananTelunjukSaktiDesa);
|
const stateTelunjukDesa = useProxy(stateLayananDesa.pelayananTelunjukSaktiDesa);
|
||||||
@@ -111,21 +109,19 @@ function EditPelayananTelunjukSakti() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Deskripsi pakai editor */}
|
{/* Deskripsi */}
|
||||||
<Box>
|
<TextInput
|
||||||
<Text fz="sm" fw="bold" mb={6}>
|
value={formData.deskripsi}
|
||||||
Deskripsi
|
onChange={(e) => handleChange('deskripsi', e.target.value)}
|
||||||
</Text>
|
label="Judul Link"
|
||||||
<EditEditor
|
placeholder="Masukkan judul link"
|
||||||
value={formData.deskripsi}
|
required
|
||||||
onChange={(htmlContent) => handleChange('deskripsi', htmlContent)}
|
/>
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Link */}
|
{/* Link */}
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Link"
|
label="Link"
|
||||||
placeholder="Masukkan link terkait"
|
placeholder="Masukkan alamat link"
|
||||||
value={formData.link}
|
value={formData.link}
|
||||||
onChange={(e) => handleChange('link', e.target.value)}
|
onChange={(e) => handleChange('link', e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ function CreatePelayananTelunjukDesa() {
|
|||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
stateTelunjukDesa.create.form.deskripsi = val.target.value;
|
stateTelunjukDesa.create.form.deskripsi = val.target.value;
|
||||||
}}
|
}}
|
||||||
label="Deskripsi"
|
label="Judul Link"
|
||||||
placeholder="Masukkan deskripsi pelayanan"
|
placeholder="Masukkan judul link"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type FormData = {
|
|||||||
imageId: string;
|
imageId: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
kategoriId: string[];
|
kategoriId: string[];
|
||||||
|
kontak: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function EditPasarDesa() {
|
function EditPasarDesa() {
|
||||||
@@ -47,6 +48,7 @@ function EditPasarDesa() {
|
|||||||
imageId: '',
|
imageId: '',
|
||||||
rating: 0,
|
rating: 0,
|
||||||
kategoriId: [],
|
kategoriId: [],
|
||||||
|
kontak: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// load data awal
|
// load data awal
|
||||||
@@ -67,6 +69,7 @@ function EditPasarDesa() {
|
|||||||
imageId: data.imageId || '',
|
imageId: data.imageId || '',
|
||||||
rating: data.rating || 0,
|
rating: data.rating || 0,
|
||||||
kategoriId: data.KategoriToPasar?.map((k: any) => k.kategoriId) || [],
|
kategoriId: data.KategoriToPasar?.map((k: any) => k.kategoriId) || [],
|
||||||
|
kontak: data.kontak || '',
|
||||||
});
|
});
|
||||||
if (data.image?.link) setPreviewImage(data.image.link);
|
if (data.image?.link) setPreviewImage(data.image.link);
|
||||||
}
|
}
|
||||||
@@ -228,6 +231,14 @@ function EditPasarDesa() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Kontak"
|
||||||
|
placeholder="Masukkan kontak"
|
||||||
|
value={formData.kontak}
|
||||||
|
onChange={(e) => handleChange('kontak', e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
label="Kategori Produk"
|
label="Kategori Produk"
|
||||||
placeholder="Pilih kategori produk"
|
placeholder="Pilih kategori produk"
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ function DetailPasarDesa() {
|
|||||||
<Text fz="md" c="dimmed">{data.alamatUsaha || '-'}</Text>
|
<Text fz="md" c="dimmed">{data.alamatUsaha || '-'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Text fz="lg" fw="bold">Kontak</Text>
|
||||||
|
<Text fz="md" c="dimmed">{data.kontak || '-'}</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Gambar</Text>
|
<Text fz="lg" fw="bold">Gambar</Text>
|
||||||
{data.image?.link ? (
|
{data.image?.link ? (
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default function CreatePasarDesa() {
|
|||||||
imageId: '',
|
imageId: '',
|
||||||
rating: 0,
|
rating: 0,
|
||||||
kategoriId: [],
|
kategoriId: [],
|
||||||
|
kontak: '',
|
||||||
};
|
};
|
||||||
setPreviewImage(null);
|
setPreviewImage(null);
|
||||||
setFile(null);
|
setFile(null);
|
||||||
@@ -184,6 +185,15 @@ export default function CreatePasarDesa() {
|
|||||||
onChange={(e) => (statePasar.pasarDesa.create.form.alamatUsaha = e.target.value)}
|
onChange={(e) => (statePasar.pasarDesa.create.form.alamatUsaha = e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Kontak */}
|
||||||
|
<TextInput
|
||||||
|
label="Kontak"
|
||||||
|
type="number"
|
||||||
|
placeholder="Masukkan kontak"
|
||||||
|
defaultValue={statePasar.pasarDesa.create.form.kontak}
|
||||||
|
onChange={(e) => (statePasar.pasarDesa.create.form.kontak = e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Kategori Produk */}
|
{/* Kategori Produk */}
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
label="Kategori Produk"
|
label="Kategori Produk"
|
||||||
|
|||||||
@@ -29,10 +29,11 @@ function EditKontakDaruratKeamanan() {
|
|||||||
const kontakState = useProxy(kontakDarurat.kontakDaruratKeamananState);
|
const kontakState = useProxy(kontakDarurat.kontakDaruratKeamananState);
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
// Remove the dependency on data in the initial state
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: "",
|
name: "",
|
||||||
icon: "" as IconKey | "",
|
icon: "" as IconKey | "",
|
||||||
kategoriId: [] as string[],
|
kategoriId: [] as string[], // Initialize as empty array
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load data dari backend
|
// Load data dari backend
|
||||||
@@ -41,7 +42,7 @@ function EditKontakDaruratKeamanan() {
|
|||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await kontakDarurat.kontakDaruratItem.findMany.load();
|
await kontakDarurat.kontakDaruratItem.findMany.load();
|
||||||
|
|
||||||
const id = params?.id as string;
|
const id = params?.id as string;
|
||||||
if (id) {
|
if (id) {
|
||||||
const data = await kontakState.update.load(id);
|
const data = await kontakState.update.load(id);
|
||||||
@@ -49,7 +50,7 @@ function EditKontakDaruratKeamanan() {
|
|||||||
setFormData({
|
setFormData({
|
||||||
name: data.nama || "",
|
name: data.nama || "",
|
||||||
icon: (data.icon as IconKey) || "",
|
icon: (data.icon as IconKey) || "",
|
||||||
kategoriId: data.kategoriId || [],
|
kategoriId: Array.isArray(data.kategoriId) ? data.kategoriId : [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,9 +135,9 @@ function EditKontakDaruratKeamanan() {
|
|||||||
data={
|
data={
|
||||||
Array.isArray(kontakDarurat.kontakDaruratItem.findMany.data)
|
Array.isArray(kontakDarurat.kontakDaruratItem.findMany.data)
|
||||||
? kontakDarurat.kontakDaruratItem.findMany.data.map((v) => ({
|
? kontakDarurat.kontakDaruratItem.findMany.data.map((v) => ({
|
||||||
value: v.id,
|
value: v.id,
|
||||||
label: v.nama,
|
label: v.nama,
|
||||||
}))
|
}))
|
||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
clearable
|
clearable
|
||||||
|
|||||||
@@ -48,27 +48,29 @@ function EditLaporanPublik() {
|
|||||||
const loadLaporanPublik = async () => {
|
const loadLaporanPublik = async () => {
|
||||||
const id = params?.id as string;
|
const id = params?.id as string;
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await stateLaporan.edit.load(id);
|
const data = await stateLaporan.edit.load(id);
|
||||||
if (data) {
|
if (data) {
|
||||||
setFormData({
|
setFormData((prev) => ({
|
||||||
judul: data.judul || '',
|
...prev,
|
||||||
lokasi: data.lokasi || '',
|
judul: data.judul ?? prev.judul,
|
||||||
tanggalWaktu: data.tanggalWaktu || '',
|
lokasi: data.lokasi ?? prev.lokasi,
|
||||||
status: data.status || '',
|
tanggalWaktu: data.tanggalWaktu ?? prev.tanggalWaktu,
|
||||||
penanganan: data.penanganan?.[0]?.deskripsi || '',
|
status: (data.status as Status) ?? prev.status,
|
||||||
kronologi: data.kronologi || '',
|
penanganan: data.penanganan?.[0]?.deskripsi ?? prev.penanganan,
|
||||||
});
|
kronologi: data.kronologi ?? prev.kronologi,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading laporan publik:', error);
|
console.error("Error loading laporan publik:", error);
|
||||||
toast.error("Gagal mengambil data laporan publik");
|
toast.error("Gagal mengambil data laporan publik");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loadLaporanPublik();
|
loadLaporanPublik();
|
||||||
}, [params?.id, stateLaporan.edit]);
|
}, [params?.id, stateLaporan.edit]);
|
||||||
|
|
||||||
|
|
||||||
const handleChange = (field: string, value: string | Status) => {
|
const handleChange = (field: string, value: string | Status) => {
|
||||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Paper,
|
Paper,
|
||||||
Stack,
|
Stack,
|
||||||
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -61,9 +62,9 @@ function EditPencegahanKriminalitas() {
|
|||||||
|
|
||||||
const handleChange =
|
const handleChange =
|
||||||
(field: keyof typeof formData) =>
|
(field: keyof typeof formData) =>
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setFormData((prev) => ({ ...prev, [field]: e.target.value }));
|
setFormData((prev) => ({ ...prev, [field]: e.target.value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const converted = convertYoutubeUrlToEmbed(formData.linkVideo);
|
const converted = convertYoutubeUrlToEmbed(formData.linkVideo);
|
||||||
@@ -128,13 +129,17 @@ function EditPencegahanKriminalitas() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<Box>
|
||||||
label="Deskripsi Singkat"
|
<Text fw="bold" fz="sm" mb={6}>
|
||||||
placeholder="Masukkan deskripsi singkat"
|
Deskripsi
|
||||||
value={formData.deskripsiSingkat}
|
</Text>
|
||||||
onChange={handleChange('deskripsiSingkat')}
|
<EditEditor
|
||||||
required
|
value={formData.deskripsiSingkat}
|
||||||
/>
|
onChange={(val) =>
|
||||||
|
setFormData((prev) => ({ ...prev, deskripsiSingkat: val }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={6} fw="bold" fz="sm" mb={6}>
|
<Title order={6} fw="bold" fz="sm" mb={6}>
|
||||||
|
|||||||
@@ -90,15 +90,17 @@ function CreatePencegahanKriminalitas() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Deskripsi Singkat */}
|
{/* Deskripsi Singkat */}
|
||||||
<TextInput
|
<Box>
|
||||||
label="Deskripsi Singkat"
|
<Text fw="bold" fz="sm" mb={6}>
|
||||||
placeholder="Masukkan deskripsi singkat"
|
Deskripsi Singkat
|
||||||
defaultValue={kriminalitasState.create.form.deskripsiSingkat}
|
</Text>
|
||||||
onChange={(e) => {
|
<CreateEditor
|
||||||
kriminalitasState.create.form.deskripsiSingkat = e.currentTarget.value;
|
value={kriminalitasState.create.form.deskripsiSingkat}
|
||||||
}}
|
onChange={(val) => {
|
||||||
required
|
kriminalitasState.create.form.deskripsiSingkat = val;
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Deskripsi Panjang */}
|
{/* Deskripsi Panjang */}
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -105,9 +105,11 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
data.map((item) => (
|
data.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
<Box w={200}>
|
||||||
|
<Text fw={500} truncate="end" lineClamp={1}>
|
||||||
{item.judul}
|
{item.judul}
|
||||||
</Text>
|
</Text>
|
||||||
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Box w={200}>
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ function ListFasilitasKesehatan({ search }: { search: string }) {
|
|||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={150}>
|
<Box w={150}>
|
||||||
{item.tarifdanlayanan?.layanan || '-'}
|
<Text truncate="end" lineClamp={1}>
|
||||||
|
{item.tarifdanlayanan?.layanan || '-'}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
|
|||||||
@@ -140,15 +140,15 @@ function EditInfoWabahPenyakit() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<Box>
|
||||||
value={formData.deskripsiSingkat}
|
<Text fz="sm" fw="bold">
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
Deskripsi Singkat
|
||||||
updateField('deskripsiSingkat', e.target.value)
|
</Text>
|
||||||
}
|
<EditEditor
|
||||||
label="Deskripsi Singkat"
|
value={formData.deskripsiSingkat}
|
||||||
placeholder="Masukkan deskripsi singkat"
|
onChange={(val) => updateField('deskripsiSingkat', val)}
|
||||||
required
|
/>
|
||||||
/>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw="bold">
|
<Text fz="sm" fw="bold">
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ function DetailInfoWabahPenyakit() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi Singkat</Text>
|
<Text fz="lg" fw="bold">Deskripsi Singkat</Text>
|
||||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{data.deskripsiSingkat || '-'}</Text>
|
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.deskripsiSingkat }} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -100,15 +100,15 @@ function CreateInfoWabahPenyakit() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<Box>
|
||||||
defaultValue={infoWabahPenyakitState.create.form.deskripsiSingkat}
|
<Text fz="sm" fw="bold">Deskripsi Singkat</Text>
|
||||||
onChange={(val) => {
|
<CreateEditor
|
||||||
infoWabahPenyakitState.create.form.deskripsiSingkat = val.target.value;
|
value={infoWabahPenyakitState.create.form.deskripsiSingkat}
|
||||||
}}
|
onChange={(val) => {
|
||||||
label={<Text fz="sm" fw="bold">Deskripsi Singkat</Text>}
|
infoWabahPenyakitState.create.form.deskripsiSingkat = val;
|
||||||
placeholder="Masukkan deskripsi singkat"
|
}}
|
||||||
required
|
/>
|
||||||
/>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw="bold">Deskripsi</Text>
|
<Text fz="sm" fw="bold">Deskripsi</Text>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ function EditKontakDarurat() {
|
|||||||
name: '',
|
name: '',
|
||||||
deskripsi: '',
|
deskripsi: '',
|
||||||
imageId: '',
|
imageId: '',
|
||||||
|
whatsapp: '',
|
||||||
});
|
});
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ function EditKontakDarurat() {
|
|||||||
name: data.name || '',
|
name: data.name || '',
|
||||||
deskripsi: data.deskripsi || '',
|
deskripsi: data.deskripsi || '',
|
||||||
imageId: data.imageId || '',
|
imageId: data.imageId || '',
|
||||||
|
whatsapp: data.whatsapp || '',
|
||||||
});
|
});
|
||||||
if (data?.image?.link) setPreviewImage(data.image.link);
|
if (data?.image?.link) setPreviewImage(data.image.link);
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,14 @@ function EditKontakDarurat() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
value={formData.whatsapp}
|
||||||
|
onChange={(e) => setFormData(prev => ({ ...prev, whatsapp: e.target.value }))}
|
||||||
|
label="Whatsapp"
|
||||||
|
placeholder="Masukkan whatsapp"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw="bold">Deskripsi</Text>
|
<Text fz="sm" fw="bold">Deskripsi</Text>
|
||||||
<EditEditor
|
<EditEditor
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ function DetailKontakDarurat() {
|
|||||||
<Text fz="md" c="dimmed">{data.name || '-'}</Text>
|
<Text fz="md" c="dimmed">{data.name || '-'}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Text fz="lg" fw="bold">Whatsapp</Text>
|
||||||
|
<Text fz="md" c="dimmed">{data.whatsapp || '-'}</Text>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ function CreateKontakDarurat() {
|
|||||||
name: '',
|
name: '',
|
||||||
deskripsi: '',
|
deskripsi: '',
|
||||||
imageId: '',
|
imageId: '',
|
||||||
|
whatsapp: '',
|
||||||
};
|
};
|
||||||
setPreviewImage(null);
|
setPreviewImage(null);
|
||||||
setFile(null);
|
setFile(null);
|
||||||
@@ -105,6 +106,17 @@ function CreateKontakDarurat() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
type='number'
|
||||||
|
defaultValue={kontakDaruratState.create.form.whatsapp}
|
||||||
|
onChange={(val) => {
|
||||||
|
kontakDaruratState.create.form.whatsapp = val.target.value;
|
||||||
|
}}
|
||||||
|
label={<Text fz="sm" fw="bold">Whatsapp</Text>}
|
||||||
|
placeholder="Masukkan whatsapp"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw="bold">Deskripsi</Text>
|
<Text fz="sm" fw="bold">Deskripsi</Text>
|
||||||
<CreateEditor
|
<CreateEditor
|
||||||
|
|||||||
@@ -117,7 +117,6 @@ function EditProgramKesehatan() {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
{[
|
{[
|
||||||
{ label: 'Judul', key: 'name', placeholder: 'Masukkan judul' },
|
{ label: 'Judul', key: 'name', placeholder: 'Masukkan judul' },
|
||||||
{ label: 'Deskripsi Singkat', key: 'deskripsiSingkat', placeholder: 'Masukkan deskripsi singkat' },
|
|
||||||
].map((field) => (
|
].map((field) => (
|
||||||
<TextInput
|
<TextInput
|
||||||
key={field.key}
|
key={field.key}
|
||||||
@@ -129,6 +128,16 @@ function EditProgramKesehatan() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw="bold" mb={6}>
|
||||||
|
Deskripsi Singkat
|
||||||
|
</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={formData.deskripsiSingkat}
|
||||||
|
onChange={(val) => handleChange('deskripsiSingkat', val)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="sm" fw="bold" mb={6}>
|
<Text fz="sm" fw="bold" mb={6}>
|
||||||
Deskripsi
|
Deskripsi
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ function DetailProgramKesehatan() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi Singkat</Text>
|
<Text fz="lg" fw="bold">Deskripsi Singkat</Text>
|
||||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{data?.deskripsiSingkat || '-'}</Text>
|
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data?.deskripsiSingkat || '-' }} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -101,15 +101,17 @@ function CreateProgramKesehatan() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<Box>
|
||||||
defaultValue={programKesehatanState.create.form.deskripsiSingkat}
|
<Title order={6} mb={6}>
|
||||||
onChange={(val) => {
|
Deskripsi Singkat
|
||||||
programKesehatanState.create.form.deskripsiSingkat = val.target.value;
|
</Title>
|
||||||
}}
|
<CreateEditor
|
||||||
label="Deskripsi Singkat"
|
value={programKesehatanState.create.form.deskripsiSingkat}
|
||||||
placeholder="Masukkan deskripsi singkat"
|
onChange={(val) => {
|
||||||
required
|
programKesehatanState.create.form.deskripsiSingkat = val;
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Title order={6} mb={6}>
|
<Title order={6} mb={6}>
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ type FormCreate = {
|
|||||||
alamatUsaha: string;
|
alamatUsaha: string;
|
||||||
imageId: string;
|
imageId: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
kategoriId: string[]; // Array of KategoriProduk IDs
|
kategoriId: string[];
|
||||||
|
kontak: string;
|
||||||
|
// Array of KategoriProduk IDs
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function pasarDesaCreate(context: Context) {
|
export default async function pasarDesaCreate(context: Context) {
|
||||||
@@ -28,7 +30,9 @@ export default async function pasarDesaCreate(context: Context) {
|
|||||||
alamatUsaha: body.alamatUsaha,
|
alamatUsaha: body.alamatUsaha,
|
||||||
imageId: body.imageId,
|
imageId: body.imageId,
|
||||||
rating: Number(body.rating),
|
rating: Number(body.rating),
|
||||||
kategoriProdukId: body.kategoriId[0], // Use the first category as the main one
|
kategoriProdukId: body.kategoriId[0],
|
||||||
|
kontak: body.kontak
|
||||||
|
// Use the first category as the main one
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const PasarDesa = new Elysia({
|
|||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
rating: t.Number(),
|
rating: t.Number(),
|
||||||
kategoriId: t.Array(t.String()),
|
kategoriId: t.Array(t.String()),
|
||||||
|
kontak: t.String(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -79,6 +80,7 @@ const PasarDesa = new Elysia({
|
|||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
rating: t.Number(),
|
rating: t.Number(),
|
||||||
kategoriId: t.Array(t.String()),
|
kategoriId: t.Array(t.String()),
|
||||||
|
kontak: t.String(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
// /api/berita/findManyAll.ts
|
||||||
|
import prisma from "@/lib/prisma";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
async function kategoriProdukFindManyAll(context: Context) {
|
||||||
|
// Ambil query search (opsional)
|
||||||
|
const search2 = (context.query.search as string) || "";
|
||||||
|
|
||||||
|
// Buat where clause
|
||||||
|
const where: any = { isActive: true };
|
||||||
|
|
||||||
|
if (search2) {
|
||||||
|
where.OR = [
|
||||||
|
{ nama: { contains: search2, mode: "insensitive" } },
|
||||||
|
{
|
||||||
|
KategoriToPasar: {
|
||||||
|
some: {
|
||||||
|
kategori: {
|
||||||
|
nama: { contains: search2, mode: "insensitive" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await prisma.kategoriProduk.findMany({
|
||||||
|
where,
|
||||||
|
orderBy: { createdAt: "desc" },
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Berhasil ambil semua kategori produk",
|
||||||
|
data,
|
||||||
|
total: data.length,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error di findManyAll:", e);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Gagal mengambil data kategori produk",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default kategoriProdukFindManyAll;
|
||||||
@@ -5,12 +5,14 @@ import kategoriProdukDelete from "./del";
|
|||||||
import kategoriProdukCreate from "./create";
|
import kategoriProdukCreate from "./create";
|
||||||
import kategoriProdukUpdate from "./updt";
|
import kategoriProdukUpdate from "./updt";
|
||||||
import { t } from "elysia";
|
import { t } from "elysia";
|
||||||
|
import kategoriProdukFindManyAll from "./findManyAll";
|
||||||
|
|
||||||
const KategoriProduk = new Elysia({
|
const KategoriProduk = new Elysia({
|
||||||
prefix: "/kategoriproduk",
|
prefix: "/kategoriproduk",
|
||||||
tags: ["Ekonomi/Kategori Produk"],
|
tags: ["Ekonomi/Kategori Produk"],
|
||||||
})
|
})
|
||||||
.get("/find-many", kategoriProdukFindMany)
|
.get("/find-many", kategoriProdukFindMany)
|
||||||
|
.get("/find-many-all", kategoriProdukFindManyAll)
|
||||||
.get("/:id", async (context) => {
|
.get("/:id", async (context) => {
|
||||||
const response = await kategoriProdukFindUnique(context);
|
const response = await kategoriProdukFindUnique(context);
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ type FormUpdate = {
|
|||||||
imageId: string;
|
imageId: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
kategoriId: string[]; // Array of KategoriProduk IDs
|
kategoriId: string[]; // Array of KategoriProduk IDs
|
||||||
|
kontak: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function pasarDesaUpdate(context: Context) {
|
export default async function pasarDesaUpdate(context: Context) {
|
||||||
@@ -31,6 +32,7 @@ export default async function pasarDesaUpdate(context: Context) {
|
|||||||
alamatUsaha: body.alamatUsaha,
|
alamatUsaha: body.alamatUsaha,
|
||||||
imageId: body.imageId,
|
imageId: body.imageId,
|
||||||
rating: Number(body.rating),
|
rating: Number(body.rating),
|
||||||
|
kontak: body.kontak
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default async function kontakDaruratKeamananFindMany(context: Context) {
|
|||||||
try {
|
try {
|
||||||
const [data, total] = await Promise.all([
|
const [data, total] = await Promise.all([
|
||||||
prisma.kontakDaruratKeamanan.findMany({
|
prisma.kontakDaruratKeamanan.findMany({
|
||||||
|
where,
|
||||||
include: {
|
include: {
|
||||||
kontakItems: {
|
kontakItems: {
|
||||||
include: {
|
include: {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export default async function kontakItemFindMany(context: Context) {
|
|||||||
skip,
|
skip,
|
||||||
take: limit,
|
take: limit,
|
||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
|
where,
|
||||||
}),
|
}),
|
||||||
prisma.kontakItem.count({ where }),
|
prisma.kontakItem.count({ where }),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type FormCreate = Prisma.KontakDaruratGetPayload<{
|
|||||||
name: true;
|
name: true;
|
||||||
deskripsi: true;
|
deskripsi: true;
|
||||||
imageId: true;
|
imageId: true;
|
||||||
|
whatsapp: true;
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
export default async function kontakDaruratCreate(context: Context) {
|
export default async function kontakDaruratCreate(context: Context) {
|
||||||
@@ -17,6 +18,7 @@ export default async function kontakDaruratCreate(context: Context) {
|
|||||||
name: body.name,
|
name: body.name,
|
||||||
deskripsi: body.deskripsi,
|
deskripsi: body.deskripsi,
|
||||||
imageId: body.imageId,
|
imageId: body.imageId,
|
||||||
|
whatsapp: body.whatsapp,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const KontakDarurat = new Elysia({
|
|||||||
name: t.String(),
|
name: t.String(),
|
||||||
deskripsi: t.String(),
|
deskripsi: t.String(),
|
||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
|
whatsapp: t.String(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.get("/find-many", kontakDaruratFindMany)
|
.get("/find-many", kontakDaruratFindMany)
|
||||||
@@ -33,6 +34,7 @@ const KontakDarurat = new Elysia({
|
|||||||
name: t.String(),
|
name: t.String(),
|
||||||
deskripsi: t.String(),
|
deskripsi: t.String(),
|
||||||
imageId: t.String(),
|
imageId: t.String(),
|
||||||
|
whatsapp: t.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type FormUpdate = Prisma.KontakDaruratGetPayload<{
|
|||||||
name: true;
|
name: true;
|
||||||
deskripsi: true;
|
deskripsi: true;
|
||||||
imageId: true;
|
imageId: true;
|
||||||
|
whatsapp: true;
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
export default async function kontakDaruratUpdate(context: Context) {
|
export default async function kontakDaruratUpdate(context: Context) {
|
||||||
@@ -21,6 +22,7 @@ export default async function kontakDaruratUpdate(context: Context) {
|
|||||||
name,
|
name,
|
||||||
deskripsi,
|
deskripsi,
|
||||||
imageId,
|
imageId,
|
||||||
|
whatsapp,
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
if(!id) {
|
if(!id) {
|
||||||
@@ -75,6 +77,7 @@ export default async function kontakDaruratUpdate(context: Context) {
|
|||||||
name,
|
name,
|
||||||
deskripsi,
|
deskripsi,
|
||||||
imageId,
|
imageId,
|
||||||
|
whatsapp,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import pasarDesaState from '@/app/admin/(dashboard)/_state/ekonomi/pasar-desa/pa
|
|||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
import { Box, Center, Flex, Grid, GridCol, Image, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||||
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconMapPinFilled, IconSearch, IconShoppingCartFilled, IconStarFilled } from '@tabler/icons-react';
|
import { IconBrandWhatsapp, IconMapPinFilled, IconSearch, IconStarFilled } from '@tabler/icons-react';
|
||||||
import { motion } from 'motion/react';
|
import { motion } from 'motion/react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -25,7 +25,7 @@ function Page() {
|
|||||||
} = state.findMany
|
} = state.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
pasarDesaState.kategoriProduk.findMany.load()
|
pasarDesaState.kategoriProduk.findManyAll.load()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Filter data based on selected category
|
// Filter data based on selected category
|
||||||
@@ -105,7 +105,7 @@ function Page() {
|
|||||||
return (
|
return (
|
||||||
<Stack key={k}>
|
<Stack key={k}>
|
||||||
<motion.div
|
<motion.div
|
||||||
onClick={() => router.push('https://www.whatsapp.com/?lang=id')}
|
onClick={() => router.push(`https://wa.me/${v.kontak?.replace(/\D/g, '')}`)}
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.8 }}
|
whileTap={{ scale: 0.8 }}
|
||||||
>
|
>
|
||||||
@@ -132,7 +132,7 @@ function Page() {
|
|||||||
<Text fz={'sm'} ml={2}>{v.alamatUsaha}</Text>
|
<Text fz={'sm'} ml={2}>{v.alamatUsaha}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<IconShoppingCartFilled size={20} color={colors['blue-button']} />
|
<IconBrandWhatsapp size={20} color={colors['blue-button']} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Paper>
|
</Paper>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ function Page() {
|
|||||||
<GridCol span={{ base: 12, md: 3 }}>
|
<GridCol span={{ base: 12, md: 3 }}>
|
||||||
<TextInput
|
<TextInput
|
||||||
radius={"lg"}
|
radius={"lg"}
|
||||||
placeholder='Cari Puskesmas'
|
placeholder='Cari Keamanan Lingkungan'
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
leftSection={<IconSearch size={20} />}
|
leftSection={<IconSearch size={20} />}
|
||||||
|
|||||||
@@ -34,6 +34,52 @@ function Page() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
return (
|
||||||
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<BackButton />
|
||||||
|
</Box>
|
||||||
|
<Group px={{ base: 'md', md: 100 }} justify={'space-between'} align='center'>
|
||||||
|
<Box>
|
||||||
|
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
|
Kontak Darurat
|
||||||
|
</Text>
|
||||||
|
<Text fz={{ base: "h4", md: "h3" }} >
|
||||||
|
Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung.
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<TextInput
|
||||||
|
placeholder='Cari kontak darurat, nama, atau nomor...'
|
||||||
|
leftSection={<IconSearch size={20} />}
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
|
<Stack gap={'lg'}>
|
||||||
|
<Paper p={"xl"} bg={colors['white-trans-1']} w={{ base: "100%", md: "100%" }}>
|
||||||
|
<Flex justify={'center'} gap={'lg'} align={'center'}>
|
||||||
|
<Avatar radius={"xl"} size={'lg'} bg={colors['BG-trans']}>
|
||||||
|
<IconPhoneCall size={30} color={colors["blue-button"]} />
|
||||||
|
</Avatar>
|
||||||
|
<Box>
|
||||||
|
<Text ta={'center'} c={colors['blue-button']} py={10} fz={{ base: "md", md: "h4" }} fw={"bold"} >
|
||||||
|
Nomor Darurat Utama
|
||||||
|
</Text>
|
||||||
|
<Text ta={'center'} fw={"bold"} fz={'h2'} c={colors["blue-button"]}>112</Text>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
</Paper>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
<Center>
|
||||||
|
<Text fz={"h1"} c={colors["blue-button"]} fw={"bold"}>Tidak ada kontak darurat yang ditemukan</Text>
|
||||||
|
</Center>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
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 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -76,57 +122,63 @@ function Page() {
|
|||||||
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl">
|
<SimpleGrid cols={{ base: 1, md: 2 }} spacing="xl">
|
||||||
{/* Layanan Darurat */}
|
{/* Layanan Darurat */}
|
||||||
{data.map((item) => (
|
{data.map((item) => (
|
||||||
<Paper
|
<a
|
||||||
key={item.id}
|
key={item.id}
|
||||||
p="lg"
|
href={`tel:${item.kontakItems[0]?.kontakItem?.nomorTelepon || '112'}`}
|
||||||
radius="md"
|
style={{ textDecoration: 'none' }}
|
||||||
bg={colors['white-trans-1']}
|
|
||||||
>
|
>
|
||||||
<Group pb="md" align="center">
|
<Paper
|
||||||
<Avatar radius="xl" size="lg" bg={colors['BG-trans']}>
|
|
||||||
{item.icon && (
|
|
||||||
<IconMapper
|
|
||||||
name={item.icon as IconKey}
|
|
||||||
size={32}
|
|
||||||
color={colors['blue-button']}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Avatar>
|
|
||||||
<Text fw="bold" fz={{ base: "lg", md: "xl" }} c={colors["blue-button"]}>
|
|
||||||
{item.nama}
|
|
||||||
</Text>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
{/* Kontak Items */}
|
p="lg"
|
||||||
{item.kontakItems?.map((kontak) => (
|
radius="md"
|
||||||
<Paper
|
bg={colors['white-trans-1']}
|
||||||
key={kontak.id}
|
>
|
||||||
p="lg"
|
<Group pb="md" align="center">
|
||||||
bg={colors['BG-trans']}
|
<Avatar radius="xl" size="lg" bg={colors['BG-trans']}>
|
||||||
radius="md"
|
{item.icon && (
|
||||||
shadow="xs"
|
<IconMapper
|
||||||
mt="sm"
|
name={item.icon as IconKey}
|
||||||
>
|
size={32}
|
||||||
<Group align="center" justify="space-between">
|
color={colors['blue-button']}
|
||||||
<Group align="center">
|
/>
|
||||||
{kontak.kontakItem?.icon && (
|
)}
|
||||||
<IconMapper
|
</Avatar>
|
||||||
name={kontak.kontakItem.icon as IconKey}
|
<Text fw="bold" fz={{ base: "lg", md: "xl" }} c={colors["blue-button"]}>
|
||||||
size={24}
|
{item.nama}
|
||||||
color={colors['blue-button']}
|
</Text>
|
||||||
/>
|
</Group>
|
||||||
)}
|
|
||||||
|
{/* Kontak Items */}
|
||||||
|
{item.kontakItems?.map((kontak) => (
|
||||||
|
<Paper
|
||||||
|
key={kontak.id}
|
||||||
|
p="lg"
|
||||||
|
bg={colors['BG-trans']}
|
||||||
|
radius="md"
|
||||||
|
shadow="xs"
|
||||||
|
mt="sm"
|
||||||
|
>
|
||||||
|
<Group align="center" justify="space-between">
|
||||||
|
<Group align="center">
|
||||||
|
{kontak.kontakItem?.icon && (
|
||||||
|
<IconMapper
|
||||||
|
name={kontak.kontakItem.icon as IconKey}
|
||||||
|
size={24}
|
||||||
|
color={colors['blue-button']}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Text fw="bold" fz={{ base: "sm", md: "md" }} c={colors["blue-button"]}>
|
||||||
|
{kontak.kontakItem?.nama}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
<Text fw="bold" fz={{ base: "sm", md: "md" }} c={colors["blue-button"]}>
|
<Text fw="bold" fz={{ base: "sm", md: "md" }} c={colors["blue-button"]}>
|
||||||
{kontak.kontakItem?.nama}
|
{kontak.kontakItem?.nomorTelepon}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Text fw="bold" fz={{ base: "sm", md: "md" }} c={colors["blue-button"]}>
|
</Paper>
|
||||||
{kontak.kontakItem?.nomorTelepon}
|
))}
|
||||||
</Text>
|
</Paper>
|
||||||
</Group>
|
</a>
|
||||||
</Paper>
|
|
||||||
))}
|
|
||||||
</Paper>
|
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
<Center>
|
<Center>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import pencegahanKriminalitasState from '@/app/admin/(dashboard)/_state/keamanan/pencegahan-kriminalitas';
|
import pencegahanKriminalitasState from '@/app/admin/(dashboard)/_state/keamanan/pencegahan-kriminalitas';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { ActionIcon, Box, Button, Center, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core';
|
import { Box, Button, Center, Paper, SimpleGrid, Skeleton, Stack, Text } from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconArrowRight } from '@tabler/icons-react';
|
import { IconArrowRight } from '@tabler/icons-react';
|
||||||
import { useTransitionRouter } from 'next-view-transitions';
|
import { useTransitionRouter } from 'next-view-transitions';
|
||||||
@@ -63,7 +63,7 @@ function Page() {
|
|||||||
<Stack pt={30} gap="lg">
|
<Stack pt={30} gap="lg">
|
||||||
{data.length > 0 ? (
|
{data.length > 0 ? (
|
||||||
data.map((item) => (
|
data.map((item) => (
|
||||||
<ActionIcon key={item.id} variant='transparent' onClick={() => router.push(`/darmasaba/keamanan/pencegahan-kriminalitas/${item.id}`)}>
|
<a key={item.id} href={`/darmasaba/keamanan/pencegahan-kriminalitas/${item.id}`}>
|
||||||
<Paper p="md" bg={colors['blue-button']} radius="md" shadow="sm">
|
<Paper p="md" bg={colors['blue-button']} radius="md" shadow="sm">
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Text fz="h3" c={colors['white-1']}>
|
<Text fz="h3" c={colors['white-1']}>
|
||||||
@@ -71,7 +71,7 @@ function Page() {
|
|||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</ActionIcon>
|
</a>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Text color="dimmed">
|
<Text color="dimmed">
|
||||||
|
|||||||
@@ -20,10 +20,41 @@ function Page() {
|
|||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data && !loading) {
|
load();
|
||||||
load();
|
}, []);
|
||||||
}
|
|
||||||
}, [data, loading]);
|
// kalau masih loading
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// kalau data kosong
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
|
<BackButton />
|
||||||
|
</Box>
|
||||||
|
<Box pb={10} px={{ base: 20, md: 100 }}>
|
||||||
|
<Text fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
|
Kantor Polisi Terdekat
|
||||||
|
</Text>
|
||||||
|
<Text pb={15} fz={'h4'} >
|
||||||
|
Desa Darmasaba, Kecamatan Abiansemal, Kabupaten Badung
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Center py="xl">
|
||||||
|
<Text fz="lg" fw="bold" c="red">
|
||||||
|
Data Polsek tidak ada
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
</Stack >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import React, { useState } from 'react';
|
|||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../../desa/layanan/_com/BackButto';
|
import BackButton from '../../../desa/layanan/_com/BackButto';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useDebouncedValue } from '@mantine/hooks';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(polsekTerdekatState);
|
const state = useProxy(polsekTerdekatState);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500); // 500ms delay
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -23,8 +25,8 @@ function Page() {
|
|||||||
} = state.findMany;
|
} = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 3, search)
|
load(page, 3, debouncedSearch)
|
||||||
}, [page, search])
|
}, [page, debouncedSearch])
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -39,10 +39,9 @@ function Page() {
|
|||||||
|
|
||||||
const nama = data?.name || 'Fasilitas Kesehatan';
|
const nama = data?.name || 'Fasilitas Kesehatan';
|
||||||
const prosedur = data?.prosedurpendaftaran.content || '';
|
const prosedur = data?.prosedurpendaftaran.content || '';
|
||||||
console.log("Prosedur:", data?.prosedurpendaftaran);
|
|
||||||
const alamat = data?.informasiumum?.alamat || '-';
|
const alamat = data?.informasiumum?.alamat || '-';
|
||||||
const jam = data?.informasiumum?.jamOperasional || '-';
|
const jam = data?.informasiumum?.jamOperasional || '-';
|
||||||
const layananUnggulan = data?.layananunggulan || '';
|
const layananUnggulan = data?.layananunggulan?.content || '';
|
||||||
const tenaga = data?.dokterdantenagamedis || null;
|
const tenaga = data?.dokterdantenagamedis || null;
|
||||||
const fasilitasPendukungHtml = data?.fasilitaspendukung?.content || '';
|
const fasilitasPendukungHtml = data?.fasilitaspendukung?.content || '';
|
||||||
const tarif = (data?.tarifdanlayanan as TarifDanLayanan) || null;
|
const tarif = (data?.tarifdanlayanan as TarifDanLayanan) || null;
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ function JadwalKegiatanPage() {
|
|||||||
{item.informasijadwalkegiatan.name}
|
{item.informasijadwalkegiatan.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fw={600} fz="sm" c={colors['blue-button']}>
|
<Text fw={600} fz="sm" c={colors['blue-button']}>
|
||||||
{item.informasijadwalkegiatan.tanggal}
|
{new Date(item.informasijadwalkegiatan.tanggal).toLocaleDateString('id-ID', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric'
|
||||||
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
'use client'
|
||||||
|
import infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Image, Paper, Skeleton, Stack, Text } 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 DetailInfoWabahPenyakitUser() {
|
||||||
|
const state = useProxy(infoWabahPenyakit);
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useParams();
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
state.findUnique.load(params?.id as string);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!state.findUnique.data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton height={400} radius="md" />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = state.findUnique.data;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box py={10}>
|
||||||
|
{/* Tombol Back */}
|
||||||
|
<Button
|
||||||
|
variant="subtle"
|
||||||
|
onClick={() => router.back()}
|
||||||
|
leftSection={<IconArrowBack size={22} color={colors['blue-button']} />}
|
||||||
|
mb={15}
|
||||||
|
>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* Wrapper Detail */}
|
||||||
|
<Paper
|
||||||
|
withBorder
|
||||||
|
w="100%"
|
||||||
|
bg={colors['white-1']}
|
||||||
|
p="lg"
|
||||||
|
radius="md"
|
||||||
|
shadow="sm"
|
||||||
|
>
|
||||||
|
<Stack gap="lg">
|
||||||
|
{/* Judul */}
|
||||||
|
<Text fz="xl" fw="bold" c={colors['blue-button']} ta="center">
|
||||||
|
{data.name || 'Kontak Darurat'}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{/* Gambar */}
|
||||||
|
{data.image?.link && (
|
||||||
|
<Image
|
||||||
|
src={data.image.link}
|
||||||
|
alt={data.name}
|
||||||
|
radius="md"
|
||||||
|
maw={400}
|
||||||
|
mx="auto"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Deskripsi */}
|
||||||
|
<Box>
|
||||||
|
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||||
|
<Text
|
||||||
|
fz="md"
|
||||||
|
c="dimmed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: data.deskripsiLengkap || '-' }}
|
||||||
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DetailInfoWabahPenyakitUser;
|
||||||
@@ -2,10 +2,14 @@
|
|||||||
import infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit';
|
import infoWabahPenyakit from '@/app/admin/(dashboard)/_state/kesehatan/info-wabah-penyakit/infoWabahPenyakit';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import {
|
import {
|
||||||
|
Badge,
|
||||||
Box,
|
Box,
|
||||||
|
Button,
|
||||||
Center,
|
Center,
|
||||||
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
|
Group,
|
||||||
Image,
|
Image,
|
||||||
Pagination,
|
Pagination,
|
||||||
Paper,
|
Paper,
|
||||||
@@ -13,27 +17,25 @@ import {
|
|||||||
Skeleton,
|
Skeleton,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput
|
||||||
Badge,
|
|
||||||
HoverCard,
|
|
||||||
Divider,
|
|
||||||
Group,
|
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconSearch, IconInfoCircle } from '@tabler/icons-react';
|
import { IconInfoCircle, IconSearch } from '@tabler/icons-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
import { useTransitionRouter } from 'next-view-transitions';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(infoWabahPenyakit);
|
const state = useProxy(infoWabahPenyakit);
|
||||||
|
const router = useTransitionRouter();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500)
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 3, search);
|
load(page, 3, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
@@ -125,28 +127,9 @@ function Page() {
|
|||||||
<Text fz="sm" lh={1.5}>
|
<Text fz="sm" lh={1.5}>
|
||||||
{v.deskripsiSingkat}
|
{v.deskripsiSingkat}
|
||||||
</Text>
|
</Text>
|
||||||
<HoverCard shadow="md" position="bottom" radius="md" width={300}>
|
<Button variant="light" radius="md" size="md" onClick={() => router.push(`/admin/kesehatan/info-wabah-penyakit/${v.id}`)}>
|
||||||
<HoverCard.Target>
|
Selengkapnya
|
||||||
<Text
|
</Button>
|
||||||
fz="sm"
|
|
||||||
fw={500}
|
|
||||||
c={colors['blue-button']}
|
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
>
|
|
||||||
Lihat detail lengkap
|
|
||||||
</Text>
|
|
||||||
</HoverCard.Target>
|
|
||||||
<HoverCard.Dropdown>
|
|
||||||
<Text
|
|
||||||
fz="sm"
|
|
||||||
lh={1.6}
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: v.deskripsiLengkap,
|
|
||||||
}}
|
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
|
||||||
/>
|
|
||||||
</HoverCard.Dropdown>
|
|
||||||
</HoverCard>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
))}
|
))}
|
||||||
@@ -154,17 +137,17 @@ function Page() {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => load(newPage)}
|
onChange={(newPage) => load(newPage)}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
radius="xl"
|
radius="xl"
|
||||||
size="md"
|
size="md"
|
||||||
mt="lg"
|
mt="lg"
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { useState } from 'react';
|
import kontakDarurat from '@/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat';
|
||||||
import { useProxy } from 'valtio/utils';
|
import colors from '@/con/colors';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
Button,
|
||||||
Center,
|
Center,
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
@@ -15,23 +15,24 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip
|
||||||
Badge,
|
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconSearch, IconPhone } from '@tabler/icons-react';
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { IconBrandWhatsapp, IconSearch } from '@tabler/icons-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import kontakDarurat from '@/app/admin/(dashboard)/_state/kesehatan/kontak-darurat/kontakDarurat';
|
import { useDebouncedValue } from '@mantine/hooks';
|
||||||
import colors from '@/con/colors';
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(kontakDarurat);
|
const state = useProxy(kontakDarurat);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500)
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 6, search);
|
load(page, 3, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
@@ -113,16 +114,16 @@ function Page() {
|
|||||||
{v.name}
|
{v.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text fz="sm" c="dimmed" ta="center" lineClamp={3}>
|
<Text fz="sm" c="dimmed" ta="center" lineClamp={3}>
|
||||||
<span style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
<span style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: v.deskripsi }} />
|
||||||
</Text>
|
</Text>
|
||||||
<Badge
|
<Button
|
||||||
color="blue"
|
variant="light"
|
||||||
leftSection={<IconPhone size={14} />}
|
leftSection={<IconBrandWhatsapp size={18} />}
|
||||||
variant="light"
|
component="a"
|
||||||
mt="sm"
|
href={`https://wa.me/${v.whatsapp.replace(/\D/g, '')}`}
|
||||||
>
|
target="_blank"
|
||||||
Panggil Sekarang
|
aria-label="Hubungi WhatsApp"
|
||||||
</Badge>
|
>WhatsApp</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
))}
|
))}
|
||||||
@@ -130,22 +131,20 @@ function Page() {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{totalPages > 1 && (
|
<Center mt="xl">
|
||||||
<Center mt="xl">
|
<Pagination
|
||||||
<Pagination
|
value={page}
|
||||||
value={page}
|
onChange={(newPage) => load(newPage, 3, search)}
|
||||||
onChange={(newPage) => load(newPage, 6, search)}
|
total={totalPages}
|
||||||
total={totalPages}
|
size="lg"
|
||||||
radius="xl"
|
radius="xl"
|
||||||
size="md"
|
styles={{
|
||||||
styles={{
|
control: {
|
||||||
control: {
|
border: `1px solid ${colors['blue-button']}`,
|
||||||
borderRadius: '999px',
|
},
|
||||||
},
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</Center>
|
||||||
</Center>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
Tooltip
|
Tooltip
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { useShallowEffect } from '@mantine/hooks'
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks'
|
||||||
import { IconSearch } from '@tabler/icons-react'
|
import { IconSearch } from '@tabler/icons-react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useProxy } from 'valtio/utils'
|
import { useProxy } from 'valtio/utils'
|
||||||
@@ -26,12 +26,12 @@ import BackButton from '../../desa/layanan/_com/BackButto'
|
|||||||
function Page() {
|
function Page() {
|
||||||
const state = useProxy(penangananDarurat)
|
const state = useProxy(penangananDarurat)
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500)
|
||||||
const { data, page, totalPages, loading, load } = state.findMany
|
const { data, page, totalPages, loading, load } = state.findMany
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 6, search)
|
load(page, 3, debouncedSearch)
|
||||||
}, [page, search])
|
}, [page, debouncedSearch])
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
@@ -127,7 +127,7 @@ function Page() {
|
|||||||
c="dimmed"
|
c="dimmed"
|
||||||
lineClamp={4}
|
lineClamp={4}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -141,22 +141,21 @@ function Page() {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{totalPages > 1 && (
|
<Center mt="xl">
|
||||||
<Center mt="xl">
|
<Pagination
|
||||||
<Pagination
|
value={page}
|
||||||
value={page}
|
onChange={(newPage) => load(newPage, 3, search)}
|
||||||
onChange={(newPage) => load(newPage, 6, search)}
|
total={totalPages}
|
||||||
total={totalPages}
|
size="lg"
|
||||||
size="lg"
|
radius="xl"
|
||||||
radius="xl"
|
styles={{
|
||||||
styles={{
|
control: {
|
||||||
control: {
|
border: `1px solid ${colors['blue-button']}`,
|
||||||
border: `1px solid ${colors['blue-button']}`,
|
},
|
||||||
},
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</Center>
|
||||||
</Center>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,16 @@ export default function Page() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
return (
|
||||||
|
<Box py="xl" px={{ base: "md", md: 100 }}>
|
||||||
|
<Text fz="lg" fw="bold" c={colors["blue-button"]}>
|
||||||
|
Tidak ada posyandu yang ditemukan
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack pos="relative" bg={colors.Bg} py="xl" gap="xl">
|
<Stack pos="relative" bg={colors.Bg} py="xl" gap="xl">
|
||||||
<Box px={{ base: "md", md: 100 }}>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
@@ -111,10 +121,11 @@ export default function Page() {
|
|||||||
<IconCalendar size={18} stroke={1.5} />
|
<IconCalendar size={18} stroke={1.5} />
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz="sm" c="dimmed">
|
||||||
Jadwal:{" "}
|
Jadwal:{" "}
|
||||||
<span style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: v.jadwalPelayanan }} />
|
<span style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: v.jadwalPelayanan }} />
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Spoiler
|
<Spoiler
|
||||||
|
key={`spoiler-${v.id}`}
|
||||||
maxHeight={70}
|
maxHeight={70}
|
||||||
showLabel="Lihat selengkapnya"
|
showLabel="Lihat selengkapnya"
|
||||||
hideLabel="Sembunyikan"
|
hideLabel="Sembunyikan"
|
||||||
@@ -124,7 +135,7 @@ export default function Page() {
|
|||||||
fz="sm"
|
fz="sm"
|
||||||
lh={1.5}
|
lh={1.5}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
</Spoiler>
|
</Spoiler>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import BackButton from "../../desa/layanan/_com/BackButto";
|
|||||||
import { useProxy } from "valtio/utils";
|
import { useProxy } from "valtio/utils";
|
||||||
import programKesehatan from "@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan";
|
import programKesehatan from "@/app/admin/(dashboard)/_state/kesehatan/program-kesehatan/programKesehatan";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useDebouncedValue, useShallowEffect } from "@mantine/hooks";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
const manfaatProgram = [
|
const manfaatProgram = [
|
||||||
@@ -58,11 +58,12 @@ export default function Page() {
|
|||||||
const state = useProxy(programKesehatan);
|
const state = useProxy(programKesehatan);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 500); // 500ms delay
|
||||||
const { data, page, totalPages, loading, load } = state.findMany;
|
const { data, page, totalPages, loading, load } = state.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 3, search);
|
load(page, 3, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
@@ -125,14 +126,18 @@ export default function Page() {
|
|||||||
className="hover-scale"
|
className="hover-scale"
|
||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Image
|
<Box h={180} w="100%">
|
||||||
src={v.image?.link}
|
<Image
|
||||||
alt={v.name}
|
src={v.image?.link}
|
||||||
radius="xl"
|
alt={v.name}
|
||||||
height={180}
|
radius="xl"
|
||||||
fit="cover"
|
w="100%"
|
||||||
loading="lazy"
|
h="100%"
|
||||||
/>
|
fit="cover"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box px="lg" pb="lg">
|
<Box px="lg" pb="lg">
|
||||||
<Text
|
<Text
|
||||||
fw="bold"
|
fw="bold"
|
||||||
@@ -147,7 +152,7 @@ export default function Page() {
|
|||||||
c="dimmed"
|
c="dimmed"
|
||||||
lineClamp={3}
|
lineClamp={3}
|
||||||
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
dangerouslySetInnerHTML={{ __html: v.deskripsi }}
|
||||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
/>
|
/>
|
||||||
<Group justify="space-between" mt="md">
|
<Group justify="space-between" mt="md">
|
||||||
<Group gap="xs">
|
<Group gap="xs">
|
||||||
@@ -155,13 +160,13 @@ export default function Page() {
|
|||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
{v.createdAt
|
{v.createdAt
|
||||||
? new Date(v.createdAt).toLocaleDateString(
|
? new Date(v.createdAt).toLocaleDateString(
|
||||||
"id-ID",
|
"id-ID",
|
||||||
{
|
{
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
: "Tanggal tidak tersedia"}
|
: "Tanggal tidak tersedia"}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user