Senin, 19 May 2025 :
Yang Sudah Di Kerjakan - Tampilan UI Admin di menu kesehatan Yang Akan Dikerjakan: - API Di Menu Desa - Tampilan UI Admin Di Menu Keamanan
This commit is contained in:
BIN
foldergambar/desa/name.png
Normal file
BIN
foldergambar/desa/name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
foldergambar/desa/ppid/profile-ppid/name.png
Normal file
BIN
foldergambar/desa/ppid/profile-ppid/name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 922 KiB |
@@ -67,6 +67,7 @@
|
||||
"readdirp": "^4.1.1",
|
||||
"recharts": "^2.15.3",
|
||||
"swr": "^2.3.2",
|
||||
"uuid": "^11.1.0",
|
||||
"valtio": "^2.1.3",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
|
||||
@@ -210,32 +210,33 @@ model GrafikBerdasarkanUmur {
|
||||
// ========================================= MENU DESA ========================================= //
|
||||
// ========================================= PROFILE DESA ========================================= //
|
||||
model ProfileDesa {
|
||||
id String @id @default(cuid())
|
||||
sejarah String @db.Text
|
||||
visi String @db.Text
|
||||
misi String @db.Text
|
||||
lambang String @db.Text
|
||||
maskot String @db.Text
|
||||
ProfilPerbekel ProfilPerbekel? @relation(fields: [profilPerbekelId], references: [id])
|
||||
profilPerbekelId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
id String @id @default(cuid())
|
||||
sejarah String @db.Text
|
||||
visi String @db.Text
|
||||
misi String @db.Text
|
||||
lambang String @db.Text
|
||||
maskot String @db.Text
|
||||
ProfilPerbekel ProfilPerbekel? @relation(fields: [profilPerbekelId], references: [id])
|
||||
profilPerbekelId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model ProfilPerbekel {
|
||||
id String @id @default(cuid())
|
||||
biodata String @db.Text
|
||||
pengalaman String @db.Text
|
||||
pengalamanOrganisasi String @db.Text
|
||||
programUnggulan String @db.Text
|
||||
ProfileDesa ProfileDesa[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
id String @id @default(cuid())
|
||||
biodata String @db.Text
|
||||
pengalaman String @db.Text
|
||||
pengalamanOrganisasi String @db.Text
|
||||
programUnggulan String @db.Text
|
||||
ProfileDesa ProfileDesa[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= BERITA ========================================= //
|
||||
model Berita {
|
||||
id String @id @default(cuid())
|
||||
@@ -581,3 +582,18 @@ model DoctorSign {
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// === BARU
|
||||
|
||||
model FileStorage {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
realName String
|
||||
path String
|
||||
mimeType String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime? // nullable agar bisa menandakan belum dihapus
|
||||
isActive Boolean @default(true)
|
||||
link String
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
@@ -6,11 +6,16 @@ import caraMemperolehSalinanInformasi from './data/list-caraMemperolehSalinanInf
|
||||
import jenisInformasiDiminta from './data/list-jenisInfromasi.json'
|
||||
import layanan from './data/list-layanan.json'
|
||||
import potensi from './data/list-potensi.json'
|
||||
import profilePPID from './data/ppid/profile-ppid/profilePPid.json'
|
||||
import visiMisiPPID from './data/ppid/visi-misi-ppid/visimisiPPID.json'
|
||||
import dasarHukumPPID from './data/ppid/dasar-hukum-ppid/dasarhukumPPID.json'
|
||||
import profileDesa from './data/desa/profile/profile_desa.json'
|
||||
import profilePerbekel from './data/desa/profile/profil_perbekel.json'
|
||||
import profilePPID from './data/ppid/profile-ppid/profilePPid.json'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { mkdir, writeFile } from 'fs/promises'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
(async () => {
|
||||
for (const l of layanan) {
|
||||
await prisma.layanan.upsert({
|
||||
@@ -121,31 +126,57 @@ import profilePerbekel from './data/desa/profile/profil_perbekel.json'
|
||||
}
|
||||
console.log("cara memperoleh salinan informasi success ...")
|
||||
|
||||
for (const c of profilePPID) {
|
||||
await prisma.profilePPID.upsert({
|
||||
where: {
|
||||
id: c.id
|
||||
},
|
||||
const seedProfilePPID = async () => {
|
||||
const targetDir = path.resolve("public", "assets", "images", "ppid", "profile-ppid")
|
||||
await mkdir(targetDir, { recursive: true })
|
||||
|
||||
for (const c of profilePPID) {
|
||||
let finalImageUrl = c.imageUrl
|
||||
|
||||
// kalau imageUrl diawali dengan "/assets/images", artinya kita harus copy file dari seed-images
|
||||
if (c.imageUrl.startsWith("/assets/images/")) {
|
||||
const filename = path.basename(c.imageUrl) // misal "perbekel.png"
|
||||
const seedImagePath = path.resolve("prisma", "seed-images", filename)
|
||||
|
||||
// Buat nama baru yang unik agar tidak bentrok
|
||||
const targetFilename = `${uuid()}_${filename}`
|
||||
const targetPath = path.join(targetDir, targetFilename)
|
||||
|
||||
// Salin file dari prisma/seed-images ke public/
|
||||
const buffer = fs.readFileSync(seedImagePath)
|
||||
await writeFile(targetPath, buffer)
|
||||
|
||||
finalImageUrl = `/assets/images/ppid/profile-ppid/${targetFilename}`
|
||||
}
|
||||
|
||||
// Upsert ke database
|
||||
await prisma.profilePPID.upsert({
|
||||
where: { id: c.id },
|
||||
update: {
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
imageUrl: c.imageUrl
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
imageUrl: finalImageUrl,
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
imageUrl: c.imageUrl
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log("profile PPID success ...")
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
biodata: c.biodata,
|
||||
riwayat: c.riwayat,
|
||||
pengalaman: c.pengalaman,
|
||||
unggulan: c.unggulan,
|
||||
imageUrl: finalImageUrl,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
console.log("✅ profilePPID seeded from JSON with image copying")
|
||||
}
|
||||
|
||||
await seedProfilePPID()
|
||||
|
||||
|
||||
for (const v of visiMisiPPID) {
|
||||
await prisma.visiMisiPPID.upsert({
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 275 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
239
src/app/admin/(dashboard)/_state/desa/profile.ts
Normal file
239
src/app/admin/(dashboard)/_state/desa/profile.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
/* Sejarah */
|
||||
const templateFormSejarahForm = z.object({
|
||||
sejarah: z.string().min(3, "Sejarah minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type SejarahForm = Prisma.ProfileDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
sejarah: true;
|
||||
}
|
||||
}>
|
||||
|
||||
const Sejarah = proxy({
|
||||
findById: {
|
||||
data: null as SejarahForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
Sejarah.findById.data = {
|
||||
id: "",
|
||||
sejarah: "",
|
||||
} as SejarahForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
Sejarah.findById.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
Sejarah.findById.data = {
|
||||
id: id,
|
||||
sejarah: res.data?.data?.sejarah ?? ""
|
||||
};
|
||||
} else {
|
||||
toast.error("Gagal mengambil data sejarah");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data sejarah");
|
||||
} finally {
|
||||
Sejarah.findById.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: SejarahForm) {
|
||||
const cek = templateFormSejarahForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Sejarah.update.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile.sejarah["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil update sejarah");
|
||||
await Sejarah.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal update sejarah");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat update sejarah");
|
||||
} finally {
|
||||
Sejarah.update.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* Visi Misi Desa */
|
||||
const templateFormVisiForm = z.object({
|
||||
visi: z.string().min(3, "Visi minimal 3 karakter"),
|
||||
misi: z.string().min(3, "Misi minimal 3 karakter")
|
||||
})
|
||||
|
||||
type VisiMisiDesaForm = Prisma.ProfileDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
visi: true;
|
||||
misi: true;
|
||||
}
|
||||
}>
|
||||
|
||||
const VisiMisiDesa = proxy({
|
||||
findById: {
|
||||
data: null as VisiMisiDesaForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
VisiMisiDesa.findById.data = {
|
||||
id: "",
|
||||
visi: "",
|
||||
misi: ""
|
||||
} as VisiMisiDesaForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
VisiMisiDesa.findById.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
VisiMisiDesa.findById.data = {
|
||||
id: id,
|
||||
visi: res.data?.data?.visi ?? "",
|
||||
misi: res.data?.data?.misi ?? ""
|
||||
};
|
||||
} else {
|
||||
toast.error("Gagal mengambil data visi misi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data visi misi");
|
||||
} finally {
|
||||
VisiMisiDesa.findById.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: VisiMisiDesaForm) {
|
||||
const cek = templateFormVisiForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
VisiMisiDesa.update.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile.visimisiDesa["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil update visi misi");
|
||||
await VisiMisiDesa.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal update visi");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat update visi misi");
|
||||
} finally {
|
||||
VisiMisiDesa.update.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
/* Lambang Desa */
|
||||
const templateFormLambangDesaForm = z.object({
|
||||
lambang: z.string().min(3, "Lambang minimal 3 karakter"),
|
||||
})
|
||||
|
||||
type LambangDesaForm = Prisma.ProfileDesaGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
lambang: true;
|
||||
}
|
||||
}>
|
||||
|
||||
const LambangDesa = proxy({
|
||||
findById: {
|
||||
data: null as LambangDesaForm | null,
|
||||
loading: false,
|
||||
initialize() {
|
||||
LambangDesa.findById.data = {
|
||||
id: "",
|
||||
lambang: "",
|
||||
} as LambangDesaForm;
|
||||
},
|
||||
async load(id: string) {
|
||||
try {
|
||||
LambangDesa.findById.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
if (res.status === 200) {
|
||||
LambangDesa.findById.data = {
|
||||
id: id,
|
||||
lambang: res.data?.data?.lambang ?? ""
|
||||
};
|
||||
} else {
|
||||
toast.error("Gagal mengambil data lambang desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat mengambil data lambang desa");
|
||||
} finally {
|
||||
LambangDesa.findById.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
update: {
|
||||
loading: false,
|
||||
async save(data: LambangDesaForm) {
|
||||
const cek = templateFormLambangDesaForm.safeParse(data);
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
.join(", ");
|
||||
toast.error(`Form tidak valid: ${errors}`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
LambangDesa.update.loading = true;
|
||||
const res = await ApiFetch.api.desa.profile.lambangDesa["update"].post(data);
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil update lambang desa");
|
||||
await LambangDesa.findById.load(data.id);
|
||||
} else {
|
||||
toast.error("Gagal update lambang desa");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error((error as Error).message);
|
||||
toast.error("Terjadi kesalahan saat update lambang desa");
|
||||
} finally {
|
||||
LambangDesa.update.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const stateProfileDesa = {
|
||||
Sejarah,
|
||||
VisiMisiDesa,
|
||||
LambangDesa,
|
||||
};
|
||||
|
||||
|
||||
export default stateProfileDesa;
|
||||
@@ -4,7 +4,9 @@ import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
// Schema validasi form
|
||||
/**
|
||||
* Schema validasi form ProfilePPID menggunakan Zod.
|
||||
*/
|
||||
const templateForm = z.object({
|
||||
name: z.string().min(3, "Nama minimal 3 karakter"),
|
||||
biodata: z.string().min(3, "Biodata minimal 3 karakter"),
|
||||
@@ -13,7 +15,9 @@ const templateForm = z.object({
|
||||
unggulan: z.string().min(3, "Unggulan minimal 3 karakter"),
|
||||
});
|
||||
|
||||
// Type ambil dari Prisma
|
||||
/**
|
||||
* Tipe data ProfilePPID yang digunakan dalam form dan API, berdasarkan Prisma schema.
|
||||
*/
|
||||
type ProfilePPIDForm = Prisma.ProfilePPIDGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
@@ -26,11 +30,23 @@ type ProfilePPIDForm = Prisma.ProfilePPIDGetPayload<{
|
||||
};
|
||||
}>;
|
||||
|
||||
// Proxy utama
|
||||
/**
|
||||
* State utama ProfilePPID yang mencakup fitur:
|
||||
* - Ambil data berdasarkan ID
|
||||
* - Update data
|
||||
* - Upload gambar
|
||||
*/
|
||||
const stateProfilePPID = proxy({
|
||||
/**
|
||||
* Bagian untuk ambil data berdasarkan ID
|
||||
*/
|
||||
findById: {
|
||||
data: null as ProfilePPIDForm | null,
|
||||
loading: false,
|
||||
|
||||
/**
|
||||
* Inisialisasi data kosong ke dalam state.
|
||||
*/
|
||||
initialize() {
|
||||
stateProfilePPID.findById.data = {
|
||||
id: '',
|
||||
@@ -39,15 +55,21 @@ const stateProfilePPID = proxy({
|
||||
riwayat: '',
|
||||
pengalaman: '',
|
||||
unggulan: '',
|
||||
imageUrl:''
|
||||
imageUrl: ''
|
||||
} as ProfilePPIDForm;
|
||||
},
|
||||
|
||||
/**
|
||||
* Mengambil data profil berdasarkan ID.
|
||||
* @param {string} id - ID dari profile yang ingin diambil.
|
||||
*/
|
||||
async load(id: string) {
|
||||
try {
|
||||
stateProfilePPID.findById.loading = true;
|
||||
const res = await ApiFetch.api.ppid.profileppid["find-by-id"].get({
|
||||
query: { id },
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
stateProfilePPID.findById.data = res.data?.data ?? null;
|
||||
} else {
|
||||
@@ -62,10 +84,19 @@ const stateProfilePPID = proxy({
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Bagian untuk update data profile
|
||||
*/
|
||||
update: {
|
||||
loading: false,
|
||||
|
||||
/**
|
||||
* Melakukan validasi dan menyimpan perubahan data profile ke server.
|
||||
* @param {ProfilePPIDForm} data - Data profil yang akan disimpan.
|
||||
*/
|
||||
async save(data: ProfilePPIDForm) {
|
||||
const cek = templateForm.safeParse(data);
|
||||
|
||||
if (!cek.success) {
|
||||
const errors = cek.error.issues
|
||||
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
||||
@@ -77,6 +108,7 @@ const stateProfilePPID = proxy({
|
||||
try {
|
||||
stateProfilePPID.update.loading = true;
|
||||
const res = await ApiFetch.api.ppid.profileppid["update"].post(data);
|
||||
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil update profile");
|
||||
await stateProfilePPID.findById.load(data.id);
|
||||
@@ -91,13 +123,24 @@ const stateProfilePPID = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Bagian untuk upload gambar profil
|
||||
*/
|
||||
uploadImage: {
|
||||
loading: false,
|
||||
|
||||
/**
|
||||
* Mengunggah gambar profil berdasarkan ID.
|
||||
* @param {File} file - File gambar yang akan diunggah.
|
||||
* @param {string} id - ID dari profil yang akan diperbarui gambarnya.
|
||||
*/
|
||||
async save(file: File, id: string) {
|
||||
if (!file || !id) {
|
||||
toast.error("File atau ID harus disertakan");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
stateProfilePPID.uploadImage.loading = true;
|
||||
|
||||
@@ -106,6 +149,7 @@ const stateProfilePPID = proxy({
|
||||
form.append("id", id);
|
||||
|
||||
const res = await ApiFetch.api.ppid.profileppid["edit-img"].post(form);
|
||||
|
||||
if (res.status === 200) {
|
||||
toast.success("Berhasil mengunggah gambar");
|
||||
await stateProfilePPID.findById.load(id);
|
||||
@@ -118,8 +162,11 @@ const stateProfilePPID = proxy({
|
||||
} finally {
|
||||
stateProfilePPID.uploadImage.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Ekspor state utama ProfilePPID untuk digunakan di komponen lain.
|
||||
*/
|
||||
export default stateProfilePPID;
|
||||
|
||||
@@ -1,62 +1,75 @@
|
||||
'use client'
|
||||
import { Center, Group, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Center, Group, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { IconImageInPicture } from '@tabler/icons-react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateDashboardBerita from '../../_state/desa/berita';
|
||||
import { BeritaEditor } from './_com/BeritaEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack>
|
||||
<SimpleGrid cols={{base: 1, md: 2}}>
|
||||
<Box>
|
||||
<Title order={3}>Berita</Title>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<BeritaCreate />
|
||||
<BeritaList />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function BeritaCreate() {
|
||||
const beritaState = useProxy(stateDashboardBerita)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<SelectCategory onChange={(val) => {
|
||||
beritaState.berita.create.form.katagoryBeritaId = val.id
|
||||
}} />
|
||||
<TextInput onChange={(val) => {
|
||||
beritaState.berita.create.form.judul = val.target.value
|
||||
}} label={"Judul"} placeholder='masukkan judul' />
|
||||
<TextInput onChange={(val) => {
|
||||
beritaState.berita.create.form.deskripsi = val.target.value
|
||||
}} label={"Deskripsi"} placeholder='masukkan deskripsi' />
|
||||
<Center w={200} h={200} bg={"gray"}>
|
||||
<IconImageInPicture />
|
||||
</Center>
|
||||
<BeritaEditor onSubmit={(val) => {
|
||||
|
||||
beritaState.berita.create.form.content = val
|
||||
beritaState.berita.create.create()
|
||||
}} />
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
function BeritaList() {
|
||||
const beritaState = useProxy(stateDashboardBerita)
|
||||
useShallowEffect(() => {
|
||||
beritaState.berita.findMany.load()
|
||||
}, [])
|
||||
|
||||
if (!beritaState.berita.findMany.data) return <Stack>
|
||||
if (!beritaState.berita.findMany.data) return <Stack py={10}>
|
||||
{Array.from({ length: 10 }).map((v, k) => <Skeleton key={k} h={40} />)}
|
||||
</Stack>
|
||||
return <Stack>
|
||||
<Text>News List</Text>
|
||||
{beritaState.berita.findMany.data?.map((item) => (
|
||||
<Text key={item.id}>{item.judul}</Text>
|
||||
))}
|
||||
</Stack>
|
||||
}
|
||||
|
||||
function BeritaCreate() {
|
||||
const beritaState = useProxy(stateDashboardBerita)
|
||||
return <Stack gap={"md"}>
|
||||
<Text>Create Some News</Text>
|
||||
<SelectCategory onChange={(val) => {
|
||||
beritaState.berita.create.form.katagoryBeritaId = val.id
|
||||
}} />
|
||||
<TextInput onChange={(val) => {
|
||||
beritaState.berita.create.form.judul = val.target.value
|
||||
}} label={"Judul"} placeholder='masukkan judul' />
|
||||
<TextInput onChange={(val) => {
|
||||
beritaState.berita.create.form.deskripsi = val.target.value
|
||||
}} label={"Deskripsi"} placeholder='masukkan deskripsi' />
|
||||
<Center w={200} h={200} bg={"gray"}>
|
||||
<IconImageInPicture />
|
||||
</Center>
|
||||
<BeritaEditor onSubmit={(val) => {
|
||||
|
||||
beritaState.berita.create.form.content = val
|
||||
beritaState.berita.create.create()
|
||||
}} />
|
||||
</Stack>
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Text fz={"xl"} fw={"bold"}>List Berita</Text>
|
||||
{beritaState.berita.findMany.data?.map((item) => (
|
||||
<Text key={item.id}>{item.judul}</Text>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectCategory({ onChange }: {
|
||||
@@ -74,7 +87,7 @@ function SelectCategory({ onChange }: {
|
||||
|
||||
if (!beritaState.category.findMany.data) return <Skeleton h={40} />
|
||||
return <Group>
|
||||
<Select placeholder='pilih katagori' label={"select katagori"} data={beritaState.category.findMany.data.map((item) => ({
|
||||
<Select placeholder='pilih katagori' label={<Text fz={"sm"} fw={"bold"}>Pilih Kategori</Text>} data={beritaState.category.findMany.data.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name
|
||||
}))} onChange={(v) => {
|
||||
|
||||
@@ -1,11 +1,35 @@
|
||||
import React from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import { IconPhoto, IconVideo } from '@tabler/icons-react';
|
||||
import Foto from './ui/foto/page';
|
||||
import Video from './ui/video/page';
|
||||
|
||||
function Page() {
|
||||
function Gallery() {
|
||||
return (
|
||||
<div>
|
||||
Gallery
|
||||
</div>
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Gallery</Title>
|
||||
<Tabs color={colors['blue-button']} variant="pills" defaultValue="foto">
|
||||
<TabsList p={"xs"} bg={"#BBC8E7FF"}>
|
||||
<TabsTab value="foto" leftSection={<IconPhoto size={12} />}>
|
||||
Foto
|
||||
</TabsTab>
|
||||
<TabsTab value="video" leftSection={<IconVideo size={12} />}>
|
||||
Video
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
|
||||
<TabsPanel value="foto">
|
||||
<Foto/>
|
||||
</TabsPanel>
|
||||
|
||||
<TabsPanel value="video">
|
||||
<Video/>
|
||||
</TabsPanel>
|
||||
</Tabs>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Gallery;
|
||||
|
||||
17
src/app/admin/(dashboard)/desa/gallery/ui/foto/listPage.tsx
Normal file
17
src/app/admin/(dashboard)/desa/gallery/ui/foto/listPage.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListFoto() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>List Foto</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListFoto;
|
||||
52
src/app/admin/(dashboard)/desa/gallery/ui/foto/page.tsx
Normal file
52
src/app/admin/(dashboard)/desa/gallery/ui/foto/page.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Group, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconUpload } from '@tabler/icons-react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListFoto from './listPage';
|
||||
|
||||
function Foto() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Foto</Title>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Tanggal Foto</Text>}
|
||||
placeholder="2022-01-01"
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Judul Foto</Text>}
|
||||
placeholder="Judul Foto"
|
||||
/>
|
||||
<Text fz={"sm"} fw={"bold"}>Upload Foto</Text>
|
||||
<Box bg={colors['BG-trans']} p={"md"}>
|
||||
<Center>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Center>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Foto</Text>
|
||||
<DesaEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListFoto/>
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Foto;
|
||||
17
src/app/admin/(dashboard)/desa/gallery/ui/video/listPage.tsx
Normal file
17
src/app/admin/(dashboard)/desa/gallery/ui/video/listPage.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListVideo() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>List Video</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListVideo;
|
||||
52
src/app/admin/(dashboard)/desa/gallery/ui/video/page.tsx
Normal file
52
src/app/admin/(dashboard)/desa/gallery/ui/video/page.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Group, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import { IconUpload } from '@tabler/icons-react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListVideo from './listPage';
|
||||
|
||||
function Video() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Video</Title>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Tanggal Video</Text>}
|
||||
placeholder="2022-01-01"
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Judul Video</Text>}
|
||||
placeholder="Judul Video"
|
||||
/>
|
||||
<Text fz={"sm"} fw={"bold"}>Upload Video</Text>
|
||||
<Box bg={colors['BG-trans']} p={"md"}>
|
||||
<Center>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Center>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Video</Text>
|
||||
<DesaEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListVideo/>
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Video;
|
||||
@@ -1,11 +1,48 @@
|
||||
import React from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import SuratKeterangan from './ui/surat_keterangan/page';
|
||||
import PerizinanUsaha from './ui/perizinan_usaha/page';
|
||||
import TelunjukSaktiDesa from './ui/telunjuk_sakti_desa/page';
|
||||
import PendudukNonPermanent from './ui/penduduk_non_permanent/page';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Layanan
|
||||
</div>
|
||||
<Box py={10}>
|
||||
<Stack >
|
||||
<Title order={3}>Layanan</Title>
|
||||
<Tabs color={colors['blue-button']} variant='pills' defaultValue={"Pelayanan Surat Keterangan"}>
|
||||
<TabsList p={"xs"} bg={"#BBC8E7FF"}>
|
||||
<TabsTab value="Pelayanan Surat Keterangan">
|
||||
Pelayanan Surat Keterangan
|
||||
</TabsTab>
|
||||
<TabsTab value="Pelayanan Perizinan Berusaha">
|
||||
Pelayanan Perizinan Berusaha
|
||||
</TabsTab>
|
||||
<TabsTab value="Pelayanan Telunjuk Sakti Desa">
|
||||
Pelayanan Telunjuk Sakti Desa
|
||||
</TabsTab>
|
||||
<TabsTab value="Pelayanan Penduduk Non-Permanent">
|
||||
Pelayanan Penduduk Non-Permanent
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
|
||||
<TabsPanel value="Pelayanan Surat Keterangan">
|
||||
<SuratKeterangan />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="Pelayanan Perizinan Berusaha">
|
||||
<PerizinanUsaha />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="Pelayanan Telunjuk Sakti Desa">
|
||||
<TelunjukSaktiDesa />
|
||||
</TabsPanel>
|
||||
<TabsPanel value="Pelayanan Penduduk Non-Permanent">
|
||||
<PendudukNonPermanent />
|
||||
</TabsPanel>
|
||||
</Tabs>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListPendudukNonPermanent() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Penduduk Non-Permanent</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListPendudukNonPermanent;
|
||||
@@ -0,0 +1,35 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, SimpleGrid, Paper, Stack, Title, Group, Button, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListPendudukNonPermanent from './listPage';
|
||||
|
||||
function PendudukNonPermanent() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>Penduduk Non-Permanent</Title>
|
||||
<Text fw={"bold"}>Deskripsi Penduduk Non-Permanent</Text>
|
||||
<DesaEditor showSubmit={false} />
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListPendudukNonPermanent />
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default PendudukNonPermanent;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListPerizinanUsaha() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>List Perizinan Usaha</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListPerizinanUsaha;
|
||||
@@ -0,0 +1,40 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import ListPerizinanUsaha from './listPage';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
|
||||
function PerizinanUsaha() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Stack gap={"xs"}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Pelayanan Perizinan Usaha</Title>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Perizinan Usaha</Text>
|
||||
<DesaEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListPerizinanUsaha />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default PerizinanUsaha;
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListSuratKeterangan() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Surat Keterangan</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListSuratKeterangan;
|
||||
@@ -0,0 +1,48 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, SimpleGrid, Paper, Stack, Title, Button, Group, TextInput, Text, Center, Flex } from '@mantine/core';
|
||||
import { IconUpload } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
import ListSuratKeterangan from './listPage';
|
||||
|
||||
function SuratKeterangan() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Stack gap={"xs"}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Pelayanan Surat Keterangan</Title>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Nama Surat Keterangan</Text>}
|
||||
placeholder='masukkan nama surat keterangan'
|
||||
/>
|
||||
<Text fz={"sm"} fw={"bold"}>Upload Gambar Surat Keterangan</Text>
|
||||
<Box bg={colors['BG-trans']} p={"md"}>
|
||||
<Center>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Center>
|
||||
</Box>
|
||||
<Flex>
|
||||
<Text fz={"xs"} c={"red"}>*</Text>
|
||||
<Text fz={"xs"} c={"dimmed"} fw={"bold"}>Upload foto untuk konten surat keterangan</Text>
|
||||
</Flex>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListSuratKeterangan />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default SuratKeterangan;
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListTelunjukSaktiDesa() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Telunjuk Sakti Desa</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListTelunjukSaktiDesa;
|
||||
@@ -0,0 +1,36 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, SimpleGrid, Paper, Stack, Title, Group, Button, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListTelunjukSaktiDesa from './listPage';
|
||||
|
||||
function TelunjukSaktiDesa() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>Telunjuk Sakti Desa</Title>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Telunjuk Sakti Desa</Text>
|
||||
<DesaEditor showSubmit={false} />
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListTelunjukSaktiDesa />
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default TelunjukSaktiDesa;
|
||||
@@ -1,10 +1,33 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import Penghargaan from './ui/penghargaan/page';
|
||||
import GambarPerhargaan from './ui/gambar_perhargaan/page';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<div>
|
||||
Penghargaan
|
||||
</div>
|
||||
<Box py={10}>
|
||||
<Stack>
|
||||
<Title order={3}>Penghargaan</Title>
|
||||
<Tabs color={colors['blue-button']} variant='pills' defaultValue={"Penghargaan"}>
|
||||
<TabsList p={"xs"} bg={"#BBC8E7FF"}>
|
||||
<TabsTab value="Penghargaan">
|
||||
Penghargaan
|
||||
</TabsTab>
|
||||
<TabsTab value="Gambar Penghargaan">
|
||||
Gambar Penghargaan
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
|
||||
<TabsPanel value="Penghargaan">
|
||||
<Penghargaan/>
|
||||
</TabsPanel>
|
||||
<TabsPanel value="Gambar Penghargaan">
|
||||
<GambarPerhargaan/>
|
||||
</TabsPanel>
|
||||
</Tabs>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListGambarPenghargaan() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Gambar Penghargaan</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListGambarPenghargaan;
|
||||
@@ -0,0 +1,50 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, SimpleGrid, Stack, Title, Text, Group, Button, TextInput, Center } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListGambarPenghargaan from './listPage';
|
||||
import { IconUpload } from '@tabler/icons-react';
|
||||
|
||||
|
||||
function GambarPerhargaan() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Stack gap={"xs"}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Tambah Gambar Penghargaan</Title>
|
||||
<TextInput
|
||||
label="Judul Gambar Penghargaan"
|
||||
placeholder='masukkan judul gambar penghargaan'
|
||||
/>
|
||||
<Text fw={"bold"}>Deskripsi Gambar Penghargaan</Text>
|
||||
<DesaEditor showSubmit={false} />
|
||||
<Box>
|
||||
<Text fw={"bold"}>Upload Gambar Penghargaan</Text>
|
||||
<Box bg={colors['BG-trans']} p={"md"}>
|
||||
<Center>
|
||||
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
|
||||
</Center>
|
||||
</Box>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListGambarPenghargaan />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default GambarPerhargaan;
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListPenghargaan() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Penghargaan</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListPenghargaan;
|
||||
@@ -0,0 +1,40 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import ListPenghargaan from './listPage';
|
||||
|
||||
function Penghargaan() {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Stack>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Penghargaan</Title>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Penghargaan</Text>
|
||||
<DesaEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListPenghargaan/>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Penghargaan;
|
||||
@@ -1,62 +1,75 @@
|
||||
'use client'
|
||||
import { Group, Select, SimpleGrid, Skeleton, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Group, Paper, Select, SimpleGrid, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateDesaPengumuman from '../../_state/desa/pengumuman';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { BeritaEditor } from '../berita/_com/BeritaEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack>
|
||||
<Box>
|
||||
<Title order={3}>Pengumuman</Title>
|
||||
<SimpleGrid cols={{
|
||||
base: 1, md: 2
|
||||
}}>
|
||||
<PengumumanList />
|
||||
<PengumumanCreate />
|
||||
<PengumumanList />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function PengumumanCreate() {
|
||||
const pengumumanState = useProxy(stateDesaPengumuman)
|
||||
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<SelectCategory onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.categoryPengumumanId = val.id
|
||||
}} />
|
||||
<TextInput onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.judul = val.target.value
|
||||
}} label={<Text fz={"sm"} fw={"bold"}>Judul</Text>} placeholder='masukkan judul' />
|
||||
<TextInput onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.deskripsi = val.target.value
|
||||
}} label={<Text fz={"sm"} fw={"bold"}>Deskripsi</Text>} placeholder='masukkan deskripsi' />
|
||||
<BeritaEditor onSubmit={(val) => {
|
||||
pengumumanState.pengumuman.create.form.content = val
|
||||
pengumumanState.pengumuman.create.create()
|
||||
}} />
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
function PengumumanList() {
|
||||
const pengumumanState = useProxy(stateDesaPengumuman)
|
||||
useShallowEffect(() => {
|
||||
pengumumanState.pengumuman.findMany.load()
|
||||
}, [])
|
||||
|
||||
if (!pengumumanState.pengumuman.findMany.data) return <Stack>
|
||||
if (!pengumumanState.pengumuman.findMany.data) return <Stack py={10}>
|
||||
{Array.from({ length: 10 }).map((v, k) => <Skeleton key={k} h={40} />)}
|
||||
</Stack>
|
||||
return <Stack>
|
||||
<Text>Announcement List</Text>
|
||||
{pengumumanState.pengumuman.findMany.data?.map((item) => (
|
||||
<Text key={item.id}>{item.judul}</Text>
|
||||
))}
|
||||
</Stack>;
|
||||
}
|
||||
|
||||
function PengumumanCreate() {
|
||||
const pengumumanState = useProxy(stateDesaPengumuman)
|
||||
|
||||
|
||||
return <Stack gap={"md"}>
|
||||
<Text>Create Some Announcement</Text>
|
||||
<SelectCategory onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.categoryPengumumanId = val.id
|
||||
}} />
|
||||
<TextInput onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.judul = val.target.value
|
||||
}} label={"Judul"} placeholder='masukkan judul' />
|
||||
<TextInput onChange={(val) => {
|
||||
pengumumanState.pengumuman.create.form.deskripsi = val.target.value
|
||||
}} label={"Deskripsi"} placeholder='masukkan deskripsi' />
|
||||
<BeritaEditor onSubmit={(val) => {
|
||||
pengumumanState.pengumuman.create.form.content = val
|
||||
pengumumanState.pengumuman.create.create()
|
||||
}} />
|
||||
</Stack>
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text fz={"xl"} fw={"bold"}>List Pengumuman</Text>
|
||||
{pengumumanState.pengumuman.findMany.data?.map((item) => (
|
||||
<Text key={item.id}>{item.judul}</Text>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectCategory({ onChange }: {
|
||||
@@ -75,7 +88,7 @@ function SelectCategory({ onChange }: {
|
||||
if (!pengumumanState.category.findMany.data) return <Skeleton h={40} />
|
||||
return <Group>
|
||||
{/* {JSON.stringify(pengumumanState.category.findMany.data)} */}
|
||||
<Select placeholder='pilih kategori' label={"select katagori"} data={pengumumanState.category.findMany.data.map((item) => ({
|
||||
<Select placeholder='pilih kategori' label={<Text fz={"sm"} fw={"bold"}>Pilih Kategori</Text>} data={pengumumanState.category.findMany.data.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name
|
||||
}))} onChange={(v) => {
|
||||
|
||||
17
src/app/admin/(dashboard)/desa/potensi/listPage.tsx
Normal file
17
src/app/admin/(dashboard)/desa/potensi/listPage.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListPotensi() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Potensi Desa</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListPotensi;
|
||||
@@ -1,11 +1,40 @@
|
||||
import React from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, TextInput, Title } from '@mantine/core';
|
||||
import ListPotensi from './listPage';
|
||||
|
||||
function Page() {
|
||||
function Potensi() {
|
||||
return (
|
||||
<div>
|
||||
Potensi
|
||||
</div>
|
||||
<Box py={10}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Potensi Desa</Title>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<TextInput
|
||||
label="Nama Potensi"
|
||||
placeholder='masukkan nama potensi'
|
||||
/>
|
||||
<TextInput
|
||||
label="Kategori Potensi"
|
||||
placeholder='masukkan kategori potensi'
|
||||
/>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListPotensi />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Potensi;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
|
||||
function ListPage() {
|
||||
return (
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Sejarah Desa</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListPage;
|
||||
@@ -1,8 +1,31 @@
|
||||
'use client'
|
||||
import stateProfileDesa from '@/app/admin/(dashboard)/_state/desa/profile';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core';
|
||||
import { DesaEditor } from '../../../_com/desaEditor';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import DesaEditorText from '../../../_com/desaEditorText';
|
||||
import ListPage from './listPage';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
|
||||
|
||||
function SejarahDesa() {
|
||||
const stateSejarah = useProxy(stateProfileDesa.Sejarah)
|
||||
|
||||
useShallowEffect(() => {
|
||||
if (!stateSejarah.findById.data) {
|
||||
stateSejarah.findById.initialize()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const submit = () => {
|
||||
if (stateSejarah.findById.data?.id && stateSejarah.findById.data.sejarah) {
|
||||
stateSejarah.update.save({
|
||||
id: stateSejarah.findById.data.id,
|
||||
sejarah: stateSejarah.findById.data.sejarah
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
@@ -11,11 +34,21 @@ function SejarahDesa() {
|
||||
<Stack>
|
||||
<Title order={3}>Sejarah Desa</Title>
|
||||
<Text fw={"bold"}>Deskripsi Sejarah Desa</Text>
|
||||
<DesaEditor showSubmit={false}/>
|
||||
<DesaEditorText
|
||||
key={stateSejarah.findById.data?.id ?? 'new'}
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
if (stateSejarah.findById.data) {
|
||||
stateSejarah.findById.data.sejarah = val
|
||||
}
|
||||
}}
|
||||
initialContent={stateSejarah.findById.data?.sejarah ?? ""}
|
||||
/>
|
||||
<Group>
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
onClick={submit}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
@@ -23,13 +56,7 @@ function SejarahDesa() {
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack>
|
||||
<Title order={3}>List Sejarah Desa</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<ListPage />
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
|
||||
93
src/app/admin/(dashboard)/kesehatan/_com/kesehatanEditor.tsx
Normal file
93
src/app/admin/(dashboard)/kesehatan/_com/kesehatanEditor.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Button, Stack } from '@mantine/core';
|
||||
import { Link, RichTextEditor } from '@mantine/tiptap';
|
||||
import Highlight from '@tiptap/extension-highlight';
|
||||
import SubScript from '@tiptap/extension-subscript';
|
||||
import Superscript from '@tiptap/extension-superscript';
|
||||
import TextAlign from '@tiptap/extension-text-align';
|
||||
import Underline from '@tiptap/extension-underline';
|
||||
import { useEditor } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
|
||||
const content =
|
||||
'<h2 style="text-align: center;">Welcome to Mantine rich text editor</h2><p><code>RichTextEditor</code> component focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. <code>RichTextEditor</code> is based on <a href="https://tiptap.dev/" rel="noopener noreferrer" target="_blank">Tiptap.dev</a> and supports all of its features:</p><ul><li>General text formatting: <strong>bold</strong>, <em>italic</em>, <u>underline</u>, <s>strike-through</s> </li><li>Headings (h1-h6)</li><li>Sub and super scripts (<sup><sup /></sup> and <sub><sub /></sub> tags)</li><li>Ordered and bullet lists</li><li>Text align </li><li>And all <a href="https://tiptap.dev/extensions" target="_blank" rel="noopener noreferrer">other extensions</a></li></ul>';
|
||||
|
||||
export function KesehatanEditor({showSubmit = true} : {
|
||||
showSubmit: boolean
|
||||
}) {
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Underline,
|
||||
Link,
|
||||
Superscript,
|
||||
SubScript,
|
||||
Highlight,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
],
|
||||
immediatelyRender: false,
|
||||
content,
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<RichTextEditor editor={editor}>
|
||||
<RichTextEditor.Toolbar sticky stickyOffset={60}>
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Bold />
|
||||
<RichTextEditor.Italic />
|
||||
<RichTextEditor.Underline />
|
||||
<RichTextEditor.Strikethrough />
|
||||
<RichTextEditor.ClearFormatting />
|
||||
<RichTextEditor.Highlight />
|
||||
<RichTextEditor.Code />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.H1 />
|
||||
<RichTextEditor.H2 />
|
||||
<RichTextEditor.H3 />
|
||||
<RichTextEditor.H4 />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Blockquote />
|
||||
<RichTextEditor.Hr />
|
||||
<RichTextEditor.BulletList />
|
||||
<RichTextEditor.OrderedList />
|
||||
<RichTextEditor.Subscript />
|
||||
<RichTextEditor.Superscript />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Link />
|
||||
<RichTextEditor.Unlink />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.AlignLeft />
|
||||
<RichTextEditor.AlignCenter />
|
||||
<RichTextEditor.AlignJustify />
|
||||
<RichTextEditor.AlignRight />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Undo />
|
||||
<RichTextEditor.Redo />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
</RichTextEditor.Toolbar>
|
||||
|
||||
<RichTextEditor.Content />
|
||||
</RichTextEditor>
|
||||
{showSubmit && (
|
||||
<Button
|
||||
mt={10}
|
||||
bg={colors['blue-button']}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
'use client'
|
||||
import { Button, Stack } from '@mantine/core';
|
||||
import { Link, RichTextEditor } from '@mantine/tiptap';
|
||||
import Highlight from '@tiptap/extension-highlight';
|
||||
import SubScript from '@tiptap/extension-subscript';
|
||||
import Superscript from '@tiptap/extension-superscript';
|
||||
import TextAlign from '@tiptap/extension-text-align';
|
||||
import Underline from '@tiptap/extension-underline';
|
||||
import { useEditor } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
|
||||
|
||||
function KesehatanEditorText({ onSubmit, onChange, showSubmit = true, initialContent = '', }: {
|
||||
onSubmit?: (val: string) => void,
|
||||
onChange: (val: string) => void,
|
||||
showSubmit?: boolean,
|
||||
initialContent?: string }) {
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Underline,
|
||||
Link,
|
||||
Superscript,
|
||||
SubScript,
|
||||
Highlight,
|
||||
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
||||
],
|
||||
immediatelyRender: false,
|
||||
content: initialContent,
|
||||
onUpdate : ({editor}) => {
|
||||
onChange(editor.getHTML())
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<RichTextEditor editor={editor}>
|
||||
<RichTextEditor.Toolbar sticky stickyOffset={60}>
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Bold />
|
||||
<RichTextEditor.Italic />
|
||||
<RichTextEditor.Underline />
|
||||
<RichTextEditor.Strikethrough />
|
||||
<RichTextEditor.ClearFormatting />
|
||||
<RichTextEditor.Highlight />
|
||||
<RichTextEditor.Code />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.H1 />
|
||||
<RichTextEditor.H2 />
|
||||
<RichTextEditor.H3 />
|
||||
<RichTextEditor.H4 />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Blockquote />
|
||||
<RichTextEditor.Hr />
|
||||
<RichTextEditor.BulletList />
|
||||
<RichTextEditor.OrderedList />
|
||||
<RichTextEditor.Subscript />
|
||||
<RichTextEditor.Superscript />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Link />
|
||||
<RichTextEditor.Unlink />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.AlignLeft />
|
||||
<RichTextEditor.AlignCenter />
|
||||
<RichTextEditor.AlignJustify />
|
||||
<RichTextEditor.AlignRight />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
|
||||
<RichTextEditor.ControlsGroup>
|
||||
<RichTextEditor.Undo />
|
||||
<RichTextEditor.Redo />
|
||||
</RichTextEditor.ControlsGroup>
|
||||
</RichTextEditor.Toolbar>
|
||||
|
||||
<RichTextEditor.Content />
|
||||
</RichTextEditor>
|
||||
{showSubmit && (
|
||||
<Button onClick={() => {
|
||||
if (!editor) return
|
||||
onSubmit?.(editor?.getHTML())
|
||||
}}>Submit</Button>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default KesehatanEditorText;
|
||||
@@ -1,21 +1,24 @@
|
||||
'use client'
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function DoctorSignUI() {
|
||||
const doctorSign = useProxy(stateArtikelKesehatan.doctorSign)
|
||||
return (
|
||||
<Box>
|
||||
<Text fw={"bold"}>Kapan Harus ke Dokter</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
doctorSign.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Kapan Harus ke Dokter</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
doctorSign.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
'use client'
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function FirstAidUI() {
|
||||
const firstAidState = useProxy(stateArtikelKesehatan.firstAid)
|
||||
return (
|
||||
<Box>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Title Pertolongan Pertama</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Judul Pertolongan Pertama</Text>}
|
||||
placeholder="Masukkan judul"
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
firstAidState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
'use client'
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function IntoductionUI() {
|
||||
const introduction = useProxy(stateArtikelKesehatan.introduction)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Text fw={"bold"}>Pendahuluan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
introduction.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text fw={"bold"}>Pendahuluan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
introduction.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,38 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function MythFactUI() {
|
||||
const mythFact = useProxy(stateArtikelKesehatan.mythFact)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Title Pertolongan Pertama Penyakit</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Mitos</Text>}
|
||||
placeholder="Masukkan mitos"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.mitos = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Fakta</Text>}
|
||||
placeholder="Masukkan fakta"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.fakta = val.target.value
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Judul Pertolongan Pertama Penyakit</Text>}
|
||||
placeholder="Masukkan judul"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Mitos</Text>}
|
||||
placeholder="Masukkan mitos"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.mitos = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"}>Fakta</Text>}
|
||||
placeholder="Masukkan fakta"
|
||||
onChange={(val) => {
|
||||
mythFact.create.form.fakta = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import { Box, Button, Center, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Center, Group, Paper, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import IntoductionUI from './introduction/page';
|
||||
import SymptomUI from './symptom/page';
|
||||
import PreventionUI from './prevention/page';
|
||||
@@ -39,19 +39,25 @@ function ArtikelKesehatan() {
|
||||
base: 1, md: 2
|
||||
}}>
|
||||
<Box >
|
||||
<Title order={3}>Artikel Kesehatan</Title>
|
||||
<IntoductionUI />
|
||||
<SymptomUI />
|
||||
<PreventionUI />
|
||||
<FirstAidUI />
|
||||
<MythFactUI />
|
||||
<DoctorSignUI />
|
||||
<Button mt={10} onClick={submitAllForms}>Submit</Button>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Artikel Kesehatan</Title>
|
||||
<IntoductionUI />
|
||||
<SymptomUI />
|
||||
<PreventionUI />
|
||||
<FirstAidUI />
|
||||
<MythFactUI />
|
||||
<DoctorSignUI />
|
||||
<Group>
|
||||
<Button bg={colors['blue-button']} mt={10} onClick={submitAllForms}>Submit</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Title order={3}>List Artikel Kesehatan</Title>
|
||||
<AllList />
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Data Artikel Kesehatan</Title>
|
||||
<AllList />
|
||||
</Stack>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
@@ -78,71 +84,88 @@ function AllList() {
|
||||
) return <Stack>
|
||||
{Array.from({ length: 10 }).map((v, k) => <Skeleton key={k} h={40} />)}
|
||||
</Stack>
|
||||
return <Stack>
|
||||
<Title order={4}>Intoduction</Title>
|
||||
{listState.introduction.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
return <Stack gap={"xs"}>
|
||||
{/* Introduction */}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Pendahuluan</Title>
|
||||
{listState.introduction.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
{/* Symptom */}
|
||||
{listState.symptom.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Gejala Penyakit</Title>
|
||||
{listState.symptom.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
{/* Prevention */}
|
||||
{listState.prevention.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Pencegahan Penyakit</Title>
|
||||
{listState.prevention.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
{/* First Aid */}
|
||||
{listState.firstAid.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Pertolongan Pertama</Title>
|
||||
{listState.firstAid.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}></Text>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
{/* Myth Fact */}
|
||||
{listState.mythFact.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead >
|
||||
<TableTr >
|
||||
<TableTh >
|
||||
<Center>Mitos</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Fakta</Center>
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody >
|
||||
<TableTr>
|
||||
<TableTd ta="center">{item.mitos}</TableTd>
|
||||
<TableTd ta="center">{item.fakta}</TableTd>
|
||||
</TableTr>
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Mitos vs Fakta</Title>
|
||||
{listState.mythFact.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Title order={4}>{item.title}</Title>
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead >
|
||||
<TableTr >
|
||||
<TableTh >
|
||||
<Center>Mitos</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Fakta</Center>
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody >
|
||||
<TableTr>
|
||||
<TableTd ta="center">{item.mitos}</TableTd>
|
||||
<TableTd ta="center">{item.fakta}</TableTd>
|
||||
</TableTr>
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
{/* Doctor Sign */}
|
||||
<Title order={4}>Kapan Harus Ke Dokter?</Title>
|
||||
{listState.doctorSign.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }}/>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Kapan Harus Ke Dokter?</Title>
|
||||
{listState.doctorSign.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
</Stack>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,33 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function PreventionUI() {
|
||||
const preventionState = useProxy(stateArtikelKesehatan.prevention)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Title Pencegahan Penyakit</Text>}
|
||||
placeholder="Masukkan title"
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Judul Pencegahan Penyakit</Text>}
|
||||
placeholder="Masukkan judul"
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
preventionState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
'use client'
|
||||
import stateArtikelKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/artikelKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function SymptomUI() {
|
||||
const symptomState = useProxy(stateArtikelKesehatan.symptom)
|
||||
return (
|
||||
<Box py={10}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Title Gejala Penyakit</Text>}
|
||||
placeholder='masukkan title'
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label={<Text fw={"bold"}>Judul Gejala Penyakit</Text>}
|
||||
placeholder='masukkan judul'
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.title = val.target.value
|
||||
}}
|
||||
/>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
symptomState.create.form.content = val
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function DokterDanTenagaMedis() {
|
||||
const dokterdantenagamedisState = useProxy(stateFasilitasKesehatan.dokterdantenagamedis)
|
||||
return (
|
||||
<Box>
|
||||
<Text fw={"bold"}>Dokter & Tenaga Medis</Text>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text fw={"bold"}>Dokter & Tenaga Medis</Text>
|
||||
<TextInput
|
||||
label="Nama Dokter"
|
||||
placeholder='masukkan nama dokter'
|
||||
@@ -29,6 +32,8 @@ function DokterDanTenagaMedis() {
|
||||
dokterdantenagamedisState.create.form.jadwal = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function FasilitasPendukung() {
|
||||
const fasilitaspendukungState = useProxy(stateFasilitasKesehatan.fasilitaspendukung)
|
||||
return <Box>
|
||||
<Text fw={"bold"}>Fasilitas Pendukung</Text>
|
||||
<KesehatanEditor
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Fasilitas Pendukung</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
fasilitaspendukungState.create.form.content = val;
|
||||
}} />
|
||||
</Paper>
|
||||
</Box>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,40 @@
|
||||
'use client'
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function InformasiUmum() {
|
||||
const infromasiState = useProxy(stateFasilitasKesehatan.informasiumum)
|
||||
return<Box>
|
||||
<Text fw={"bold"}>Informasi Umum</Text>
|
||||
<TextInput
|
||||
label="Fasilitas"
|
||||
placeholder='masukkan nama fasilitas kesehatan'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.fasilitas = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder='masukkan alamat'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.alamat = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label="Jam Operasional"
|
||||
placeholder='masukkan jam operasional'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.jamOperasional = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
return <Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Informasi Umum</Text>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label="Fasilitas"
|
||||
placeholder='masukkan nama fasilitas kesehatan'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.fasilitas = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder='masukkan alamat'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.alamat = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label="Jam Operasional"
|
||||
placeholder='masukkan jam operasional'
|
||||
onChange={(val) => {
|
||||
infromasiState.create.form.jamOperasional = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
}
|
||||
|
||||
export default InformasiUmum;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
'use client'
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function LayananUnggulan() {
|
||||
const informasiumumState = useProxy(stateFasilitasKesehatan.layananunggulan)
|
||||
return <Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Layanan Unggulan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
informasiumumState.create.form.content = val;
|
||||
}} />
|
||||
</Paper>
|
||||
</Box>
|
||||
;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Center, Paper, SimpleGrid, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import DokterDanTenagaMedis from './dokterdantenagamedis/page';
|
||||
@@ -91,7 +91,7 @@ function FasilitasKesehatan() {
|
||||
}}>
|
||||
<Box>
|
||||
<Stack gap={'xs'}>
|
||||
<Title order={3}>Fasilitas Kesehatan</Title>
|
||||
<Title order={4}>Tambah Fasilitas Kesehatan</Title>
|
||||
{/* Informasi Umum */}
|
||||
<InformasiUmum />
|
||||
{/* Layanan Unggulan */}
|
||||
@@ -110,7 +110,7 @@ function FasilitasKesehatan() {
|
||||
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>List Fasilitas Kesehatan</Title>
|
||||
<Title order={4}>Data Fasilitas Kesehatan</Title>
|
||||
<AllList />
|
||||
</Stack>
|
||||
</Box>
|
||||
@@ -141,100 +141,113 @@ function AllList() {
|
||||
{Array.from({ length: 10 }).map((v, k) => <Skeleton key={k} h={40} />)}
|
||||
</Stack>
|
||||
return <Stack>
|
||||
<Title order={4}>Informasi Umum</Title>
|
||||
{allListState.informasiumum.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Informasi Umum</Title>
|
||||
{allListState.informasiumum.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
|
||||
<Text>{item.fasilitas}</Text>
|
||||
<Text>{item.alamat}</Text>
|
||||
<Text>{item.jamOperasional}</Text>
|
||||
</Box>
|
||||
))}
|
||||
<Text>{item.fasilitas}</Text>
|
||||
<Text>{item.alamat}</Text>
|
||||
<Text>{item.jamOperasional}</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Layanan Unggulan</Title>
|
||||
{allListState.layananunggulan.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Layanan Unggulan</Title>
|
||||
{allListState.layananunggulan.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
|
||||
|
||||
<Title order={4}>Dokter & Tenaga Medis</Title>
|
||||
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead >
|
||||
<TableTr >
|
||||
<TableTh >
|
||||
<Center>Nama</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Specialist</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Jadwal</Center>
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody >
|
||||
{allListState.dokterdantenagamedis.findMany.data?.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd ta="center">{item.name}</TableTd>
|
||||
<TableTd ta="center">Specialist {item.specialist}</TableTd>
|
||||
<TableTd ta="center">{item.jadwal}</TableTd>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Dokter & Tenaga Medis</Title>
|
||||
|
||||
<Table
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead >
|
||||
<TableTr >
|
||||
<TableTh >
|
||||
<Center>Nama</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Specialist</Center>
|
||||
</TableTh>
|
||||
<TableTh >
|
||||
<Center>Jadwal</Center>
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</TableThead>
|
||||
<TableTbody >
|
||||
{allListState.dokterdantenagamedis.findMany.data?.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd ta="center">{item.name}</TableTd>
|
||||
<TableTd ta="center">Specialist {item.specialist}</TableTd>
|
||||
<TableTd ta="center">{item.jadwal}</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Fasilitas Pendukung</Title>
|
||||
{allListState.fasilitaspendukung.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
|
||||
<Title order={4}>Tarif & Layanan</Title>
|
||||
<Table
|
||||
suppressHydrationWarning
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>
|
||||
Layanan
|
||||
</TableTh>
|
||||
<TableTh>
|
||||
Tarif
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{allListState.tarifdanlayanan.findMany.data?.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.layanan}</TableTd>
|
||||
<TableTd>Rp.{item.tarif}</TableTd>
|
||||
<Title order={4}>Fasilitas Pendukung</Title>
|
||||
{allListState.fasilitaspendukung.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Tarif & Layanan</Title>
|
||||
<Table
|
||||
suppressHydrationWarning
|
||||
striped
|
||||
highlightOnHover
|
||||
withTableBorder
|
||||
withColumnBorders
|
||||
bg={colors['white-1']}
|
||||
>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>
|
||||
Layanan
|
||||
</TableTh>
|
||||
<TableTh>
|
||||
Tarif
|
||||
</TableTh>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{allListState.tarifdanlayanan.findMany.data?.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.layanan}</TableTd>
|
||||
<TableTd>Rp.{item.tarif}</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Prosedur Pendaftaran</Title>
|
||||
{allListState.prosedurpendaftaran.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{__html: item.content}}/>
|
||||
</Box>
|
||||
))}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
|
||||
<Title order={4}>Prosedur Pendaftaran</Title>
|
||||
{allListState.prosedurpendaftaran.findMany.data?.map((item) => (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
))}
|
||||
</Paper>
|
||||
</Stack>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Text, Paper } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function ProsedurPendaftaran() {
|
||||
const prosedurpendaftaranState = useProxy(stateFasilitasKesehatan.prosedurpendaftaran)
|
||||
return <Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Prosedur Pendaftaran</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
prosedurpendaftaranState.create.form.content = val;
|
||||
}} />
|
||||
</Box>
|
||||
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
prosedurpendaftaranState.create.form.content = val;
|
||||
}} />
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
}
|
||||
|
||||
export default ProsedurPendaftaran;
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
import stateFasilitasKesehatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/fasilitasKesehatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Text, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function TarifDanLayanan() {
|
||||
const tarifdanlayanan = useProxy(stateFasilitasKesehatan.tarifdanlayanan)
|
||||
return <Box>
|
||||
<Text fw={"bold"}>Tarif & Layanan</Text>
|
||||
<TextInput
|
||||
label="Tarif"
|
||||
placeholder='masukkan tarif'
|
||||
onChange={(val) => {
|
||||
tarifdanlayanan.create.form.tarif = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label="Layanan"
|
||||
placeholder='masukkan layanan'
|
||||
onChange={(val) => {
|
||||
tarifdanlayanan.create.form.layanan = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Text fw={"bold"}>Tarif & Layanan</Text>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label="Tarif"
|
||||
placeholder='masukkan tarif'
|
||||
onChange={(val) => {
|
||||
tarifdanlayanan.create.form.tarif = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
mb={10}
|
||||
label="Layanan"
|
||||
placeholder='masukkan layanan'
|
||||
onChange={(val) => {
|
||||
tarifdanlayanan.create.form.layanan = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
}
|
||||
|
||||
export default TarifDanLayanan;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
'use client'
|
||||
import stategrafikKepuasan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/grafikKepuasan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { Box, Button, Group, Paper, Skeleton, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
@@ -35,54 +35,65 @@ function GrafikHasilKepuasan() {
|
||||
|
||||
|
||||
return (
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Grafik Hasil Kepuasan</Title>
|
||||
<Box>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Label"
|
||||
placeholder='Masukkan label yang diinginkan'
|
||||
value={grafikkepuasan.create.form.label}
|
||||
onChange={(val) => {
|
||||
grafikkepuasan.create.form.label = val.currentTarget.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Jumlah Penderita"
|
||||
type='number'
|
||||
placeholder='Masukkan jumlah penderita'
|
||||
value={grafikkepuasan.create.form.jumlah}
|
||||
onChange={(val) => {
|
||||
grafikkepuasan.create.form.jumlah = val.currentTarget.value
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button mt={10}
|
||||
onClick={async () => {
|
||||
await grafikkepuasan.create.create();
|
||||
await grafikkepuasan.findMany.load();
|
||||
if (grafikkepuasan.findMany.data) {
|
||||
setChartData(grafikkepuasan.findMany.data);
|
||||
}
|
||||
}}
|
||||
>Submit</Button>
|
||||
</Group>
|
||||
<Box h={400} w={{ base: "100%", md: "80%" }}>
|
||||
<Title py={15} order={3}>Data Kelahiran & Kematian</Title>
|
||||
<BarChart
|
||||
width={isMobile ? 450 : isTablet ? 600 : 900}
|
||||
height={380}
|
||||
data={chartData}
|
||||
>
|
||||
<XAxis dataKey="label" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="jumlah" fill={colors['blue-button']} name="Jumlah" />
|
||||
</BarChart>
|
||||
</Box>
|
||||
<Stack py={10} gap={"xs"}>
|
||||
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Tambah Grafik Hasil Kepuasan</Title>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label="Label"
|
||||
placeholder='Masukkan label yang diinginkan'
|
||||
value={grafikkepuasan.create.form.label}
|
||||
onChange={(val) => {
|
||||
grafikkepuasan.create.form.label = val.currentTarget.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Jumlah Penderita"
|
||||
type='number'
|
||||
placeholder='Masukkan jumlah penderita'
|
||||
value={grafikkepuasan.create.form.jumlah}
|
||||
onChange={(val) => {
|
||||
grafikkepuasan.create.form.jumlah = val.currentTarget.value
|
||||
}}
|
||||
/>
|
||||
<Group>
|
||||
<Button bg={colors['blue-button']} mt={10}
|
||||
onClick={async () => {
|
||||
await grafikkepuasan.create.create();
|
||||
await grafikkepuasan.findMany.load();
|
||||
if (grafikkepuasan.findMany.data) {
|
||||
setChartData(grafikkepuasan.findMany.data);
|
||||
}
|
||||
}}
|
||||
>Submit</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
{!chartData ? (
|
||||
<Box style={{ width: '100%', minWidth: 300, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title py={15} order={4}>Data Hasil Kepuasan</Title>
|
||||
<Skeleton h={400} />
|
||||
</Paper>
|
||||
</Box>
|
||||
) : (
|
||||
<Box style={{ width: '100%', minWidth: 300, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title py={15} order={4}>Data Hasil Kepuasan</Title>
|
||||
<BarChart
|
||||
width={isMobile ? 250 : isTablet ? 300 : 350}
|
||||
height={380}
|
||||
data={chartData}
|
||||
>
|
||||
<XAxis dataKey="label" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="jumlah" fill={colors['blue-button']} name="Jumlah" />
|
||||
</BarChart>
|
||||
</Paper>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function DeskripsiKegiatan() {
|
||||
const deskripsiKegiatanState = useProxy(stateJadwalKegiatan.deskripsiKegiatan)
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Deskripsi Kegiatan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
deskripsiKegiatanState.create.form.deskripsi = val
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text pt={10} fw={"bold"}>Deskripsi Kegiatan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
deskripsiKegiatanState.create.form.deskripsi = val
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function DokumenYangDiperlukan() {
|
||||
const dokumenDiperlukan = useProxy(stateJadwalKegiatan.dokumenjadwalkegiatan)
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Dokumen Yang Diperlukan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val)=> {
|
||||
dokumenDiperlukan.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text pt={10} fw={"bold"}>Dokumen Yang Diperlukan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
dokumenDiperlukan.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function InformasiKegiatan() {
|
||||
const informasiKegiatanState = useProxy(stateJadwalKegiatan.informasiKegiatan)
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Informasi Kegiatan</Text>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Informasi Kegiatan</Title>
|
||||
<TextInput
|
||||
label="Nama Kegiatan"
|
||||
placeholder="Masukkan nama kegiatan"
|
||||
@@ -35,6 +38,8 @@ function InformasiKegiatan() {
|
||||
informasiKegiatanState.create.form.lokasi = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function LayananTersedia() {
|
||||
const layananTersediaState = useProxy(stateJadwalKegiatan.layanantersedia)
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Layanan Yang Tersedia</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
layananTersediaState.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text pt={10} fw={"bold"}>Layanan Yang Tersedia</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
layananTersediaState.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Button, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { Box, Button, Paper, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import DeskripsiKegiatan from './deskripsi_kegiatan/page';
|
||||
@@ -9,6 +9,7 @@ import InformasiKegiatan from './informasi_kegiatan/page';
|
||||
import LayananTersedia from './layanan_yang_tersedia/page';
|
||||
import Pendaftaran from './pendaftaran/page';
|
||||
import SyaratDanKetentuan from './syarat_dan_ketentuan/page';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function JadwalKegiatan() {
|
||||
const allState = useProxy(stateJadwalKegiatan)
|
||||
@@ -54,21 +55,25 @@ function JadwalKegiatan() {
|
||||
base: 1, md: 2
|
||||
}}>
|
||||
<Box>
|
||||
<Title order={3}>Jadwal Kegiatan</Title>
|
||||
<InformasiKegiatan />
|
||||
<DeskripsiKegiatan />
|
||||
<LayananTersedia />
|
||||
<SyaratDanKetentuan />
|
||||
<DokumenYangDiperlukan />
|
||||
<Pendaftaran />
|
||||
<Button mt={10} onClick={submitAllForms}>
|
||||
Submit
|
||||
</Button>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Tambah Jadwal Kegiatan</Title>
|
||||
<InformasiKegiatan />
|
||||
<DeskripsiKegiatan />
|
||||
<LayananTersedia />
|
||||
<SyaratDanKetentuan />
|
||||
<DokumenYangDiperlukan />
|
||||
<Pendaftaran />
|
||||
<Button mt={10} onClick={submitAllForms}>
|
||||
Submit
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Title order={3}>List Jadwal Kegiatan</Title>
|
||||
<AllList />
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Data Jadwal Kegiatan</Title>
|
||||
<AllList />
|
||||
</Stack>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
@@ -103,68 +108,82 @@ function AllList() {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={4}>Informasi Kegiatan</Title>
|
||||
{allList.informasiKegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text>{item.name}</Text>
|
||||
<Text>{item.tanggal}</Text>
|
||||
<Text>{item.waktu}</Text>
|
||||
<Text>{item.lokasi}</Text>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Stack gap={"xs"}>
|
||||
|
||||
<Title order={4}>Deskripsi Kegiatan</Title>
|
||||
{allList.deskripsiKegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Informasi Kegiatan</Title>
|
||||
{allList.informasiKegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text>{item.name}</Text>
|
||||
<Text>{item.tanggal}</Text>
|
||||
<Text>{item.waktu}</Text>
|
||||
<Text>{item.lokasi}</Text>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Layanan Yang Tersedia</Title>
|
||||
{allList.layanantersedia.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
|
||||
<Title order={4}>Syarat dan Ketentuan</Title>
|
||||
{allList.syaratketentuan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Title order={4}>Deskripsi Kegiatan</Title>
|
||||
{allList.deskripsiKegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Dokumen Yang Diperlukan</Title>
|
||||
{allList.dokumenjadwalkegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Layanan Yang Tersedia</Title>
|
||||
{allList.layanantersedia.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
|
||||
<Title order={4}>Pendaftaran</Title>
|
||||
{allList.pendaftaranjadwal.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text>{item.name}</Text>
|
||||
<Text>{item.tanggal}</Text>
|
||||
<Text>{item.namaOrangtua}</Text>
|
||||
<Text>{item.nomor}</Text>
|
||||
<Text>{item.alamat}</Text>
|
||||
<Text>{item.catatan}</Text>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Syarat dan Ketentuan</Title>
|
||||
{allList.syaratketentuan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Dokumen Yang Diperlukan</Title>
|
||||
{allList.dokumenjadwalkegiatan.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text dangerouslySetInnerHTML={{ __html: item.content }} />
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Pendaftaran</Title>
|
||||
{allList.pendaftaranjadwal.findMany.data?.map((item) => {
|
||||
return (
|
||||
<Box key={item.id}>
|
||||
<Text>{item.name}</Text>
|
||||
<Text>{item.tanggal}</Text>
|
||||
<Text>{item.namaOrangtua}</Text>
|
||||
<Text>{item.nomor}</Text>
|
||||
<Text>{item.alamat}</Text>
|
||||
<Text>{item.catatan}</Text>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</Paper>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,56 +1,61 @@
|
||||
'use client'
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text, Textarea, TextInput } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, Stack, Text, Textarea, TextInput } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function Pendaftaran() {
|
||||
const pendaftaran = useProxy(stateJadwalKegiatan.pendaftaranjadwal)
|
||||
const pendaftaran = useProxy(stateJadwalKegiatan.pendaftaranjadwal)
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Pendaftaran</Text>
|
||||
<TextInput
|
||||
label='Nama Balita'
|
||||
placeholder='Masukkan nama balita'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.name = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Tanggal'
|
||||
placeholder='Masukkan tanggal'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.tanggal = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Nama Orang Tua / Wali'
|
||||
placeholder='Masukkan nama orang tua / wali'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.namaOrangtua = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='No. Telepon'
|
||||
placeholder='Masukkan no. telepon'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.nomor = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Alamat'
|
||||
placeholder='Masukkan alamat'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.alamat = val.target.value
|
||||
}}
|
||||
/>
|
||||
<Textarea
|
||||
label='Catatan Khusus (Opsional)'
|
||||
placeholder='Masukkan catatan khusus'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.catatan = val.target.value
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text pt={10} fw={"bold"}>Pendaftaran</Text>
|
||||
<TextInput
|
||||
label='Nama Balita'
|
||||
placeholder='Masukkan nama balita'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.name = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Tanggal'
|
||||
placeholder='Masukkan tanggal'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.tanggal = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Nama Orang Tua / Wali'
|
||||
placeholder='Masukkan nama orang tua / wali'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.namaOrangtua = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='No. Telepon'
|
||||
placeholder='Masukkan no. telepon'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.nomor = val.target.value
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label='Alamat'
|
||||
placeholder='Masukkan alamat'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.alamat = val.target.value
|
||||
}}
|
||||
/>
|
||||
<Textarea
|
||||
label='Catatan Khusus (Opsional)'
|
||||
placeholder='Masukkan catatan khusus'
|
||||
onChange={(val) => {
|
||||
pendaftaran.create.form.catatan = val.target.value
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import stateJadwalKegiatan from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/jadwalKegiatan';
|
||||
import { Box, Text } from '@mantine/core';
|
||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
import colors from '@/con/colors';
|
||||
|
||||
function SyaratDanKetentuan() {
|
||||
const syaratKetentuan = useProxy(stateJadwalKegiatan.syaratketentuan)
|
||||
return (
|
||||
<Box>
|
||||
<Text pt={10} fw={"bold"}>Syarat dan Ketentuan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
syaratKetentuan.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Text pt={10} fw={"bold"}>Syarat dan Ketentuan</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
onChange={(val) => {
|
||||
syaratKetentuan.create.form.content = val;
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import statePersentase from '@/app/admin/(dashboard)/_state/kesehatan/data_kesehatan_warga/persentaseKelahiran';
|
||||
import { Box, Button, Stack, TextInput, Title } from '@mantine/core';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, Skeleton, Stack, TextInput, Title } from '@mantine/core';
|
||||
import { useMediaQuery, useShallowEffect } from '@mantine/hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Bar, BarChart, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
@@ -32,76 +33,90 @@ function PersentaseDataKelahiranKematian() {
|
||||
<Stack py={10}>
|
||||
{/* Form Input */}
|
||||
<Box>
|
||||
<Title order={3}>Persentase Data Kelahiran & Kematian</Title>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Tahun"
|
||||
type="number"
|
||||
value={persentase.create.form.tahun}
|
||||
placeholder="Masukkan tahun"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.tahun = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Kematian Kasar"
|
||||
type="number"
|
||||
value={persentase.create.form.kematianKasar}
|
||||
placeholder="Masukkan kematian kasar"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kematianKasar = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Kematian Bayi"
|
||||
type="number"
|
||||
value={persentase.create.form.kematianBayi}
|
||||
placeholder="Masukkan kematian bayi"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kematianBayi = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
label="Kelahiran Kasar"
|
||||
type="number"
|
||||
value={persentase.create.form.kelahiranKasar}
|
||||
placeholder="Masukkan kelahiran kasar"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kelahiranKasar = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
mt={10}
|
||||
onClick={async () => {
|
||||
await persentase.create.create();
|
||||
await persentase.findMany.load();
|
||||
if (persentase.findMany.data) {
|
||||
setChartData(persentase.findMany.data);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
|
||||
<Title order={4}>Tambah Persentase Data Kelahiran & Kematian</Title>
|
||||
<Stack gap={"xs"}>
|
||||
<TextInput
|
||||
label="Tahun"
|
||||
type="number"
|
||||
value={persentase.create.form.tahun}
|
||||
placeholder="Masukkan tahun"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.tahun = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Kematian Kasar"
|
||||
type="number"
|
||||
value={persentase.create.form.kematianKasar}
|
||||
placeholder="Masukkan kematian kasar"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kematianKasar = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Kematian Bayi"
|
||||
type="number"
|
||||
value={persentase.create.form.kematianBayi}
|
||||
placeholder="Masukkan kematian bayi"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kematianBayi = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<TextInput
|
||||
label="Kelahiran Kasar"
|
||||
type="number"
|
||||
value={persentase.create.form.kelahiranKasar}
|
||||
placeholder="Masukkan kelahiran kasar"
|
||||
onChange={(val) => {
|
||||
persentase.create.form.kelahiranKasar = val.currentTarget.value;
|
||||
}}
|
||||
/>
|
||||
<Group>
|
||||
<Button
|
||||
bg={colors['blue-button']}
|
||||
mt={10}
|
||||
onClick={async () => {
|
||||
await persentase.create.create();
|
||||
await persentase.findMany.load();
|
||||
if (persentase.findMany.data) {
|
||||
setChartData(persentase.findMany.data);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Chart */}
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Title pb={10} order={3}>Data Kelahiran & Kematian</Title>
|
||||
{mounted && chartData.length > 0 && (
|
||||
<BarChart width={isMobile ? 450 : isTablet ? 600 : 900} height={380} data={chartData} >
|
||||
<XAxis dataKey="tahun" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="kematianKasar" fill="#f03e3e" name="Kematian Kasar" />
|
||||
<Bar dataKey="kematianBayi" fill="#ff922b" name="Kematian Bayi" />
|
||||
<Bar dataKey="kelahiranKasar" fill="#4dabf7" name="Kelahiran Kasar" />
|
||||
</BarChart>
|
||||
)}
|
||||
</Box>
|
||||
{!mounted && !chartData ? (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={3}>Data Kelahiran & Kematian</Title>
|
||||
<Skeleton h={400} />
|
||||
</Paper>
|
||||
</Box>
|
||||
) : (
|
||||
<Box style={{ width: '100%', minWidth: 300, height: 400, minHeight: 300 }}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<Title pb={10} order={4}>Data Kelahiran & Kematian</Title>
|
||||
{mounted && chartData.length > 0 && (
|
||||
<BarChart width={isMobile ? 450 : isTablet ? 500 : 550} height={350} data={chartData} >
|
||||
<XAxis dataKey="tahun" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Bar dataKey="kematianKasar" fill="#f03e3e" name="Kematian Kasar" />
|
||||
<Bar dataKey="kematianBayi" fill="#ff922b" name="Kematian Bayi" />
|
||||
<Bar dataKey="kelahiranKasar" fill="#4dabf7" name="Kelahiran Kasar" />
|
||||
</BarChart>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Tabs, TabsList, TabsPanel, TabsTab } from '@mantine/core';
|
||||
import { Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import ArtikelKesehatan from './_ui/artikel_kesehatan/page';
|
||||
import FasilitasKesehatan from './_ui/fasilitas_kesehatan/page';
|
||||
import GrafikHasilKepuasan from './_ui/grafik_hasil_kepuasan/page';
|
||||
@@ -10,8 +10,9 @@ import PersentaseDataKelahiranKematian from './_ui/persentase_data_kelahiran_kem
|
||||
function Page() {
|
||||
return (
|
||||
<Stack>
|
||||
<Title order={3}>Data Kesehatan Warga</Title>
|
||||
<Tabs color={colors['blue-button']} variant='pills' defaultValue={"Persentase Kelahiran & Kematian"}>
|
||||
<TabsList >
|
||||
<TabsList bg={colors['BG-trans']} p={'xs'}>
|
||||
<TabsTab value="Persentase Kelahiran & Kematian">
|
||||
Persentase Kelahiran & Kematian
|
||||
</TabsTab>
|
||||
|
||||
@@ -1,11 +1,54 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Group, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { KesehatanEditor } from '../_com/kesehatanEditor';
|
||||
|
||||
function Page() {
|
||||
function Posyandu() {
|
||||
return (
|
||||
<div>
|
||||
Posyandu
|
||||
</div>
|
||||
<Box>
|
||||
<Title order={3}>Kesehatan</Title>
|
||||
<SimpleGrid py={10} cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={3}>Posyandu</Title>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Nama Posyandu</Text>}
|
||||
placeholder='masukkan nama posyandu'
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fz={"sm"} fw={"bold"}>Nomor Telepon Posyandu</Text>}
|
||||
placeholder='masukkan nomor telepon posyandu'
|
||||
/>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Deskripsi Posyandu</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"sm"} fw={"bold"}>Pelayanan Posyandu</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Group>
|
||||
<Button bg={colors['blue-button']}>Submit</Button>
|
||||
</Group>
|
||||
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack>
|
||||
<Title order={3}>Preview Data Posyandu</Title>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Posyandu;
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
import React from 'react';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||
import UpdatePuskesmas from './ui/Edit-Puskesmas/updatePuskesmas';
|
||||
import CreatePuskesmas from './ui/Tambah-Puskesmas/createPuskesmas';
|
||||
|
||||
function Page() {
|
||||
function Puskesmas() {
|
||||
return (
|
||||
<div>
|
||||
Puskesmas
|
||||
</div>
|
||||
<Stack gap={"xs"}>
|
||||
<Box>
|
||||
<Title order={3}>Puskesmas</Title>
|
||||
<Tabs defaultValue="create" color={colors['blue-button']} variant='pills'>
|
||||
<TabsList mb={10} bg={colors['BG-trans']} p={'xs'}>
|
||||
<TabsTab value="create" >
|
||||
Tambah Puskesmas
|
||||
</TabsTab>
|
||||
<TabsTab value="update" >
|
||||
Edit Puskesmas
|
||||
</TabsTab>
|
||||
</TabsList>
|
||||
|
||||
<TabsPanel value="create">
|
||||
<CreatePuskesmas />
|
||||
</TabsPanel>
|
||||
|
||||
<TabsPanel value="update">
|
||||
<UpdatePuskesmas />
|
||||
</TabsPanel>
|
||||
</Tabs>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default Puskesmas;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Stack, SimpleGrid, Paper, Title, TextInput, Text } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
|
||||
function UpdatePuskesmas() {
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Edit Puskesmas</Title>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"} fz={"sm"}>Nama Puskesmas</Text>}
|
||||
placeholder='Masukkan nama puskesmas'
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"} fz={"sm"}>No Telp Puskesmas</Text>}
|
||||
placeholder='Masukkan no telp puskesmas'
|
||||
/>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"sm"}>Deskripsi</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"sm"}>Pelayanan Posyandu</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Preview Data Puskesmas</Title>
|
||||
<Text fw={"bold"} fz={"sm"}>Nama Puskesmas</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>No Telp Puskesmas</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>Deskripsi</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>Pelayanan Posyandu</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default UpdatePuskesmas;
|
||||
@@ -0,0 +1,55 @@
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Paper, SimpleGrid, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import { KesehatanEditor } from '../../../_com/kesehatanEditor';
|
||||
|
||||
function CreatePuskesmas() {
|
||||
return (
|
||||
<Box>
|
||||
<Stack gap={"xs"}>
|
||||
<SimpleGrid cols={{ base: 1, md: 2 }}>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Tambah Puskesmas</Title>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"} fz={"sm"}>Nama Puskesmas</Text>}
|
||||
placeholder='Masukkan nama puskesmas'
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw={"bold"} fz={"sm"}>No Telp Puskesmas</Text>}
|
||||
placeholder='Masukkan no telp puskesmas'
|
||||
/>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"sm"}>Deskripsi</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"sm"}>Pelayanan Posyandu</Text>
|
||||
<KesehatanEditor
|
||||
showSubmit={false}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
<Box>
|
||||
<Paper bg={colors['white-1']} p={"md"}>
|
||||
<Stack gap={"xs"}>
|
||||
<Title order={4}>Preview Data Puskesmas</Title>
|
||||
<Text fw={"bold"} fz={"sm"}>Nama Puskesmas</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>No Telp Puskesmas</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>Deskripsi</Text>
|
||||
<Text fw={"bold"} fz={"sm"}>Pelayanan Posyandu</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreatePuskesmas;
|
||||
@@ -29,7 +29,7 @@ function ProfileList() {
|
||||
<Box mb={20}>
|
||||
<Text fw={"bold"} mb={5}>Preview Gambar:</Text>
|
||||
<Image
|
||||
src={item.imageUrl}
|
||||
src={item.imageUrl ?? '/perbekel.png'}
|
||||
alt="Profile"
|
||||
w={200}
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useProxy } from 'valtio/utils';
|
||||
import stateProfilePPID from '../../_state/ppid/profile_ppid/profile_PPID';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import ProfileList from './listPage';
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
|
||||
function Page() {
|
||||
@@ -23,14 +25,16 @@ function Page() {
|
||||
}
|
||||
|
||||
function ProfileCreate() {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const allState = useProxy(stateProfilePPID)
|
||||
|
||||
|
||||
// Initialize data if it doesn't exist
|
||||
useShallowEffect(() => {
|
||||
if (!allState.findById.data) {
|
||||
if (!allState.findById.data && isLoading) {
|
||||
allState.findById.initialize()
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [])
|
||||
}, [isLoading])
|
||||
|
||||
const submit = () => {
|
||||
if (
|
||||
@@ -41,6 +45,12 @@ function ProfileCreate() {
|
||||
allState.findById.data?.unggulan
|
||||
) {
|
||||
allState.update.save(allState.findById.data)
|
||||
setIsLoading(true)
|
||||
toast.success("success")
|
||||
console.log("[SUBMIT SUCCESS]", JSON.stringify(allState.findById.data, null, 2))
|
||||
allState.findById.initialize()
|
||||
} else {
|
||||
toast.error("error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +73,8 @@ function ProfileCreate() {
|
||||
<PengalamanOrganisasi />
|
||||
<ProgramKerjaUnggulan />
|
||||
<Group>
|
||||
<Button
|
||||
bg={colors['blue-button']}
|
||||
<Button
|
||||
bg={colors['blue-button']}
|
||||
onClick={submit}
|
||||
loading={allState.update.loading}
|
||||
>
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import colors from "@/con/colors";
|
||||
import { ActionIcon, AppShell, AppShellHeader, AppShellMain, AppShellNavbar, Burger, Group, Image, NavLink, ScrollArea, Text } from "@mantine/core";
|
||||
import {
|
||||
ActionIcon,
|
||||
AppShell,
|
||||
AppShellHeader,
|
||||
AppShellMain,
|
||||
AppShellNavbar,
|
||||
Burger,
|
||||
Group,
|
||||
Image,
|
||||
NavLink,
|
||||
ScrollArea,
|
||||
Text
|
||||
} from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
|
||||
import _ from 'lodash';
|
||||
@@ -10,75 +23,106 @@ import { navBar } from "./_com/list_PageAdmin";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const [opened, { toggle }] = useDisclosure();
|
||||
const [desktopOpened, { toggle: toggleDesktop }] =
|
||||
useDisclosure(true);
|
||||
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);
|
||||
|
||||
// Normalisasi semua segmen jadi lowercase
|
||||
const segments = useSelectedLayoutSegments().map(s => _.lowerCase(s));
|
||||
|
||||
const segments = useSelectedLayoutSegments()
|
||||
return (
|
||||
<AppShell
|
||||
suppressHydrationWarning
|
||||
header={{ height: 60 }}
|
||||
navbar={{
|
||||
width: 300, breakpoint: 'sm', collapsed: { mobile: !opened, desktop: !desktopOpened }
|
||||
width: 300,
|
||||
breakpoint: 'sm',
|
||||
collapsed: {
|
||||
mobile: !opened,
|
||||
desktop: !desktopOpened,
|
||||
},
|
||||
}}
|
||||
padding={'md'}
|
||||
>
|
||||
<AppShellHeader bg={colors["white-trans-1"]}>
|
||||
<Group px={10} align="center">
|
||||
{!desktopOpened && <ActionIcon variant="light" onClick={toggleDesktop}><IconChevronRight /></ActionIcon>}
|
||||
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size={'sm'} />
|
||||
<ActionIcon w={50} h={50} variant="transparent" component={Link} href="/admin">
|
||||
<Image py={5} src={'/assets/images/darmasaba-icon.png'} alt="" width={50} height={50} />
|
||||
{!desktopOpened && (
|
||||
<ActionIcon variant="light" onClick={toggleDesktop}>
|
||||
<IconChevronRight />
|
||||
</ActionIcon>
|
||||
)}
|
||||
<Burger
|
||||
opened={opened}
|
||||
onClick={toggle}
|
||||
hiddenFrom="sm"
|
||||
size={'sm'}
|
||||
/>
|
||||
<ActionIcon
|
||||
w={50}
|
||||
h={50}
|
||||
variant="transparent"
|
||||
component={Link}
|
||||
href="/admin"
|
||||
>
|
||||
<Image
|
||||
py={5}
|
||||
src={'/assets/images/darmasaba-icon.png'}
|
||||
alt=""
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</ActionIcon>
|
||||
<Text fw={'bold'} c={colors["blue-button"]} fz={'lg'}>Dashboard Admin</Text>
|
||||
<Text fw={'bold'} c={colors["blue-button"]} fz={'lg'}>
|
||||
Dashboard Admin
|
||||
</Text>
|
||||
</Group>
|
||||
</AppShellHeader>
|
||||
<AppShellNavbar
|
||||
|
||||
c={colors["blue-button"]}
|
||||
component={ScrollArea}
|
||||
>
|
||||
<AppShell.Section >
|
||||
<AppShellNavbar c={colors["blue-button"]} component={ScrollArea}>
|
||||
<AppShell.Section>
|
||||
{navBar.map((v, k) => {
|
||||
const isParentActive = segments.includes(_.lowerCase(v.name));
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
c={_.lowerCase(v.name) == segments[1] ? colors["blue-button"] : "grey"}
|
||||
key={k}
|
||||
defaultOpened={_.lowerCase(v.name) == segments[1]}
|
||||
// onClick={() => setActive(k)}
|
||||
label={<Text
|
||||
style={{ fontWeight: _.lowerCase(v.name) == segments[1] ? "bold" : "normal" }}
|
||||
>{v.name}</Text>}
|
||||
defaultOpened={isParentActive}
|
||||
c={isParentActive ? colors["blue-button"] : "grey"}
|
||||
label={
|
||||
<Text style={{ fontWeight: isParentActive ? "bold" : "normal" }}>
|
||||
{v.name}
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{v.children.map((child, key) => {
|
||||
const isChildActive = segments.includes(_.lowerCase(child.name));
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
c={_.lowerCase(child.name) == _.lowerCase(segments[2]) ? colors["blue-button"] : "grey"}
|
||||
key={key}
|
||||
href={child.path}
|
||||
// active={isClient && Number(child.id) === active}
|
||||
// onClick={() => setActive(Number(child.id))}
|
||||
label={<Text
|
||||
style={{ fontWeight: _.lowerCase(child.name) == _.lowerCase(segments[2]) ? "bold" : "normal" }}
|
||||
>{child.name}</Text>}
|
||||
c={isChildActive ? colors["blue-button"] : "grey"}
|
||||
label={
|
||||
<Text style={{ fontWeight: isChildActive ? "bold" : "normal" }}>
|
||||
{child.name}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</NavLink>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</AppShell.Section>
|
||||
|
||||
<AppShell.Section py={20}>
|
||||
<Group justify="end">
|
||||
<ActionIcon variant="light" onClick={toggleDesktop}><IconChevronLeft /></ActionIcon>
|
||||
<ActionIcon variant="light" onClick={toggleDesktop}>
|
||||
<IconChevronLeft />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</AppShell.Section>
|
||||
</AppShellNavbar>
|
||||
<AppShellMain bg={colors.Bg}>
|
||||
{children}
|
||||
</AppShellMain>
|
||||
|
||||
<AppShellMain bg={colors.Bg}>{children}</AppShellMain>
|
||||
</AppShell>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function profileDesaFindById(context: Context) {
|
||||
try {
|
||||
const id = context?.params?.slugs?.[0];
|
||||
|
||||
// If no ID provided, get the first profile
|
||||
if (!id) {
|
||||
const data = await prisma.profileDesa.findFirst();
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
const data = await prisma.profileDesa.findUniqueOrThrow({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching profileDesa:", error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export default async function profileDesaFindMany() {
|
||||
const res = await prisma.profileDesa.findMany({
|
||||
include: {
|
||||
ProfilPerbekel: true,
|
||||
},
|
||||
});
|
||||
return {
|
||||
data: res,
|
||||
};
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
import profileDesaFindMany from "./find-many";
|
||||
import lambangDesaUpdate from "./lambangDesa";
|
||||
import maskotDesaUpdate from "./maskotDesa";
|
||||
import profilePerbekelUpdate from "./profilePerbekel";
|
||||
import sejarahDesaUpdate from "./sejarahDesa";
|
||||
import visimisiDesaUpdate from "./visimisiDesa";
|
||||
import lambangDesaUpdate from "./lambangDesa/update";
|
||||
import maskotDesaUpdate from "./maskotDesa/update";
|
||||
import profilePerbekelUpdate from "../profilePerbekel/update";
|
||||
import sejarahDesaUpdate from "./sejarah/update";
|
||||
import visimisiDesaUpdate from "./visimisiDesa/update";
|
||||
import profileDesaFindById from "./find-by-id";
|
||||
|
||||
const ProfileDesa = new Elysia({
|
||||
prefix: "/profile",
|
||||
tags: ["Desa/Profile"]
|
||||
})
|
||||
.get("/find-many", profileDesaFindMany)
|
||||
.get("/find-by-id", profileDesaFindById)
|
||||
.post("/profilePerbekel/update", profilePerbekelUpdate, {
|
||||
body: t.Object({
|
||||
id: t.String(),
|
||||
@@ -27,7 +27,7 @@ const ProfileDesa = new Elysia({
|
||||
misi: t.String(),
|
||||
})
|
||||
})
|
||||
.post("/sejarahDesa/update", sejarahDesaUpdate, {
|
||||
.post("/sejarah/update", sejarahDesaUpdate, {
|
||||
body: t.Object({
|
||||
id: t.String(),
|
||||
sejarah: t.String(),
|
||||
|
||||
63
src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts
Normal file
63
src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
|
||||
|
||||
const fileStorageCreate = async (context: Context) => {
|
||||
const body = (await context.body) as {
|
||||
name: string;
|
||||
file: File;
|
||||
};
|
||||
const file = body.file;
|
||||
const name = body.name;
|
||||
|
||||
if (!file) {
|
||||
return {
|
||||
status: 400,
|
||||
body: "No file uploaded",
|
||||
};
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
return {
|
||||
status: 400,
|
||||
body: "No name provided",
|
||||
};
|
||||
}
|
||||
|
||||
if (!UPLOAD_DIR) {
|
||||
return {
|
||||
status: 500,
|
||||
body: "UPLOAD_DIR is not defined",
|
||||
};
|
||||
}
|
||||
const pathName = "desa/ppid/profile-ppid";
|
||||
const rootPath = path.join(UPLOAD_DIR, pathName);
|
||||
await fs.mkdir(rootPath, { recursive: true });
|
||||
|
||||
const ext = file.name.split(".").pop();
|
||||
const newName = nanoid() + "." + ext;
|
||||
|
||||
const data = await prisma.fileStorage.create({
|
||||
data: {
|
||||
name: newName,
|
||||
path: rootPath,
|
||||
mimeType: file.type,
|
||||
link: `/api/fileStorage/findUnique/${newName}`,
|
||||
},
|
||||
});
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(rootPath, newName),
|
||||
Buffer.from(await file.arrayBuffer())
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
export default fileStorageCreate;
|
||||
@@ -0,0 +1,6 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
export const fileStorageFindMany = async () => {
|
||||
const data = await prisma.fileStorage.findMany();
|
||||
return data;
|
||||
};
|
||||
34
src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts
Normal file
34
src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
const fileStorageFindUnique = async (context: Context) => {
|
||||
const { name } = context.params;
|
||||
|
||||
const data = await prisma.fileStorage.findUnique({
|
||||
where: {
|
||||
name,
|
||||
},
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
context.set.status = "No Content";
|
||||
return {
|
||||
status: 404,
|
||||
message: "File not found",
|
||||
};
|
||||
}
|
||||
|
||||
console.log(data);
|
||||
|
||||
const file = await fs.readFile(path.join(data.path, data.name));
|
||||
context.set.headers = {
|
||||
"Content-Type": data.mimeType,
|
||||
"Content-Length": file.length,
|
||||
};
|
||||
|
||||
return file;
|
||||
};
|
||||
|
||||
export default fileStorageFindUnique;
|
||||
19
src/app/api/[[...slugs]]/_lib/fileStorage/index.ts
Normal file
19
src/app/api/[[...slugs]]/_lib/fileStorage/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import Elysia, { t } from "elysia";
|
||||
import fileStorageCreate from "./_lib/create";
|
||||
import fileStorageFindUnique from "./_lib/findUniq";
|
||||
import { fileStorageFindMany } from "./_lib/findMany";
|
||||
|
||||
const FileStorage = new Elysia({
|
||||
prefix: "/api/fileStorage",
|
||||
tags: ["FileStorage"],
|
||||
})
|
||||
.post("/create", fileStorageCreate, {
|
||||
body: t.Object({
|
||||
name: t.String(),
|
||||
file: t.File(),
|
||||
}),
|
||||
})
|
||||
.get("/findUnique/:name", fileStorageFindUnique)
|
||||
.get("/findMany", fileStorageFindMany);
|
||||
|
||||
export default FileStorage;
|
||||
@@ -1,21 +1,22 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { staticPlugin } from '@elysiajs/static'
|
||||
import cors, { HTTPMethod } from "@elysiajs/cors";
|
||||
import { staticPlugin } from "@elysiajs/static";
|
||||
import swagger from "@elysiajs/swagger";
|
||||
import { Elysia, t } from "elysia";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import Desa from "./_lib/desa";
|
||||
import getPotensi from "./_lib/get-potensi";
|
||||
import img from "./_lib/img";
|
||||
import imgDel from "./_lib/img-del";
|
||||
import imgs from "./_lib/imgs";
|
||||
import Kesehatan from "./_lib/kesehatan";
|
||||
import PPID from "./_lib/ppid";
|
||||
import uplCsv from "./_lib/upl-csv";
|
||||
import { uplCsvSingle } from "./_lib/upl-csv-single";
|
||||
import uplImg from "./_lib/upl-img";
|
||||
import { uplImgSingle } from "./_lib/upl-img-single";
|
||||
import Desa from "./_lib/desa";
|
||||
import Kesehatan from "./_lib/kesehatan";
|
||||
import PPID from "./_lib/ppid";
|
||||
import FileStorage from "./_lib/fileStorage";
|
||||
|
||||
const ROOT = process.cwd();
|
||||
|
||||
@@ -23,7 +24,14 @@ if (!process.env.WIBU_UPLOAD_DIR)
|
||||
throw new Error("WIBU_UPLOAD_DIR is not defined");
|
||||
|
||||
const UPLOAD_DIR = path.join(ROOT, process.env.WIBU_UPLOAD_DIR);
|
||||
const UPLOAD_DIR_IMAGE = path.join(UPLOAD_DIR, "public", "assets", "images", "ppid", "profile-ppid");
|
||||
const UPLOAD_DIR_IMAGE = path.join(
|
||||
UPLOAD_DIR,
|
||||
"public",
|
||||
"assets",
|
||||
"images",
|
||||
"ppid",
|
||||
"profile-ppid"
|
||||
);
|
||||
|
||||
// create uploads dir
|
||||
fs.mkdir(UPLOAD_DIR, {
|
||||
@@ -63,15 +71,18 @@ const Utils = new Elysia({
|
||||
|
||||
const ApiServer = new Elysia()
|
||||
.use(swagger({ path: "/api/docs" }))
|
||||
.use(staticPlugin({
|
||||
prefix: '/', // biar bisa akses dari root URL
|
||||
assets: './public'
|
||||
}))
|
||||
.use(
|
||||
staticPlugin({
|
||||
prefix: "/", // biar bisa akses dari root URL
|
||||
assets: "./public",
|
||||
})
|
||||
)
|
||||
.use(cors(corsConfig))
|
||||
.use(PPID)
|
||||
.use(Kesehatan)
|
||||
.use(Desa)
|
||||
.use(Utils)
|
||||
.use(FileStorage)
|
||||
.onError(({ code }) => {
|
||||
if (code === "NOT_FOUND") {
|
||||
return {
|
||||
|
||||
67
src/app/percobaan/page.tsx
Normal file
67
src/app/percobaan/page.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
'use client'
|
||||
import ApiFetch from '@/lib/api-fetch';
|
||||
import { Button, Card, Container, FileInput, Flex, Image, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
function Page() {
|
||||
|
||||
const [gambar, setGambar] = useState<string | null>(null);
|
||||
const [listFile, setListFile] = useState<string[]>([])
|
||||
const [fileNya, setFileNya] = useState<File | null>(null)
|
||||
|
||||
|
||||
const loadListFile = async () => {
|
||||
const { data } = await ApiFetch.api.fileStorage.findMany.get()
|
||||
setListFile(data?.map((item) => item.link) || [])
|
||||
}
|
||||
useShallowEffect(() => {
|
||||
loadListFile()
|
||||
}, [])
|
||||
|
||||
const submit = async () => {
|
||||
console.log("kirim gamabar")
|
||||
const file = fileNya
|
||||
if (!file) return toast.warn("file dibutuhkan");
|
||||
|
||||
const { data } = await ApiFetch.api.fileStorage.create.post({
|
||||
file: file,
|
||||
name: file.name
|
||||
})
|
||||
|
||||
console.log(data?.data)
|
||||
setGambar(data?.data?.link || null)
|
||||
toast.success("berhasil upload")
|
||||
loadListFile()
|
||||
setGambar(null)
|
||||
|
||||
}
|
||||
return (
|
||||
<Container w={"90%"} >
|
||||
<Stack>
|
||||
<Text>Uoload gambar</Text>
|
||||
<Card withBorder>
|
||||
<Flex gap={"lg"} >
|
||||
<FileInput label={"upload gambar"} onChange={async (e) => {
|
||||
console.log(e?.name)
|
||||
setGambar(e ? "data:image/png;base64," + Buffer.from(await e.arrayBuffer()).toString("base64") : null)
|
||||
setFileNya(e)
|
||||
}} />
|
||||
<Button onClick={submit}>submit</Button>
|
||||
</Flex>
|
||||
{gambar && <Image w={400} src={gambar || null} alt="gambar" />}
|
||||
</Card>
|
||||
|
||||
|
||||
<SimpleGrid cols={6} p={"lg"}>
|
||||
{listFile.map((v) => (
|
||||
<Image key={v} src={v} alt="gambar" />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
8
types/env.d.ts
vendored
Normal file
8
types/env.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
DATABASE_URL?: string;
|
||||
WIBU_UPLOAD_DIR?: string;
|
||||
NEXT_PUBLIC_BASE_URL?: string;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user