Compare commits
8 Commits
nico/19-se
...
nico/29-se
| Author | SHA1 | Date | |
|---|---|---|---|
| 295d6f7d63 | |||
| dbd56a1493 | |||
| 2a26db6e17 | |||
| 33fc472472 | |||
| d8fa56d923 | |||
| cac146471a | |||
| 3e4a7a1c0a | |||
| b5c044df6e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -41,6 +41,9 @@ next-env.d.ts
|
||||
# uploads
|
||||
/uploads
|
||||
|
||||
# download
|
||||
/download
|
||||
|
||||
# cache
|
||||
/cache
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
experimental: {},
|
||||
allowedDevOrigins: [
|
||||
"http://192.168.1.82:3000", // buat akses dari HP/device lain
|
||||
"http://localhost:3000", // akses lokal
|
||||
],
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.1.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "bun --bun next dev",
|
||||
"dev": "bun --bun next dev --hostname 0.0.0.0",
|
||||
"build": "bun --bun next build",
|
||||
"start": "bun --bun next start"
|
||||
},
|
||||
@@ -39,19 +39,23 @@
|
||||
"@tiptap/pm": "^2.11.7",
|
||||
"@tiptap/react": "^2.11.7",
|
||||
"@tiptap/starter-kit": "^2.11.7",
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bun": "^1.2.2",
|
||||
"@types/leaflet": "^1.9.20",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"add": "^2.0.6",
|
||||
"adm-zip": "^0.5.16",
|
||||
"animate.css": "^4.1.1",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"bun": "^1.2.2",
|
||||
"chart.js": "^4.4.8",
|
||||
"classnames": "^2.5.1",
|
||||
"colors": "^1.4.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"elysia": "^1.3.5",
|
||||
"embla-carousel-autoplay": "^8.5.2",
|
||||
"embla-carousel-react": "^7.1.0",
|
||||
"extract-zip": "^2.0.1",
|
||||
"form-data": "^4.0.2",
|
||||
"framer-motion": "^12.23.5",
|
||||
"get-port": "^7.1.0",
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"id": "role-1",
|
||||
"name": "ADMIN DESA",
|
||||
"description": "Administrator Desa",
|
||||
"permissions": ["manage_users", "manage_content", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"id": "role-2",
|
||||
"name": "ADMIN KESEHATAN",
|
||||
"description": "Administrator Bidang Kesehatan",
|
||||
"permissions": ["manage_health_data", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"id": "role-3",
|
||||
"name": "ADMIN SEKOLAH",
|
||||
"description": "Administrator Sekolah",
|
||||
"permissions": ["manage_school_data", "view_reports"],
|
||||
"isActive": true,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
"isActive": true
|
||||
}
|
||||
]
|
||||
@@ -1,32 +1,23 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"nama": "Admin Desa",
|
||||
"nomor": "089647037426",
|
||||
"roleId": "1",
|
||||
"isActive": true,
|
||||
"lastLogin": "2025-08-31T10:00:00.000Z",
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"nama": "Admin Kesehatan",
|
||||
"nomor": "082339004198",
|
||||
"roleId": "2",
|
||||
"isActive": true,
|
||||
"lastLogin": null,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"nama": "Admin Sekolah",
|
||||
"nomor": "085237157222",
|
||||
"roleId": "3",
|
||||
"isActive": true,
|
||||
"lastLogin": null,
|
||||
"createdAt": "2025-09-01T00:00:00.000Z",
|
||||
"updatedAt": "2025-09-01T00:00:00.000Z"
|
||||
}
|
||||
]
|
||||
{
|
||||
"id": "user-1",
|
||||
"nama": "Admin Desa",
|
||||
"nomor": "089647037426",
|
||||
"roleId": "role-1",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": "user-2",
|
||||
"nama": "Admin Kesehatan",
|
||||
"nomor": "082339004198",
|
||||
"roleId": "role-2",
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": "user-3",
|
||||
"nama": "Admin Sekolah",
|
||||
"nomor": "085237157222",
|
||||
"roleId": "role-3",
|
||||
"isActive": true
|
||||
}
|
||||
]
|
||||
|
||||
30
prisma/safeseedUnique.ts
Normal file
30
prisma/safeseedUnique.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// helpers/safeSeedUnique.ts
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
/**
|
||||
* Helper generic buat seed dengan upsert aman
|
||||
*/
|
||||
export async function safeSeedUnique<T extends keyof PrismaClient>(
|
||||
model: T,
|
||||
where: Record<string, any>,
|
||||
data: Record<string, any>
|
||||
) {
|
||||
const m = prisma[model];
|
||||
|
||||
if (!m) throw new Error(`Model ${String(model)} tidak ditemukan di PrismaClient`);
|
||||
|
||||
try {
|
||||
// @ts-expect-error upsert dynamic
|
||||
await m.upsert({
|
||||
where,
|
||||
update: data,
|
||||
create: { ...where, ...data },
|
||||
});
|
||||
console.log(`✅ Seeded ${String(model)} -> ${JSON.stringify(where)}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Gagal seed ${String(model)} -> ${JSON.stringify(where)}`, err);
|
||||
}
|
||||
}
|
||||
@@ -672,17 +672,18 @@ model GalleryVideo {
|
||||
|
||||
// ========================================= LAYANAN DESA ========================================= //
|
||||
model PelayananSuratKeterangan {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
deskripsi String @db.Text
|
||||
image FileStorage? @relation("PelayananSuratKeteranganImage", fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
image2 FileStorage? @relation("PelayananSuratKeteranganImage2", fields: [image2Id], references: [id])
|
||||
image2Id String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
deskripsi String @db.Text
|
||||
image FileStorage? @relation("PelayananSuratKeteranganImage", fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
image2 FileStorage? @relation("PelayananSuratKeteranganImage2", fields: [image2Id], references: [id])
|
||||
image2Id String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
AjukanPermohonan AjukanPermohonan[]
|
||||
}
|
||||
|
||||
model PelayananTelunjukSaktiDesa {
|
||||
@@ -717,6 +718,20 @@ model PelayananPendudukNonPermanen {
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
model AjukanPermohonan {
|
||||
id String @id @default(cuid())
|
||||
nama String
|
||||
nik String
|
||||
alamat String
|
||||
nomorKk String
|
||||
kategori PelayananSuratKeterangan @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= PENGHARGAAN ========================================= //
|
||||
model Penghargaan {
|
||||
id String @id @default(cuid())
|
||||
@@ -835,8 +850,8 @@ model JadwalKegiatan {
|
||||
syaratKetentuanJadwalKegiatanId String
|
||||
dokumenjadwalkegiatan DokumenJadwalKegiatan @relation(fields: [dokumenJadwalKegiatanId], references: [id])
|
||||
dokumenJadwalKegiatanId String
|
||||
pendaftaranjadwalkegiatan PendaftaranJadwalKegiatan @relation(fields: [pendaftaranJadwalKegiatanId], references: [id])
|
||||
pendaftaranJadwalKegiatanId String
|
||||
pendaftaranjadwalkegiatan PendaftaranJadwalKegiatan? @relation(fields: [pendaftaranJadwalKegiatanId], references: [id])
|
||||
pendaftaranJadwalKegiatanId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -1254,15 +1269,15 @@ model KontakDaruratToItem {
|
||||
|
||||
// ========================================= PENCEGAHAN KRIMINALITAS ========================================= //
|
||||
model PencegahanKriminalitas {
|
||||
id String @id @default(cuid())
|
||||
judul String
|
||||
deskripsi String
|
||||
deskripsiSingkat String
|
||||
linkVideo String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
id String @id @default(cuid())
|
||||
judul String
|
||||
deskripsi String
|
||||
deskripsiSingkat String
|
||||
linkVideo String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
}
|
||||
|
||||
// ========================================= LAPORAN PUBLIK ========================================= //
|
||||
|
||||
@@ -56,6 +56,8 @@ import tujuanProgram from "./data/pendidikan/program-pendidikan-anak/tujuan-prog
|
||||
import roles from "./data/user/roles.json";
|
||||
import users from "./data/user/users.json";
|
||||
import fileStorage from "./data/file-storage.json";
|
||||
import seedAssets from "./seed_assets";
|
||||
import { safeSeedUnique } from "./safeseedUnique";
|
||||
|
||||
(async () => {
|
||||
// =========== USER & ROLE ===========
|
||||
@@ -63,23 +65,14 @@ import fileStorage from "./data/file-storage.json";
|
||||
// =========== ROLES ===========
|
||||
console.log("🔄 Seeding roles...");
|
||||
for (const r of roles) {
|
||||
await prisma.role.upsert({
|
||||
where: { id: r.id },
|
||||
update: {
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
permissions: r.permissions,
|
||||
isActive: r.isActive,
|
||||
},
|
||||
create: {
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
permissions: r.permissions,
|
||||
isActive: r.isActive,
|
||||
},
|
||||
await safeSeedUnique("role", { id: r.id }, {
|
||||
name: r.name,
|
||||
description: r.description,
|
||||
permissions: r.permissions,
|
||||
isActive: r.isActive,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("✅ Roles seeded");
|
||||
|
||||
// =========== USERS ===========
|
||||
@@ -95,22 +88,12 @@ import fileStorage from "./data/file-storage.json";
|
||||
continue;
|
||||
}
|
||||
|
||||
await prisma.user.upsert({
|
||||
where: { id: u.id },
|
||||
update: {
|
||||
username: u.nama,
|
||||
nomor: u.nomor,
|
||||
roleId: u.roleId,
|
||||
await safeSeedUnique("user", { id: u.id }, {
|
||||
username: u.nama,
|
||||
nomor: u.nomor,
|
||||
roleId: u.roleId,
|
||||
isActive: u.isActive,
|
||||
},
|
||||
create: {
|
||||
id: u.id,
|
||||
username: u.nama,
|
||||
nomor: u.nomor,
|
||||
roleId: u.roleId,
|
||||
isActive: u.isActive,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
console.log("✅ Users seeded");
|
||||
|
||||
@@ -364,6 +347,7 @@ import fileStorage from "./data/file-storage.json";
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
create: {
|
||||
id: l.id,
|
||||
name: l.name,
|
||||
jumlah: l.jumlah,
|
||||
},
|
||||
@@ -1169,6 +1153,10 @@ import fileStorage from "./data/file-storage.json";
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)"
|
||||
);
|
||||
|
||||
// seed assets
|
||||
await seedAssets();
|
||||
|
||||
})()
|
||||
.then(() => prisma.$disconnect())
|
||||
.catch((e) => {
|
||||
|
||||
118
prisma/seed_assets.ts
Normal file
118
prisma/seed_assets.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
// prisma/seedAssets.ts
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import sharp from "sharp";
|
||||
import fetch from "node-fetch";
|
||||
import AdmZip from "adm-zip";
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
const UPLOADS_DIR =
|
||||
process.env.WIBU_UPLOAD_DIR || path.join(process.cwd(), "uploads");
|
||||
|
||||
// --- Helper: deteksi kategori file ---
|
||||
function detectCategory(filename: string): "image" | "document" | "other" {
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
if ([".jpg", ".jpeg", ".png", ".webp"].includes(ext)) return "image";
|
||||
if ([".pdf", ".doc", ".docx"].includes(ext)) return "document";
|
||||
return "other";
|
||||
}
|
||||
|
||||
// --- Helper: recursive walk dir ---
|
||||
async function walkDir(dir: string, fileList: string[] = []): Promise<string[]> {
|
||||
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name === "__MACOSX") continue; // skip folder sampah
|
||||
await walkDir(fullPath, fileList);
|
||||
} else {
|
||||
if (entry.name.startsWith(".") || entry.name === ".DS_Store") continue; // skip file sampah
|
||||
fileList.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
|
||||
export default async function seedAssets() {
|
||||
console.log("🚀 Seeding assets...");
|
||||
|
||||
// 1. Download zip
|
||||
const url =
|
||||
"https://cld-dkr-makuro-seafile.wibudev.com/f/ffd5a548a04f47939474/?dl=1";
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`Gagal download assets: ${res.statusText}`);
|
||||
const buffer = Buffer.from(await res.arrayBuffer());
|
||||
|
||||
// 2. Extract zip ke folder tmp
|
||||
const extractDir = path.join(process.cwd(), "tmp_assets");
|
||||
await fs.rm(extractDir, { recursive: true, force: true });
|
||||
await fs.mkdir(extractDir, { recursive: true });
|
||||
|
||||
const zip = new AdmZip(buffer);
|
||||
zip.extractAllTo(extractDir, true);
|
||||
|
||||
// 3. Cari semua file valid (recursive)
|
||||
const files = await walkDir(extractDir);
|
||||
|
||||
// 4. Loop tiap file & simpan
|
||||
for (const filePath of files) {
|
||||
const entryName = path.basename(filePath);
|
||||
const category = detectCategory(entryName);
|
||||
|
||||
let finalName = entryName;
|
||||
let mimeType = "application/octet-stream";
|
||||
let targetPath = "";
|
||||
|
||||
if (category === "image") {
|
||||
const fileBaseName = path.parse(entryName).name;
|
||||
finalName = `${fileBaseName}.webp`;
|
||||
targetPath = path.join(UPLOADS_DIR, "images", finalName);
|
||||
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
||||
await sharp(filePath).webp({ quality: 80 }).toFile(targetPath);
|
||||
mimeType = "image/webp";
|
||||
} else if (category === "document") {
|
||||
targetPath = path.join(UPLOADS_DIR, "documents", entryName);
|
||||
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
||||
await fs.copyFile(filePath, targetPath);
|
||||
mimeType = "application/pdf";
|
||||
} else {
|
||||
targetPath = path.join(UPLOADS_DIR, "other", entryName);
|
||||
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
||||
await fs.copyFile(filePath, targetPath);
|
||||
}
|
||||
|
||||
// 5. Simpan ke DB
|
||||
await prisma.fileStorage.create({
|
||||
data: {
|
||||
name: finalName,
|
||||
realName: entryName,
|
||||
path: targetPath,
|
||||
mimeType,
|
||||
link: `/uploads/${category}/${finalName}`,
|
||||
category,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`📂 saved: ${category}/${finalName}`);
|
||||
}
|
||||
|
||||
// 6. Cleanup
|
||||
await fs.rm(extractDir, { recursive: true, force: true });
|
||||
|
||||
console.log("✅ Selesai seed assets!");
|
||||
}
|
||||
|
||||
// --- Auto run kalau dipanggil langsung ---
|
||||
if (import.meta.main) {
|
||||
seedAssets()
|
||||
.catch((err) => {
|
||||
console.error("❌ Error seeding assets:", err);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 47 KiB |
@@ -71,6 +71,22 @@ const pelayananPendudukNonPermanenForm = {
|
||||
deskripsi: "",
|
||||
};
|
||||
|
||||
const templateAjukanForm = z.object({
|
||||
nama: z.string().min(1).max(5000),
|
||||
nik: z.string().min(1).max(5000),
|
||||
alamat: z.string().min(1).max(5000),
|
||||
nomorKk: z.string().min(1).max(5000),
|
||||
kategoriId: z.string().min(1).max(5000),
|
||||
});
|
||||
|
||||
const defaultAjukanForm = {
|
||||
nama: "",
|
||||
nik: "",
|
||||
alamat: "",
|
||||
nomorKk: "",
|
||||
kategoriId: "",
|
||||
};
|
||||
|
||||
const suratKeterangan = proxy({
|
||||
create: {
|
||||
form: { ...suratKeteranganForm },
|
||||
@@ -146,6 +162,30 @@ const suratKeterangan = proxy({
|
||||
}
|
||||
},
|
||||
},
|
||||
findManyAll: {
|
||||
data: null as Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
omit: { isActive: true };
|
||||
}>[] | null,
|
||||
loading: false,
|
||||
load: async () => {
|
||||
suratKeterangan.findManyAll.loading = true;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.layanan.pelayanansuratketerangan["findManyAll"].get();
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
suratKeterangan.findManyAll.data = res.data.data || [];
|
||||
} else {
|
||||
suratKeterangan.findManyAll.data = [];
|
||||
console.error("Failed to load surat keterangan all:", res.data?.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading surat keterangan all:", error);
|
||||
suratKeterangan.findManyAll.data = [];
|
||||
} finally {
|
||||
suratKeterangan.findManyAll.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.PelayananSuratKeteranganGetPayload<{
|
||||
include: {
|
||||
@@ -769,11 +809,250 @@ const pelayananPendudukNonPermanen = proxy({
|
||||
},
|
||||
});
|
||||
|
||||
const ajukanPermohonan = proxy({
|
||||
create: {
|
||||
form: { ...defaultAjukanForm },
|
||||
loading: false,
|
||||
async create() {
|
||||
const cek = templateAjukanForm.safeParse(
|
||||
ajukanPermohonan.create.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
ajukanPermohonan.create.loading = true;
|
||||
const res = await ApiFetch.api.desa.ajukanpermohonan[
|
||||
"create"
|
||||
].post(ajukanPermohonan.create.form);
|
||||
if (res.status === 200) {
|
||||
ajukanPermohonan.findMany.load();
|
||||
return toast.success("Ajukan permohonan berhasil disimpan!");
|
||||
}
|
||||
return toast.error("Gagal menyimpan ajukan permohonan");
|
||||
} catch (error) {
|
||||
console.log((error as Error).message);
|
||||
} finally {
|
||||
ajukanPermohonan.create.loading = false;
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
ajukanPermohonan.create.form = { ...defaultAjukanForm };
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as Prisma.AjukanPermohonanGetPayload<{
|
||||
include: {
|
||||
kategori: true;
|
||||
};
|
||||
}>[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
// Change to arrow function
|
||||
ajukanPermohonan.findMany.loading = true; // Use the full path to access the property
|
||||
ajukanPermohonan.findMany.page = page;
|
||||
ajukanPermohonan.findMany.search = search;
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
const res = await ApiFetch.api.desa.ajukanpermohonan[
|
||||
"findMany"
|
||||
].get({
|
||||
query,
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
ajukanPermohonan.findMany.data = res.data.data || [];
|
||||
ajukanPermohonan.findMany.total = res.data.total || 0;
|
||||
ajukanPermohonan.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load ajukan permohonan:", res.data?.message);
|
||||
ajukanPermohonan.findMany.data = [];
|
||||
ajukanPermohonan.findMany.total = 0;
|
||||
ajukanPermohonan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading ajukan permohonan:", error);
|
||||
ajukanPermohonan.findMany.data = [];
|
||||
ajukanPermohonan.findMany.total = 0;
|
||||
ajukanPermohonan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
ajukanPermohonan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.AjukanPermohonanGetPayload<{
|
||||
include: {
|
||||
kategori: true;
|
||||
}
|
||||
}> | null,
|
||||
async load(id: string) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/desa/ajukanpermohonan/${id}`
|
||||
);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
ajukanPermohonan.findUnique.data = data.data ?? null;
|
||||
} else {
|
||||
console.error("Failed to fetch ajukan permohonan:", res.statusText);
|
||||
ajukanPermohonan.findUnique.data = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching ajukan permohonan:", error);
|
||||
ajukanPermohonan.findUnique.data = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
loading: false,
|
||||
async byId(id: string) {
|
||||
if (!id) return toast.warn("ID tidak valid");
|
||||
try {
|
||||
ajukanPermohonan.delete.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/desa/ajukanpermohonan/del/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
toast.success(result.message || "Ajukan permohonan berhasil dihapus");
|
||||
await ajukanPermohonan.findMany.load(); // refresh list
|
||||
} else {
|
||||
toast.error(result.message || "Gagal menghapus ajukan permohonan");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Gagal delete:", error);
|
||||
toast.error("Terjadi kesalahan saat menghapus ajukan permohonan");
|
||||
} finally {
|
||||
ajukanPermohonan.delete.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
id: "",
|
||||
form: { ...defaultAjukanForm },
|
||||
loading: false,
|
||||
|
||||
async load(id: string) {
|
||||
if (!id) {
|
||||
toast.warn("ID tidak valid");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/desa/ajukanpermohonan/${id}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result?.success) {
|
||||
const data = result.data;
|
||||
this.id = data.id;
|
||||
this.form = {
|
||||
nama: data.nama,
|
||||
nik: data.nik,
|
||||
alamat: data.alamat,
|
||||
nomorKk: data.nomorKk,
|
||||
kategoriId: data.kategoriId,
|
||||
};
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal memuat data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching ajukan permohonan:", error);
|
||||
toast.error(
|
||||
error instanceof Error ? error.message : "Gagal memuat data"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
async update() {
|
||||
const cek = templateAjukanForm.safeParse(
|
||||
ajukanPermohonan.edit.form
|
||||
);
|
||||
if (!cek.success) {
|
||||
const err = `[${cek.error.issues
|
||||
.map((v) => `${v.path.join(".")}`)
|
||||
.join("\n")}] required`;
|
||||
return toast.error(err);
|
||||
}
|
||||
try {
|
||||
ajukanPermohonan.edit.loading = true;
|
||||
const response = await fetch(
|
||||
`/api/desa/ajukanpermohonan/${this.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nama: this.form.nama,
|
||||
nik: this.form.nik,
|
||||
alamat: this.form.alamat,
|
||||
nomorKk: this.form.nomorKk,
|
||||
kategoriId: this.form.kategoriId,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
toast.success(result.message || "Ajukan permohonan berhasil diupdate");
|
||||
await ajukanPermohonan.findMany.load(); // refresh list
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(
|
||||
result.message || "Gagal mengupdate ajukan permohonan"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating ajukan permohonan:", error);
|
||||
toast.error(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Terjadi kesalahan saat update ajukan permohonan"
|
||||
);
|
||||
return false;
|
||||
} finally {
|
||||
ajukanPermohonan.edit.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const stateLayananDesa = proxy({
|
||||
suratKeterangan,
|
||||
pelayananPerizinanBerusaha,
|
||||
pelayananTelunjukSaktiDesa,
|
||||
pelayananPendudukNonPermanen,
|
||||
ajukanPermohonan,
|
||||
});
|
||||
|
||||
export default stateLayananDesa;
|
||||
|
||||
@@ -26,14 +26,6 @@ const templateForm = z.object({
|
||||
dokumenJadwalKegiatan: z.object({
|
||||
content: z.string().min(1, "Content minimal 1 karakter"),
|
||||
}),
|
||||
pendaftaranJadwalKegiatan: z.object({
|
||||
name: z.string().min(1, "Name minimal 1 karakter"),
|
||||
tanggal: z.string().min(1, "Tanggal minimal 1 karakter"),
|
||||
namaOrangtua: z.string().min(1, "Nama Orangtua minimal 1 karakter"),
|
||||
nomor: z.string().min(1, "Nomor minimal 1 karakter"),
|
||||
alamat: z.string().min(1, "Alamat minimal 1 karakter"),
|
||||
catatan: z.string().min(1, "Catatan minimal 1 karakter"),
|
||||
}),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
@@ -55,15 +47,7 @@ const defaultForm = {
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: "",
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: "",
|
||||
tanggal: "",
|
||||
namaOrangtua: "",
|
||||
nomor: "",
|
||||
alamat: "",
|
||||
catatan: "",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const jadwalkegiatanState = proxy({
|
||||
@@ -116,7 +100,6 @@ const jadwalkegiatanState = proxy({
|
||||
deskripsijadwalkegiatan: true;
|
||||
layananjadwalkegiatan: true;
|
||||
dokumenjadwalkegiatan: true;
|
||||
pendaftaranjadwalkegiatan: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
@@ -161,7 +144,6 @@ const jadwalkegiatanState = proxy({
|
||||
layananjadwalkegiatan: true;
|
||||
syaratketentuanjadwalkegiatan: true;
|
||||
dokumenjadwalkegiatan: true;
|
||||
pendaftaranjadwalkegiatan: true;
|
||||
};
|
||||
}> | null,
|
||||
loading: false,
|
||||
@@ -209,15 +191,7 @@ const jadwalkegiatanState = proxy({
|
||||
},
|
||||
dokumenJadwalKegiatan: {
|
||||
content: data.dokumenjadwalkegiatan.content,
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: data.pendaftaranjadwalkegiatan.name,
|
||||
tanggal: data.pendaftaranjadwalkegiatan.tanggal,
|
||||
namaOrangtua: data.pendaftaranjadwalkegiatan.namaOrangtua,
|
||||
nomor: data.pendaftaranjadwalkegiatan.nomor,
|
||||
alamat: data.pendaftaranjadwalkegiatan.alamat,
|
||||
catatan: data.pendaftaranjadwalkegiatan.catatan,
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
async submit() {
|
||||
@@ -259,20 +233,6 @@ const jadwalkegiatanState = proxy({
|
||||
content:
|
||||
jadwalkegiatanState.edit.form.dokumenJadwalKegiatan.content,
|
||||
},
|
||||
pendaftaranJadwalKegiatan: {
|
||||
name: jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.name,
|
||||
tanggal:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.tanggal,
|
||||
namaOrangtua:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan
|
||||
.namaOrangtua,
|
||||
nomor:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.nomor,
|
||||
alamat:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.alamat,
|
||||
catatan:
|
||||
jadwalkegiatanState.edit.form.pendaftaranJadwalKegiatan.catatan,
|
||||
},
|
||||
};
|
||||
|
||||
const res = await fetch(
|
||||
|
||||
@@ -354,14 +354,39 @@ const kategoriKegiatan = proxy({
|
||||
id: string;
|
||||
nama: string;
|
||||
}> | null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.lingkungan.kategorikegiatan[
|
||||
"find-many"
|
||||
].get();
|
||||
if (res.status === 200) {
|
||||
kategoriKegiatan.findMany.data = res.data?.data ?? [];
|
||||
}
|
||||
},
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
loading: false,
|
||||
search: "",
|
||||
load: async (page = 1, limit = 10, search = "") => {
|
||||
kategoriKegiatan.findMany.loading = true; // ✅ Akses langsung via nama path
|
||||
kategoriKegiatan.findMany.page = page;
|
||||
kategoriKegiatan.findMany.search = search;
|
||||
|
||||
try {
|
||||
const query: any = { page, limit };
|
||||
if (search) query.search = search;
|
||||
|
||||
const res =
|
||||
await ApiFetch.api.lingkungan.kategorikegiatan[
|
||||
"find-many"
|
||||
].get({ query });
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
kategoriKegiatan.findMany.data = res.data.data ?? [];
|
||||
kategoriKegiatan.findMany.totalPages = res.data.totalPages ?? 1;
|
||||
} else {
|
||||
kategoriKegiatan.findMany.data = [];
|
||||
kategoriKegiatan.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Gagal fetch kategori kegiatan paginated:", err);
|
||||
kategoriKegiatan.findMany.data = [];
|
||||
kategoriKegiatan.findMany.totalPages = 1;
|
||||
} finally {
|
||||
kategoriKegiatan.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
findUnique: {
|
||||
data: null as Prisma.KategoriKegiatanGetPayload<{
|
||||
|
||||
@@ -4,7 +4,7 @@ import colors from '@/con/colors';
|
||||
import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title, Tooltip } from '@mantine/core';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IconFileText, IconBuildingStore, IconSparkles, IconUsers } from '@tabler/icons-react';
|
||||
import { IconFileText, IconBuildingStore, IconSparkles, IconUsers, IconUsersPlus } from '@tabler/icons-react';
|
||||
|
||||
function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
@@ -37,6 +37,13 @@ function LayoutTabsLayanan({ children }: { children: React.ReactNode }) {
|
||||
href: "/admin/desa/layanan/pelayanan_penduduk_non_permanent",
|
||||
icon: <IconUsers size={18} stroke={1.8} />,
|
||||
tooltip: "Pendataan penduduk non-permanent"
|
||||
},
|
||||
{
|
||||
label: "Ajukan Permohonan",
|
||||
value: "ajukanpermohonan",
|
||||
href: "/admin/desa/layanan/ajukan_permohonan",
|
||||
icon: <IconUsersPlus size={18} stroke={1.8} />,
|
||||
tooltip: "Ajukan permohonan"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ function EditKategoriBerita() {
|
||||
<TextInput
|
||||
label="Nama Kategori Berita"
|
||||
placeholder="Masukkan nama kategori berita"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -7,10 +7,9 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -62,9 +61,9 @@ function CreateKategoriBerita() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Kategori Berita</Text>}
|
||||
label="Nama Kategori Berita"
|
||||
placeholder="Masukkan nama kategori berita"
|
||||
value={createState.create.form.name || ''}
|
||||
defaultValue={createState.create.form.name || ''}
|
||||
onChange={(e) => (createState.create.form.name = e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -131,17 +131,36 @@ function EditBerita() {
|
||||
<TextInput
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul"
|
||||
value={formData.judul}
|
||||
defaultValue={formData.judul}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, judul: e.target.value })
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<Select
|
||||
value={formData.kategoriBeritaId}
|
||||
onChange={(val) =>
|
||||
setFormData({ ...formData, kategoriBeritaId: val || "" })
|
||||
}
|
||||
label="Kategori"
|
||||
placeholder="Pilih kategori"
|
||||
data={
|
||||
beritaState.kategoriBerita.findMany.data?.map((v) => ({
|
||||
value: v.id,
|
||||
label: v.name,
|
||||
})) || []
|
||||
}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
error={!formData.kategoriBeritaId ? "Pilih kategori" : undefined}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Deskripsi"
|
||||
placeholder="Masukkan deskripsi"
|
||||
value={formData.deskripsi}
|
||||
label="Deskripsi Singkat"
|
||||
placeholder="Masukkan deskripsi singkat"
|
||||
defaultValue={formData.deskripsi}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, deskripsi: e.target.value })
|
||||
}
|
||||
@@ -216,26 +235,6 @@ function EditBerita() {
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Select
|
||||
value={formData.kategoriBeritaId}
|
||||
onChange={(val) =>
|
||||
setFormData({ ...formData, kategoriBeritaId: val || "" })
|
||||
}
|
||||
label="Kategori"
|
||||
placeholder="Pilih kategori"
|
||||
data={
|
||||
beritaState.kategoriBerita.findMany.data?.map((v) => ({
|
||||
value: v.id,
|
||||
label: v.name,
|
||||
})) || []
|
||||
}
|
||||
clearable
|
||||
searchable
|
||||
required
|
||||
error={!formData.kategoriBeritaId ? "Pilih kategori" : undefined}
|
||||
/>
|
||||
|
||||
<Group justify="right">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
|
||||
@@ -80,7 +80,7 @@ function DetailBerita() {
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||
<Text fz="md" c="dimmed">{data.deskripsi || '-'}</Text>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{data.deskripsi || '-'}</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
|
||||
@@ -100,7 +100,7 @@ export default function CreateBerita() {
|
||||
<TextInput
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul berita"
|
||||
value={beritaState.berita.create.form.judul}
|
||||
defaultValue={beritaState.berita.create.form.judul}
|
||||
onChange={(e) => (beritaState.berita.create.form.judul = e.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -112,7 +112,7 @@ export default function CreateBerita() {
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))}
|
||||
value={beritaState.berita.create.form.kategoriBeritaId || null}
|
||||
defaultValue={beritaState.berita.create.form.kategoriBeritaId || null}
|
||||
onChange={(val: string | null) => {
|
||||
if (val) {
|
||||
const selected = beritaState.kategoriBerita.findMany.data?.find(
|
||||
@@ -133,8 +133,9 @@ export default function CreateBerita() {
|
||||
|
||||
<TextInput
|
||||
label="Deskripsi Singkat"
|
||||
required
|
||||
placeholder="Masukkan deskripsi berita"
|
||||
value={beritaState.berita.create.form.deskripsi}
|
||||
defaultValue={beritaState.berita.create.form.deskripsi}
|
||||
onChange={(e) => (beritaState.berita.create.form.deskripsi = e.target.value)}
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
Button,
|
||||
Center,
|
||||
Group,
|
||||
Image,
|
||||
Pagination,
|
||||
Paper,
|
||||
Skeleton,
|
||||
@@ -18,7 +17,7 @@ import {
|
||||
TableTr,
|
||||
Text,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconCircleDashedPlus, IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
@@ -87,7 +86,6 @@ function ListBerita({ search }: { search: string }) {
|
||||
<TableTr>
|
||||
<TableTh style={{ width: '30%' }}>Judul</TableTh>
|
||||
<TableTh style={{ width: '20%' }}>Kategori</TableTh>
|
||||
<TableTh style={{ width: '25%' }}>Gambar</TableTh>
|
||||
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
@@ -96,7 +94,7 @@ function ListBerita({ search }: { search: string }) {
|
||||
filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd style={{ width: '30%' }}>
|
||||
<Box w={200}>
|
||||
<Box w={150}>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.judul}
|
||||
</Text>
|
||||
@@ -107,19 +105,6 @@ function ListBerita({ search }: { search: string }) {
|
||||
{item.kategoriBerita?.name || '-'}
|
||||
</Text>
|
||||
</TableTd>
|
||||
<TableTd style={{ width: '25%' }}>
|
||||
<Box
|
||||
w={80}
|
||||
h={80}
|
||||
style={{ borderRadius: 8, overflow: 'hidden' }}
|
||||
>
|
||||
{item.image?.link ? (
|
||||
<Image loading='lazy' src={item.image.link} alt="gambar" fit="cover" />
|
||||
) : (
|
||||
<Box bg={colors['blue-button']} w="100%" h="100%" />
|
||||
)}
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ width: '15%' }}>
|
||||
<Button
|
||||
variant="light"
|
||||
|
||||
@@ -102,7 +102,7 @@ function EditVideo() {
|
||||
<TextInput
|
||||
label="Judul Video"
|
||||
placeholder="Masukkan judul video"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -111,7 +111,7 @@ function EditVideo() {
|
||||
<TextInput
|
||||
label="Link Video YouTube"
|
||||
placeholder="https://www.youtube.com/watch?v=abc123"
|
||||
value={formData.linkVideo}
|
||||
defaultValue={formData.linkVideo}
|
||||
onChange={(e) => setFormData({ ...formData, linkVideo: e.currentTarget.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -102,6 +102,7 @@ function DetailVideo() {
|
||||
fz="md"
|
||||
c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
) : (
|
||||
<Text fz="sm" c="dimmed">Tidak ada deskripsi</Text>
|
||||
|
||||
@@ -80,7 +80,7 @@ function CreateVideo() {
|
||||
<TextInput
|
||||
label="Judul Video"
|
||||
placeholder="Masukkan judul video"
|
||||
value={videoState.create.form.name}
|
||||
defaultValue={videoState.create.form.name}
|
||||
onChange={(e) => {
|
||||
videoState.create.form.name = e.currentTarget.value;
|
||||
}}
|
||||
@@ -91,7 +91,7 @@ function CreateVideo() {
|
||||
<TextInput
|
||||
label="Link Video YouTube"
|
||||
placeholder="https://www.youtube.com/watch?v=abc123"
|
||||
value={link}
|
||||
defaultValue={link}
|
||||
onChange={(e) => setLink(e.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
'use client'
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Group,
|
||||
Paper,
|
||||
Select,
|
||||
Stack,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function EditAjukanPermohonan() {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const stateAjukan = useProxy(stateLayananDesa.ajukanPermohonan);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
nama: stateAjukan.edit.form.nama,
|
||||
nik: stateAjukan.edit.form.nik,
|
||||
alamat: stateAjukan.edit.form.alamat,
|
||||
nomorKk: stateAjukan.edit.form.nomorKk,
|
||||
kategoriId: stateAjukan.edit.form.kategoriId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
stateLayananDesa.suratKeterangan.findManyAll.load();
|
||||
const loadAjukan = async () => {
|
||||
const id = params?.id as string;
|
||||
if (!id) return;
|
||||
|
||||
try {
|
||||
const data = await stateAjukan.edit.load(id);
|
||||
if (data) {
|
||||
setFormData({
|
||||
nama: data.nama || '',
|
||||
nik: data.nik || '',
|
||||
alamat: data.alamat || '',
|
||||
nomorKk: data.nomorKk || '',
|
||||
kategoriId: data.kategoriId || '',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading ajukan:', error);
|
||||
toast.error('Gagal memuat data ajukan');
|
||||
}
|
||||
};
|
||||
|
||||
loadAjukan();
|
||||
}, [params?.id]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
stateAjukan.edit.form = {
|
||||
...stateAjukan.edit.form,
|
||||
...formData,
|
||||
};
|
||||
toast.success('Ajukan berhasil diperbarui!');
|
||||
router.push('/admin/desa/layanan/ajukan_permohonan');
|
||||
} catch (error) {
|
||||
console.error('Error updating ajukan:', error);
|
||||
toast.error('Terjadi kesalahan saat memperbarui ajukan');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
||||
{/* Back Button */}
|
||||
<Group mb="md">
|
||||
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
|
||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||
<IconArrowBack color={colors['blue-button']} size={24} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Title order={4} ml="sm" c="dark">
|
||||
Edit Ajukan Permohonan
|
||||
</Title>
|
||||
</Group>
|
||||
|
||||
<Paper
|
||||
w={{ base: '100%', md: '50%' }}
|
||||
bg={colors['white-1']}
|
||||
p="lg"
|
||||
radius="md"
|
||||
shadow="sm"
|
||||
style={{ border: '1px solid #e0e0e0' }}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label="Nama"
|
||||
placeholder="Masukkan nama"
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
type="number"
|
||||
label="NIK"
|
||||
placeholder="Masukkan NIK"
|
||||
defaultValue={formData.nik}
|
||||
onChange={(e) => setFormData({ ...formData, nik: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder="Masukkan alamat"
|
||||
defaultValue={formData.alamat}
|
||||
onChange={(e) => setFormData({ ...formData, alamat: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
type="number"
|
||||
label="Nomor KK"
|
||||
placeholder="Masukkan nomor KK"
|
||||
defaultValue={formData.nomorKk}
|
||||
onChange={(e) => setFormData({ ...formData, nomorKk: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
<Select
|
||||
label="Kategori"
|
||||
placeholder="Pilih kategori"
|
||||
data={stateLayananDesa.suratKeterangan.findManyAll.data?.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))}
|
||||
value={formData.kategoriId || null}
|
||||
onChange={(val: string | null) => {
|
||||
if (val) {
|
||||
const selected = stateLayananDesa.suratKeterangan.findMany.data?.find(
|
||||
(item) => item.id === val
|
||||
);
|
||||
if (selected) {
|
||||
stateAjukan.edit.form.kategoriId = selected.id;
|
||||
}
|
||||
} else {
|
||||
stateAjukan.edit.form.kategoriId = '';
|
||||
}
|
||||
}}
|
||||
searchable
|
||||
clearable
|
||||
nothingFoundMessage="Tidak ditemukan"
|
||||
required
|
||||
/>
|
||||
|
||||
<Group justify="right">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
radius="md"
|
||||
size="md"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
|
||||
color: '#fff',
|
||||
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
|
||||
}}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditAjukanPermohonan;
|
||||
@@ -0,0 +1,172 @@
|
||||
'use client'
|
||||
import { ModalKonfirmasiHapus } from '@/app/admin/(dashboard)/_com/modalKonfirmasiHapus';
|
||||
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Group,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Text,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function DetailAjukanPermohonan() {
|
||||
const ajukanPermohonanState = useProxy(stateLayananDesa.ajukanPermohonan);
|
||||
const [modalHapus, setModalHapus] = useState(false);
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
|
||||
useShallowEffect(() => {
|
||||
ajukanPermohonanState.findUnique.load(params?.id as string);
|
||||
}, []);
|
||||
|
||||
const handleHapus = () => {
|
||||
if (selectedId) {
|
||||
ajukanPermohonanState.delete.byId(selectedId);
|
||||
setModalHapus(false);
|
||||
setSelectedId(null);
|
||||
router.push('/admin/desa/layanan/ajukan_permohonan');
|
||||
}
|
||||
};
|
||||
|
||||
if (!ajukanPermohonanState.findUnique.data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton height={500} radius="md" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const data = ajukanPermohonanState.findUnique.data;
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
{/* Tombol Kembali */}
|
||||
<Button
|
||||
variant="subtle"
|
||||
onClick={() => router.back()}
|
||||
leftSection={<IconArrowBack size={24} color={colors['blue-button']} />}
|
||||
mb={15}
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
|
||||
<Paper
|
||||
withBorder
|
||||
w={{ base: '100%', md: '60%' }}
|
||||
bg={colors['white-1']}
|
||||
p="lg"
|
||||
radius="md"
|
||||
shadow="sm"
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text fz="2xl" fw="bold" c={colors['blue-button']}>
|
||||
Detail Surat Keterangan
|
||||
</Text>
|
||||
|
||||
<Paper bg="#ECEEF8" p="md" radius="md" shadow="xs">
|
||||
<Stack gap="sm">
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">
|
||||
Nama
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>
|
||||
{data?.nama || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">
|
||||
NIK
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed">
|
||||
{data?.nik || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">
|
||||
Alamat
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>
|
||||
{data?.alamat || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">
|
||||
Nomor KK
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed">
|
||||
{data?.nomorKk || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">
|
||||
Kategori
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed">
|
||||
{data?.kategori.name || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Group gap="sm">
|
||||
<Tooltip label="Hapus Surat" withArrow position="top">
|
||||
<Button
|
||||
color="red"
|
||||
onClick={() => {
|
||||
setSelectedId(data.id);
|
||||
setModalHapus(true);
|
||||
}}
|
||||
variant="light"
|
||||
radius="md"
|
||||
size="md"
|
||||
disabled={ajukanPermohonanState.delete.loading}
|
||||
>
|
||||
<IconTrash size={20} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip label="Edit Surat" withArrow position="top">
|
||||
<Button
|
||||
color="green"
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/admin/desa/layanan/ajukan_permohonan/${data.id}/edit`
|
||||
)
|
||||
}
|
||||
variant="light"
|
||||
radius="md"
|
||||
size="md"
|
||||
>
|
||||
<IconEdit size={20} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
{/* Modal Konfirmasi Hapus */}
|
||||
<ModalKonfirmasiHapus
|
||||
opened={modalHapus}
|
||||
onClose={() => setModalHapus(false)}
|
||||
onConfirm={handleHapus}
|
||||
text="Apakah Anda yakin ingin menghapus ajukan permohonan ini?"
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default DetailAjukanPermohonan;
|
||||
@@ -0,0 +1,155 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
Pagination,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Table,
|
||||
TableTbody,
|
||||
TableTd,
|
||||
TableTh,
|
||||
TableThead,
|
||||
TableTr,
|
||||
Text,
|
||||
Title
|
||||
} from '@mantine/core';
|
||||
import { IconDeviceImacCog, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import HeaderSearch from '../../../_com/header';
|
||||
import stateLayananDesa from '../../../_state/desa/layananDesa';
|
||||
|
||||
function AjukanPermohonan() {
|
||||
const [search, setSearch] = useState("");
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Pelayanan Ajukan Permohonan'
|
||||
placeholder='Cari nama atau deskripsi...'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListAjukanPermohonan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListAjukanPermohonan({ search }: { search: string }) {
|
||||
const AjukanPermohonanState = useProxy(stateLayananDesa.ajukanPermohonan);
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = AjukanPermohonanState.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10, search);
|
||||
}, [page, search]);
|
||||
|
||||
// Loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton height={600} radius="md" />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
||||
<Title order={4}>List Ajukan Permohonan</Title>
|
||||
<Box style={{ overflowX: "auto" }}>
|
||||
<Table highlightOnHover>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh style={{ width: '30%' }}>Nama</TableTh>
|
||||
<TableTh style={{ width: '45%' }}>Alamat</TableTh>
|
||||
<TableTh style={{ width: '15%' }}>NIK</TableTh>
|
||||
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
{data.length > 0 ? (
|
||||
data.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd style={{ width: '30%' }}>
|
||||
<Box w={200}>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.nama}
|
||||
</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ width: '45%' }}>
|
||||
<Box w={200}>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.alamat}
|
||||
</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ width: '45%' }}>
|
||||
<Box w={200}>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.nik}
|
||||
</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd style={{ width: '15%' }}>
|
||||
<Button
|
||||
size="xs"
|
||||
radius="md"
|
||||
variant="light"
|
||||
color="blue"
|
||||
leftSection={<IconDeviceImacCog size={16} />}
|
||||
onClick={() =>
|
||||
router.push(`/admin/desa/layanan/ajukan_permohonan/${item.id}`)
|
||||
}
|
||||
>
|
||||
Detail
|
||||
</Button>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))
|
||||
) : (
|
||||
<TableTr>
|
||||
<TableTd colSpan={3}>
|
||||
<Center py={20}>
|
||||
<Text color="dimmed">Tidak ada data ajukan permohonan yang cocok</Text>
|
||||
</Center>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
)}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10, search);
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
color="blue"
|
||||
radius="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default AjukanPermohonan;
|
||||
@@ -76,7 +76,7 @@ function EditPelayananPendudukNonPermanent() {
|
||||
<TextInput
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ function PelayananPendudukNonPermanent() {
|
||||
ta="justify"
|
||||
fz={{ base: '1rem', md: '1.2rem' }}
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -83,7 +83,7 @@ function EditPelayananPerizinanBerusaha() {
|
||||
<TextInput
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -92,7 +92,7 @@ function EditPelayananPerizinanBerusaha() {
|
||||
<TextInput
|
||||
label="Link"
|
||||
placeholder="Masukkan link terkait"
|
||||
value={formData.link}
|
||||
defaultValue={formData.link}
|
||||
onChange={(e) => setFormData({ ...formData, link: e.target.value })}
|
||||
/>
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ function PerizinanBerusaha() {
|
||||
ta="justify"
|
||||
fz={{ base: '1rem', md: '1.2rem' }}
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi }}
|
||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||
/>
|
||||
|
||||
<Text
|
||||
|
||||
@@ -122,7 +122,7 @@ function EditSuratKeterangan() {
|
||||
<TextInput
|
||||
label="Nama Surat Keterangan"
|
||||
placeholder="Masukkan nama surat keterangan"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -95,6 +95,7 @@ function DetailSuratKeterangan() {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: data?.deskripsi || '-',
|
||||
}}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -106,9 +106,9 @@ function CreateSuratKeterangan() {
|
||||
<Stack gap="md">
|
||||
{/* Nama Surat */}
|
||||
<TextInput
|
||||
value={stateSurat.create.form.name}
|
||||
defaultValue={stateSurat.create.form.name}
|
||||
onChange={(val) => (stateSurat.create.form.name = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Nama Surat Keterangan</Text>}
|
||||
label="Nama Surat Keterangan"
|
||||
placeholder="Masukkan nama surat keterangan"
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -119,6 +119,7 @@ function ListSuratKeterangan({ search }: { search: string }) {
|
||||
<Box w={200}>
|
||||
<Text truncate="end" lineClamp={1} fz="sm" c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||
/>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
@@ -94,7 +94,7 @@ function EditPelayananTelunjukSakti() {
|
||||
<TextInput
|
||||
label="Nama Pelayanan"
|
||||
placeholder="Masukkan nama pelayanan"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -114,7 +114,7 @@ function EditPelayananTelunjukSakti() {
|
||||
<TextInput
|
||||
label="Link"
|
||||
placeholder="Masukkan link terkait"
|
||||
value={formData.link}
|
||||
defaultValue={formData.link}
|
||||
onChange={(e) => setFormData({ ...formData, link: e.target.value })}
|
||||
/>
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ function DetailPelayananTelunjukSakti() {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{data.link}
|
||||
@@ -124,6 +125,7 @@ function DetailPelayananTelunjukSakti() {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: data?.deskripsi || '-',
|
||||
}}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -8,15 +8,14 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
|
||||
function CreatePelayananTelunjukDesa() {
|
||||
const stateTelunjukDesa = useProxy(stateLayananDesa.pelayananTelunjukSaktiDesa);
|
||||
@@ -68,33 +67,35 @@ function CreatePelayananTelunjukDesa() {
|
||||
<Stack gap="md">
|
||||
{/* Nama */}
|
||||
<TextInput
|
||||
value={stateTelunjukDesa.create.form.name}
|
||||
defaultValue={stateTelunjukDesa.create.form.name}
|
||||
onChange={(val) => {
|
||||
stateTelunjukDesa.create.form.name = val.target.value;
|
||||
}}
|
||||
label={<Text fz="sm" fw="bold">Nama Pelayanan</Text>}
|
||||
label="Nama Pelayanan"
|
||||
placeholder="Masukkan nama pelayanan telunjuk sakti desa"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Deskripsi */}
|
||||
<TextInput
|
||||
value={stateTelunjukDesa.create.form.deskripsi}
|
||||
defaultValue={stateTelunjukDesa.create.form.deskripsi}
|
||||
onChange={(val) => {
|
||||
stateTelunjukDesa.create.form.deskripsi = val.target.value;
|
||||
}}
|
||||
label={<Text fz="sm" fw="bold">Deskripsi</Text>}
|
||||
label="Deskripsi"
|
||||
placeholder="Masukkan deskripsi pelayanan"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Link */}
|
||||
<TextInput
|
||||
value={stateTelunjukDesa.create.form.link}
|
||||
defaultValue={stateTelunjukDesa.create.form.link}
|
||||
onChange={(val) => {
|
||||
stateTelunjukDesa.create.form.link = val.target.value;
|
||||
}}
|
||||
label={<Text fz="sm" fw="bold">Link</Text>}
|
||||
label="Link"
|
||||
placeholder="Masukkan link pelayanan"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Tombol Simpan */}
|
||||
|
||||
@@ -261,7 +261,7 @@ function ListPelayananTelunjukSakti({ search }: { search: string }) {
|
||||
<TableTd>
|
||||
<Box w={200}>
|
||||
<a href={item.link} target="_blank" rel="noopener noreferrer">
|
||||
<Text lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }} truncate="end" fz={"sm"} />
|
||||
<Text lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }} style={{wordBreak: "break-word", whiteSpace: "normal"}} truncate="end" fz={"sm"} />
|
||||
</a>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
@@ -122,7 +122,7 @@ function EditPenghargaan() {
|
||||
<TextInput
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul penghargaan"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -131,7 +131,7 @@ function EditPenghargaan() {
|
||||
<TextInput
|
||||
label="Juara"
|
||||
placeholder="Masukkan juara"
|
||||
value={formData.juara}
|
||||
defaultValue={formData.juara}
|
||||
onChange={(e) => setFormData({ ...formData, juara: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -122,6 +122,7 @@ function DetailPenghargaan() {
|
||||
fz="md"
|
||||
c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -87,17 +87,17 @@ function CreatePenghargaan() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
value={statePenghargaan.create.form.name}
|
||||
defaultValue={statePenghargaan.create.form.name}
|
||||
onChange={(val) => (statePenghargaan.create.form.name = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Nama Penghargaan</Text>}
|
||||
label="Nama Penghargaan"
|
||||
placeholder="Masukkan nama penghargaan"
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
value={statePenghargaan.create.form.juara}
|
||||
defaultValue={statePenghargaan.create.form.juara}
|
||||
onChange={(val) => (statePenghargaan.create.form.juara = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Juara</Text>}
|
||||
label="Juara"
|
||||
placeholder="Masukkan juara"
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -108,6 +108,7 @@ function ListPenghargaan({ search }: { search: string }) {
|
||||
fz="sm"
|
||||
c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||
/>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
Stack,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Text,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
@@ -95,11 +94,7 @@ function EditKategoriPengumuman() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label={
|
||||
<Text fz="sm" fw="bold">
|
||||
Nama Kategori Pengumuman
|
||||
</Text>
|
||||
}
|
||||
label="Nama Kategori Pengumuman"
|
||||
placeholder="Masukkan nama kategori Pengumuman"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
|
||||
@@ -7,10 +7,9 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -62,9 +61,9 @@ function CreateKategoriPengumuman() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Kategori Pengumuman</Text>}
|
||||
label="Nama Kategori Pengumuman"
|
||||
placeholder="Masukkan nama kategori pengumuman"
|
||||
value={createState.create.form.name || ''}
|
||||
defaultValue={createState.create.form.name || ''}
|
||||
onChange={(e) => (createState.create.form.name = e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -108,7 +108,7 @@ function EditPengumuman() {
|
||||
<TextInput
|
||||
label="Judul Pengumuman"
|
||||
placeholder="Masukkan judul"
|
||||
value={formData.judul}
|
||||
defaultValue={formData.judul}
|
||||
onChange={(e) => setFormData({ ...formData, judul: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -116,7 +116,7 @@ function EditPengumuman() {
|
||||
<TextInput
|
||||
label="Deskripsi Singkat"
|
||||
placeholder="Masukkan deskripsi"
|
||||
value={formData.deskripsi}
|
||||
defaultValue={formData.deskripsi}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, deskripsi: e.target.value })
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ export default function DetailPengumuman() {
|
||||
<Text fz="lg" fw="bold">
|
||||
Deskripsi
|
||||
</Text>
|
||||
<Text fz="md" c="dimmed">
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>
|
||||
{data?.deskripsi || '-'}
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -112,6 +112,7 @@ export default function DetailPengumuman() {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: data?.content || '-',
|
||||
}}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -68,16 +68,16 @@ function CreatePengumuman() {
|
||||
<Stack gap="md">
|
||||
{/* Judul */}
|
||||
<TextInput
|
||||
value={pengumumanState.pengumuman.create.form.judul}
|
||||
defaultValue={pengumumanState.pengumuman.create.form.judul}
|
||||
onChange={(val) => (pengumumanState.pengumuman.create.form.judul = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Judul</Text>}
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul pengumuman"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Kategori */}
|
||||
<Select
|
||||
label={<Text fz="sm" fw="bold">Kategori</Text>}
|
||||
label="Kategori"
|
||||
placeholder="Pilih kategori"
|
||||
value={pengumumanState.pengumuman.create.form.categoryPengumumanId || ""}
|
||||
onChange={(val) => {
|
||||
@@ -93,9 +93,9 @@ function CreatePengumuman() {
|
||||
|
||||
{/* Deskripsi Singkat */}
|
||||
<TextInput
|
||||
value={pengumumanState.pengumuman.create.form.deskripsi}
|
||||
defaultValue={pengumumanState.pengumuman.create.form.deskripsi}
|
||||
onChange={(val) => (pengumumanState.pengumuman.create.form.deskripsi = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Deskripsi Singkat</Text>}
|
||||
label="Deskripsi Singkat"
|
||||
placeholder="Masukkan deskripsi singkat"
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -94,9 +94,11 @@ function ListPengumuman({ search }: { search: string }) {
|
||||
filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.judul}
|
||||
</Text>
|
||||
<Box w={150}>
|
||||
<Text fw={500} truncate="end" lineClamp={1}>
|
||||
{item.judul}
|
||||
</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text fz="sm" c="dimmed">
|
||||
|
||||
@@ -89,7 +89,7 @@ function EditKategoriPotensi() {
|
||||
<TextInput
|
||||
label="Nama Kategori Potensi"
|
||||
placeholder="Masukkan nama kategori potensi"
|
||||
value={formData.nama}
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -7,10 +7,9 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -62,9 +61,9 @@ function CreateKategoriPotensi() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Kategori Potensi</Text>}
|
||||
label="Nama Kategori Potensi"
|
||||
placeholder="Masukkan nama kategori potensi"
|
||||
value={createState.create.form.nama || ''}
|
||||
defaultValue={createState.create.form.nama || ''}
|
||||
onChange={(e) => (createState.create.form.nama = e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Center, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title, Tooltip, Pagination } from '@mantine/core';
|
||||
import { Box, Button, Center, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title, Tooltip, Pagination, Group } from '@mantine/core';
|
||||
import { IconEdit, IconSearch, IconTrash, IconPlus } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -60,7 +60,7 @@ function ListKategoriPotensi({ search }: { search: string }) {
|
||||
<Box py={10}>
|
||||
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
||||
<Stack>
|
||||
<Box style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 15 }}>
|
||||
<Group justify="space-between">
|
||||
<Title order={4}>List Kategori Potensi</Title>
|
||||
<Tooltip label="Tambah Kategori Potensi" withArrow>
|
||||
<Button
|
||||
@@ -72,7 +72,7 @@ function ListKategoriPotensi({ search }: { search: string }) {
|
||||
Tambah Baru
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Group>
|
||||
|
||||
<Box style={{ overflowX: 'auto' }}>
|
||||
<Table highlightOnHover striped withRowBorders style={{ minWidth: '700px' }}>
|
||||
|
||||
@@ -122,7 +122,7 @@ function EditPotensi() {
|
||||
<TextInput
|
||||
label="Judul Potensi"
|
||||
placeholder="Masukkan judul"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -130,7 +130,7 @@ function EditPotensi() {
|
||||
<TextInput
|
||||
label="Deskripsi Singkat"
|
||||
placeholder="Masukkan deskripsi"
|
||||
value={formData.deskripsi}
|
||||
defaultValue={formData.deskripsi}
|
||||
onChange={(e) => setFormData({ ...formData, deskripsi: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function DetailPotensi() {
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||
<Text fz="md" c="dimmed">{data.deskripsi || '-'}</Text>
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{data.deskripsi || '-'}</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
@@ -103,6 +103,7 @@ export default function DetailPotensi() {
|
||||
fz="md"
|
||||
c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: data.content || '-' }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -93,25 +93,25 @@ function CreatePotensi() {
|
||||
<Stack gap="md">
|
||||
{/* Judul */}
|
||||
<TextInput
|
||||
value={potensiState.create.form.name}
|
||||
defaultValue={potensiState.create.form.name}
|
||||
onChange={(val) => (potensiState.create.form.name = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Judul</Text>}
|
||||
label="Judul"
|
||||
placeholder="Masukkan judul potensi"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Deskripsi */}
|
||||
<TextInput
|
||||
value={potensiState.create.form.deskripsi}
|
||||
defaultValue={potensiState.create.form.deskripsi}
|
||||
onChange={(val) => (potensiState.create.form.deskripsi = val.target.value)}
|
||||
label={<Text fz="sm" fw="bold">Deskripsi</Text>}
|
||||
label="Deskripsi"
|
||||
placeholder="Masukkan deskripsi singkat"
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Kategori */}
|
||||
<Select
|
||||
label={<Text fz="sm" fw="bold">Kategori</Text>}
|
||||
label="Kategori"
|
||||
placeholder="Pilih kategori"
|
||||
value={potensiState.create.form.kategoriId || ""}
|
||||
onChange={(val) => {
|
||||
|
||||
@@ -115,6 +115,7 @@ function ListPotensi({ search }: { search: string }) {
|
||||
truncate
|
||||
fz="sm"
|
||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||
style={{wordBreak: "break-word", whiteSpace: "normal"}}
|
||||
/>
|
||||
</Box>
|
||||
</TableTd>
|
||||
|
||||
@@ -115,7 +115,7 @@ function Page() {
|
||||
<TextInput
|
||||
label={<Text fw="bold">Judul</Text>}
|
||||
placeholder="Judul lambang"
|
||||
value={lambangState.update.form.judul}
|
||||
defaultValue={lambangState.update.form.judul}
|
||||
onChange={(e) => lambangState.update.form.judul = e.currentTarget.value}
|
||||
error={!lambangState.update.form.judul && "Judul wajib diisi"}
|
||||
/>
|
||||
|
||||
@@ -175,7 +175,7 @@ function Page() {
|
||||
<TextInput
|
||||
label={<Text fw="bold">Judul</Text>}
|
||||
placeholder="Masukkan judul maskot"
|
||||
value={formData.judul}
|
||||
defaultValue={formData.judul}
|
||||
onChange={(e) => setFormData({ ...formData, judul: e.currentTarget.value })}
|
||||
error={!formData.judul && "Judul wajib diisi"}
|
||||
/>
|
||||
|
||||
@@ -116,7 +116,7 @@ function Page() {
|
||||
<TextInput
|
||||
label={<Text fw="bold">Judul</Text>}
|
||||
placeholder="Judul sejarah"
|
||||
value={sejarahState.update.form.judul}
|
||||
defaultValue={sejarahState.update.form.judul}
|
||||
onChange={(e) => sejarahState.update.form.judul = e.currentTarget.value}
|
||||
error={!sejarahState.update.form.judul && "Judul wajib diisi"}
|
||||
/>
|
||||
|
||||
@@ -70,7 +70,7 @@ function Page() {
|
||||
</Paper>
|
||||
</Stack>
|
||||
<Divider my="md" color={colors['blue-button']} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" dangerouslySetInnerHTML={{ __html: sejarah.deskripsi }} />
|
||||
<Text fz={{ base: "md", md: "h3" }} style={{wordBreak: "break-word", whiteSpace: "normal"}} ta="justify" dangerouslySetInnerHTML={{ __html: sejarah.deskripsi }} />
|
||||
</Paper>
|
||||
</Box>
|
||||
</Paper>
|
||||
@@ -118,9 +118,9 @@ function Page() {
|
||||
</Stack>
|
||||
<Divider my="md" color={colors['blue-button']} />
|
||||
<Text fw="bold" fz={{ base: "lg", md: "h2" }}>Visi Desa</Text>
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" dangerouslySetInnerHTML={{ __html: visiMisi.visi }} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: visiMisi.visi }} />
|
||||
<Text fw="bold" fz={{ base: "lg", md: "h2" }}>Misi Desa</Text>
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" dangerouslySetInnerHTML={{ __html: visiMisi.misi }} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: visiMisi.misi }} />
|
||||
</Paper>
|
||||
</Box>
|
||||
</Paper>
|
||||
@@ -167,7 +167,7 @@ function Page() {
|
||||
</Paper>
|
||||
</Stack>
|
||||
<Divider my="md" color={colors['blue-button']} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" dangerouslySetInnerHTML={{ __html: lambang.deskripsi }} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: lambang.deskripsi }} />
|
||||
</Paper>
|
||||
</Box>
|
||||
</Paper>
|
||||
@@ -214,7 +214,7 @@ function Page() {
|
||||
</Paper>
|
||||
</Stack>
|
||||
<Divider my="md" color={colors['blue-button']} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" dangerouslySetInnerHTML={{ __html: maskot.deskripsi }} />
|
||||
<Text fz={{ base: "md", md: "h3" }} ta="justify" style={{wordBreak: "break-word", whiteSpace: "normal"}} dangerouslySetInnerHTML={{ __html: maskot.deskripsi }} />
|
||||
<Stack mt="md" gap="sm">
|
||||
<SimpleGrid cols={{ base: 2, md: 4 }} spacing="md">
|
||||
{maskot.images.map((img, idx) => (
|
||||
|
||||
@@ -106,7 +106,7 @@ function EditPerbekelDariMasaKeMasa() {
|
||||
<TextInput
|
||||
label="Nama"
|
||||
placeholder="Masukkan nama"
|
||||
value={formData.nama}
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -170,7 +170,7 @@ function EditPerbekelDariMasaKeMasa() {
|
||||
<TextInput
|
||||
label="Daerah"
|
||||
placeholder="Masukkan daerah"
|
||||
value={formData.daerah}
|
||||
defaultValue={formData.daerah}
|
||||
onChange={(e) => setFormData({ ...formData, daerah: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -178,7 +178,7 @@ function EditPerbekelDariMasaKeMasa() {
|
||||
<TextInput
|
||||
label="Periode"
|
||||
placeholder="Masukkan periode"
|
||||
value={formData.periode}
|
||||
defaultValue={formData.periode}
|
||||
onChange={(e) => setFormData({ ...formData, periode: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -70,23 +70,23 @@ function CreatePerbekelDariMasaKeMasa() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Perbekel</Text>}
|
||||
label="Nama Perbekel"
|
||||
placeholder="Masukkan nama perbekel"
|
||||
value={state.create.form.nama}
|
||||
defaultValue={state.create.form.nama}
|
||||
onChange={(e) => (state.create.form.nama = e.target.value)}
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Daerah</Text>}
|
||||
label="Daerah"
|
||||
placeholder="Masukkan daerah"
|
||||
value={state.create.form.daerah}
|
||||
defaultValue={state.create.form.daerah}
|
||||
onChange={(e) => (state.create.form.daerah = e.target.value)}
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Periode</Text>}
|
||||
label="Periode"
|
||||
placeholder="Masukkan periode"
|
||||
value={state.create.form.periode}
|
||||
defaultValue={state.create.form.periode}
|
||||
onChange={(e) => (state.create.form.periode = e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -97,16 +97,16 @@ function Page() {
|
||||
{/* Biodata & Info */}
|
||||
<Box mt="lg">
|
||||
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mb={4}>Biodata</Text>
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: perbekel.biodata }} />
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: perbekel.biodata }} />
|
||||
|
||||
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mt="md" mb={4}>Pengalaman</Text>
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: perbekel.pengalaman }} />
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: perbekel.pengalaman }} />
|
||||
|
||||
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mt="md" mb={4}>Pengalaman Organisasi</Text>
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: perbekel.pengalamanOrganisasi }} />
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: perbekel.pengalamanOrganisasi }} />
|
||||
|
||||
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mt="md" mb={4}>Program Kerja Unggulan</Text>
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" dangerouslySetInnerHTML={{ __html: perbekel.programUnggulan }} />
|
||||
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: perbekel.programUnggulan }} />
|
||||
</Box>
|
||||
</Paper>
|
||||
</Stack>
|
||||
|
||||
@@ -111,7 +111,7 @@ function EditAPBDesa() {
|
||||
{/* Tahun */}
|
||||
<TextInput
|
||||
type="number"
|
||||
value={formData.tahun}
|
||||
defaultValue={formData.tahun}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, tahun: e.target.value })
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ function CreateAPBDesa() {
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
type="number"
|
||||
value={apbDesaState.create.form.tahun}
|
||||
defaultValue={apbDesaState.create.form.tahun}
|
||||
onChange={(val) => {
|
||||
apbDesaState.create.form.tahun = Number(val.target.value);
|
||||
}}
|
||||
|
||||
@@ -112,7 +112,7 @@ function EditBelanja() {
|
||||
<TextInput
|
||||
label="Nama Jenis Belanja"
|
||||
placeholder="Masukkan nama jenis belanja"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -120,7 +120,7 @@ function EditBelanja() {
|
||||
<TextInput
|
||||
label="Nilai"
|
||||
placeholder="Masukkan nilai"
|
||||
value={formatRupiah(formData.value)}
|
||||
defaultValue={formatRupiah(formData.value)}
|
||||
onChange={(e) => {
|
||||
const raw = e.currentTarget.value;
|
||||
const cleanValue = unformatRupiah(raw);
|
||||
|
||||
@@ -85,7 +85,7 @@ function CreateBelanja() {
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Jenis Belanja</Text>}
|
||||
placeholder="Masukkan nama jenis belanja"
|
||||
value={belanjaState.create.form.name}
|
||||
defaultValue={belanjaState.create.form.name}
|
||||
onChange={(e) => (belanjaState.create.form.name = e.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -94,7 +94,7 @@ function CreateBelanja() {
|
||||
type="text"
|
||||
label={<Text fw="bold" fz="sm">Nilai</Text>}
|
||||
placeholder="Masukkan nilai belanja"
|
||||
value={formatRupiah(belanjaState.create.form.value)}
|
||||
defaultValue={formatRupiah(belanjaState.create.form.value)}
|
||||
onChange={(e) => {
|
||||
const raw = e.currentTarget.value;
|
||||
belanjaState.create.form.value = unformatRupiah(raw);
|
||||
|
||||
@@ -112,7 +112,7 @@ function EditPembiayaan() {
|
||||
<TextInput
|
||||
label="Nama Jenis Pembiayaan"
|
||||
placeholder="Masukkan nama jenis pembiayaan"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -120,7 +120,7 @@ function EditPembiayaan() {
|
||||
<TextInput
|
||||
label="Nilai"
|
||||
placeholder="Masukkan nilai"
|
||||
value={formatRupiah(formData.value)}
|
||||
defaultValue={formatRupiah(formData.value)}
|
||||
onChange={(e) => {
|
||||
const raw = e.currentTarget.value;
|
||||
const cleanValue = unformatRupiah(raw);
|
||||
|
||||
@@ -85,7 +85,7 @@ function CreatePembiayaan() {
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Jenis Pembiayaan</Text>}
|
||||
placeholder="Masukkan nama jenis pembiayaan"
|
||||
value={pembiayaanState.create.form.name}
|
||||
defaultValue={pembiayaanState.create.form.name}
|
||||
onChange={(e) => {
|
||||
pembiayaanState.create.form.name = e.currentTarget.value;
|
||||
}}
|
||||
@@ -96,7 +96,7 @@ function CreatePembiayaan() {
|
||||
type="text"
|
||||
label={<Text fw="bold" fz="sm">Nilai</Text>}
|
||||
placeholder="Masukkan nilai"
|
||||
value={formatRupiah(pembiayaanState.create.form.value)}
|
||||
defaultValue={formatRupiah(pembiayaanState.create.form.value)}
|
||||
onChange={(e) => {
|
||||
const raw = e.currentTarget.value;
|
||||
pembiayaanState.create.form.value = unformatRupiah(raw);
|
||||
|
||||
@@ -110,7 +110,7 @@ function EditPendapatan() {
|
||||
<TextInput
|
||||
label="Nama Jenis Pendapatan"
|
||||
placeholder="Masukkan nama jenis pendapatan"
|
||||
value={formData.name}
|
||||
defaultValue={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -118,7 +118,7 @@ function EditPendapatan() {
|
||||
<TextInput
|
||||
label="Nilai"
|
||||
placeholder="Masukkan nilai"
|
||||
value={formatRupiah(formData.value)}
|
||||
defaultValue={formatRupiah(formData.value)}
|
||||
onChange={(e) => {
|
||||
const raw = e.currentTarget.value;
|
||||
const cleanValue = unformatRupiah(raw);
|
||||
|
||||
@@ -7,10 +7,9 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { IconArrowBack } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -76,32 +75,24 @@ function CreatePendapatan() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
value={pendapatanState.create.form.name}
|
||||
defaultValue={pendapatanState.create.form.name}
|
||||
onChange={(val) => {
|
||||
pendapatanState.create.form.name = val.target.value;
|
||||
}}
|
||||
label={
|
||||
<Text fw="bold" fz="sm">
|
||||
Nama Jenis Pendapatan
|
||||
</Text>
|
||||
}
|
||||
label="Nama Jenis Pendapatan"
|
||||
placeholder="Masukkan nama jenis pendapatan"
|
||||
required
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
type="text"
|
||||
value={formatRupiah(pendapatanState.create.form.value)}
|
||||
defaultValue={formatRupiah(pendapatanState.create.form.value)}
|
||||
onChange={(val) => {
|
||||
const raw = val.currentTarget.value;
|
||||
const cleanValue = unformatRupiah(raw);
|
||||
pendapatanState.create.form.value = cleanValue;
|
||||
}}
|
||||
label={
|
||||
<Text fw="bold" fz="sm">
|
||||
Nilai
|
||||
</Text>
|
||||
}
|
||||
label="Nilai"
|
||||
placeholder="Masukkan nilai"
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -91,7 +91,7 @@ function EditDemografiPekerjaan() {
|
||||
<TextInput
|
||||
label="Pekerjaan"
|
||||
placeholder="Masukkan jenis pekerjaan"
|
||||
value={stateDemografi.update.form.pekerjaan}
|
||||
defaultValue={stateDemografi.update.form.pekerjaan}
|
||||
onChange={(e) =>
|
||||
(stateDemografi.update.form.pekerjaan = e.currentTarget.value)
|
||||
}
|
||||
@@ -102,7 +102,7 @@ function EditDemografiPekerjaan() {
|
||||
label="Jumlah Pekerja Laki-laki"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah pekerja laki-laki"
|
||||
value={stateDemografi.update.form.lakiLaki}
|
||||
defaultValue={stateDemografi.update.form.lakiLaki}
|
||||
onChange={(e) =>
|
||||
(stateDemografi.update.form.lakiLaki = Number(
|
||||
e.currentTarget.value
|
||||
@@ -115,7 +115,7 @@ function EditDemografiPekerjaan() {
|
||||
label="Jumlah Pekerja Perempuan"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah pekerja perempuan"
|
||||
value={stateDemografi.update.form.perempuan}
|
||||
defaultValue={stateDemografi.update.form.perempuan}
|
||||
onChange={(e) =>
|
||||
(stateDemografi.update.form.perempuan = Number(
|
||||
e.currentTarget.value
|
||||
|
||||
@@ -77,7 +77,7 @@ function CreateDemografiPekerjaan() {
|
||||
<TextInput
|
||||
label="Pekerjaan"
|
||||
type="text"
|
||||
value={stateDemografi.create.form.pekerjaan}
|
||||
defaultValue={stateDemografi.create.form.pekerjaan}
|
||||
placeholder="Masukkan pekerjaan"
|
||||
onChange={(val) => {
|
||||
stateDemografi.create.form.pekerjaan = val.currentTarget.value;
|
||||
@@ -87,7 +87,7 @@ function CreateDemografiPekerjaan() {
|
||||
<TextInput
|
||||
label="Jumlah Pekerja Laki-Laki"
|
||||
type="number"
|
||||
value={stateDemografi.create.form.lakiLaki}
|
||||
defaultValue={stateDemografi.create.form.lakiLaki}
|
||||
placeholder="Masukkan jumlah pekerja laki-laki"
|
||||
onChange={(val) => {
|
||||
stateDemografi.create.form.lakiLaki = Number(val.currentTarget.value);
|
||||
@@ -97,7 +97,7 @@ function CreateDemografiPekerjaan() {
|
||||
<TextInput
|
||||
label="Jumlah Pekerja Perempuan"
|
||||
type="number"
|
||||
value={stateDemografi.create.form.perempuan}
|
||||
defaultValue={stateDemografi.create.form.perempuan}
|
||||
placeholder="Masukkan jumlah pekerja perempuan"
|
||||
onChange={(val) => {
|
||||
stateDemografi.create.form.perempuan = Number(val.currentTarget.value);
|
||||
|
||||
@@ -78,7 +78,7 @@ function EditJumlahPendudukMiskin() {
|
||||
placeholder="Masukkan tahun"
|
||||
type="number"
|
||||
required
|
||||
value={stateJPM.update.form.year}
|
||||
defaultValue={stateJPM.update.form.year}
|
||||
onChange={(val) => {
|
||||
stateJPM.update.form.year = Number(val.currentTarget.value);
|
||||
}}
|
||||
@@ -89,7 +89,7 @@ function EditJumlahPendudukMiskin() {
|
||||
placeholder="Masukkan jumlah penduduk miskin"
|
||||
type="number"
|
||||
required
|
||||
value={stateJPM.update.form.totalPoorPopulation}
|
||||
defaultValue={stateJPM.update.form.totalPoorPopulation}
|
||||
onChange={(val) => {
|
||||
stateJPM.update.form.totalPoorPopulation = Number(val.currentTarget.value);
|
||||
}}
|
||||
|
||||
@@ -61,7 +61,7 @@ export default function CreateJumlahPendudukMiskin() {
|
||||
<TextInput
|
||||
label="Tahun"
|
||||
type="number"
|
||||
value={stateJPM.create.form.year || ''}
|
||||
defaultValue={stateJPM.create.form.year || ''}
|
||||
placeholder="Masukkan tahun"
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
@@ -73,7 +73,7 @@ export default function CreateJumlahPendudukMiskin() {
|
||||
<TextInput
|
||||
label="Jumlah Penduduk Miskin"
|
||||
type="number"
|
||||
value={stateJPM.create.form.totalPoorPopulation}
|
||||
defaultValue={stateJPM.create.form.totalPoorPopulation}
|
||||
placeholder="Masukkan jumlah penduduk miskin"
|
||||
onChange={(e) => {
|
||||
stateJPM.create.form.totalPoorPopulation = Number(e.currentTarget.value);
|
||||
|
||||
@@ -63,35 +63,35 @@ function EditGrafikBerdasarkanPendidikan() {
|
||||
label="SD"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.SD}
|
||||
defaultValue={stategrafik.update.form.SD}
|
||||
onChange={(val) => (stategrafik.update.form.SD = val.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="SMP"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.SMP}
|
||||
defaultValue={stategrafik.update.form.SMP}
|
||||
onChange={(val) => (stategrafik.update.form.SMP = val.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="SMA"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.SMA}
|
||||
defaultValue={stategrafik.update.form.SMA}
|
||||
onChange={(val) => (stategrafik.update.form.SMA = val.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="D3"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.D3}
|
||||
defaultValue={stategrafik.update.form.D3}
|
||||
onChange={(val) => (stategrafik.update.form.D3 = val.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="S1"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.S1}
|
||||
defaultValue={stategrafik.update.form.S1}
|
||||
onChange={(val) => (stategrafik.update.form.S1 = val.currentTarget.value)}
|
||||
/>
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ function CreateGrafikBerdasarkanPendidikan() {
|
||||
label="SD"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.SD}
|
||||
defaultValue={stategrafik.create.form.SD}
|
||||
onChange={(val) => (stategrafik.create.form.SD = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -75,7 +75,7 @@ function CreateGrafikBerdasarkanPendidikan() {
|
||||
label="SMP"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.SMP}
|
||||
defaultValue={stategrafik.create.form.SMP}
|
||||
onChange={(val) => (stategrafik.create.form.SMP = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -83,7 +83,7 @@ function CreateGrafikBerdasarkanPendidikan() {
|
||||
label="SMA"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.SMA}
|
||||
defaultValue={stategrafik.create.form.SMA}
|
||||
onChange={(val) => (stategrafik.create.form.SMA = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -91,7 +91,7 @@ function CreateGrafikBerdasarkanPendidikan() {
|
||||
label="D3"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.D3}
|
||||
defaultValue={stategrafik.create.form.D3}
|
||||
onChange={(val) => (stategrafik.create.form.D3 = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -99,7 +99,7 @@ function CreateGrafikBerdasarkanPendidikan() {
|
||||
label="S1"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.S1}
|
||||
defaultValue={stategrafik.create.form.S1}
|
||||
onChange={(val) => (stategrafik.create.form.S1 = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -71,7 +71,7 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 18 - 25"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.usia18_25}
|
||||
defaultValue={stategrafik.update.form.usia18_25}
|
||||
onChange={(val) => {
|
||||
stategrafik.update.form.usia18_25 = val.currentTarget.value;
|
||||
}}
|
||||
@@ -81,7 +81,7 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 26 - 35"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.usia26_35}
|
||||
defaultValue={stategrafik.update.form.usia26_35}
|
||||
onChange={(val) => {
|
||||
stategrafik.update.form.usia26_35 = val.currentTarget.value;
|
||||
}}
|
||||
@@ -91,7 +91,7 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 36 - 45"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.usia36_45}
|
||||
defaultValue={stategrafik.update.form.usia36_45}
|
||||
onChange={(val) => {
|
||||
stategrafik.update.form.usia36_45 = val.currentTarget.value;
|
||||
}}
|
||||
@@ -101,7 +101,7 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 46 +"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.update.form.usia46_keatas}
|
||||
defaultValue={stategrafik.update.form.usia46_keatas}
|
||||
onChange={(val) => {
|
||||
stategrafik.update.form.usia46_keatas = val.currentTarget.value;
|
||||
}}
|
||||
|
||||
@@ -66,7 +66,7 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 18 - 25"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.usia18_25}
|
||||
defaultValue={stategrafik.create.form.usia18_25}
|
||||
onChange={(val) => (stategrafik.create.form.usia18_25 = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -74,7 +74,7 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 26 - 35"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.usia26_35}
|
||||
defaultValue={stategrafik.create.form.usia26_35}
|
||||
onChange={(val) => (stategrafik.create.form.usia26_35 = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -82,7 +82,7 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 36 - 45"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.usia36_45}
|
||||
defaultValue={stategrafik.create.form.usia36_45}
|
||||
onChange={(val) => (stategrafik.create.form.usia36_45 = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -90,7 +90,7 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
|
||||
label="Usia 46 +"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stategrafik.create.form.usia46_keatas}
|
||||
defaultValue={stategrafik.create.form.usia46_keatas}
|
||||
onChange={(val) => (stategrafik.create.form.usia46_keatas = val.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -139,20 +139,23 @@ function EditDetailDataPengangguran() {
|
||||
/>
|
||||
<NumberInput
|
||||
label="Tahun"
|
||||
value={formData.year}
|
||||
defaultValue={formData.year}
|
||||
onChange={(val) => updateFormData({ year: Number(val) })}
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
label="Pengangguran Terdidik"
|
||||
type="number"
|
||||
value={formData.educatedUnemployment}
|
||||
defaultValue={formData.educatedUnemployment}
|
||||
onChange={(val) => updateFormData({ educatedUnemployment: Number(val.currentTarget.value) || 0 })}
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
label="Pengangguran Tidak Terdidik"
|
||||
type="number"
|
||||
value={formData.uneducatedUnemployment}
|
||||
defaultValue={formData.uneducatedUnemployment}
|
||||
onChange={(val) => updateFormData({ uneducatedUnemployment: Number(val.currentTarget.value) || 0 })}
|
||||
required
|
||||
/>
|
||||
<Text fz="sm" fw={500}>Total Otomatis: {formData.totalUnemployment}</Text>
|
||||
<Text fz="sm" fw={500}>Perubahan Otomatis: {formData.percentageChange !== null ? `${formData.percentageChange}%` : '-'}</Text>
|
||||
|
||||
@@ -107,7 +107,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
label="Posisi"
|
||||
placeholder="Masukkan posisi"
|
||||
value={formData.posisi}
|
||||
defaultValue={formData.posisi}
|
||||
onChange={(e) => setFormData({ ...formData, posisi: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -115,7 +115,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
label="Nama Perusahaan"
|
||||
placeholder="Masukkan nama perusahaan"
|
||||
value={formData.namaPerusahaan}
|
||||
defaultValue={formData.namaPerusahaan}
|
||||
onChange={(e) => setFormData({ ...formData, namaPerusahaan: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -123,7 +123,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
label="Lokasi"
|
||||
placeholder="Masukkan lokasi"
|
||||
value={formData.lokasi}
|
||||
defaultValue={formData.lokasi}
|
||||
onChange={(e) => setFormData({ ...formData, lokasi: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -131,7 +131,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
label="Tipe Pekerjaan"
|
||||
placeholder="Masukkan tipe pekerjaan"
|
||||
value={formData.tipePekerjaan}
|
||||
defaultValue={formData.tipePekerjaan}
|
||||
onChange={(e) => setFormData({ ...formData, tipePekerjaan: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -139,7 +139,7 @@ function EditLowonganKerja() {
|
||||
<TextInput
|
||||
label="Gaji (per bulan)"
|
||||
placeholder="Masukkan gaji"
|
||||
value={formData.gaji}
|
||||
defaultValue={formData.gaji}
|
||||
onChange={(e) => setFormData({ ...formData, gaji: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -94,12 +94,12 @@ function DetailLowonganKerjaLokal() {
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||
<Text fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }} />
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }} />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Kualifikasi</Text>
|
||||
<Text fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data.kualifikasi || '-' }} />
|
||||
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.kualifikasi || '-' }} />
|
||||
</Box>
|
||||
|
||||
<Group gap="sm" mt="sm">
|
||||
|
||||
@@ -69,7 +69,7 @@ function CreateLowonganKerja() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
value={lowonganState.create.form.posisi}
|
||||
defaultValue={lowonganState.create.form.posisi}
|
||||
onChange={(val) =>
|
||||
(lowonganState.create.form.posisi = val.target.value)
|
||||
}
|
||||
@@ -78,7 +78,7 @@ function CreateLowonganKerja() {
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
value={lowonganState.create.form.namaPerusahaan}
|
||||
defaultValue={lowonganState.create.form.namaPerusahaan}
|
||||
onChange={(val) =>
|
||||
(lowonganState.create.form.namaPerusahaan = val.target.value)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ function CreateLowonganKerja() {
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
value={lowonganState.create.form.lokasi}
|
||||
defaultValue={lowonganState.create.form.lokasi}
|
||||
onChange={(val) =>
|
||||
(lowonganState.create.form.lokasi = val.target.value)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ function CreateLowonganKerja() {
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
value={lowonganState.create.form.tipePekerjaan}
|
||||
defaultValue={lowonganState.create.form.tipePekerjaan}
|
||||
onChange={(val) =>
|
||||
(lowonganState.create.form.tipePekerjaan = val.target.value)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ function CreateLowonganKerja() {
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
value={lowonganState.create.form.gaji}
|
||||
defaultValue={lowonganState.create.form.gaji}
|
||||
onChange={(val) =>
|
||||
(lowonganState.create.form.gaji = val.target.value)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ function EditKategoriProduk() {
|
||||
<TextInput
|
||||
label={<Text fw="bold" fz="sm">Nama Kategori Produk</Text>}
|
||||
placeholder="Masukkan nama kategori produk"
|
||||
value={formData.nama}
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -74,7 +74,7 @@ function CreateKategoriProduk() {
|
||||
<TextInput
|
||||
label="Nama Kategori Produk"
|
||||
placeholder="Masukkan nama kategori produk"
|
||||
value={statePasar.create.form.nama || ''}
|
||||
defaultValue={statePasar.create.form.nama || ''}
|
||||
onChange={(e) => (statePasar.create.form.nama = e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -173,7 +173,7 @@ function EditPasarDesa() {
|
||||
<TextInput
|
||||
label="Nama Produk"
|
||||
placeholder="Masukkan nama produk"
|
||||
value={formData.nama}
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) => setFormData({ ...formData, nama: e.target.value })}
|
||||
required
|
||||
/>
|
||||
@@ -182,7 +182,7 @@ function EditPasarDesa() {
|
||||
type="number"
|
||||
label="Harga Produk"
|
||||
placeholder="Masukkan harga produk"
|
||||
value={formData.harga}
|
||||
defaultValue={formData.harga}
|
||||
onChange={(e) => setFormData({ ...formData, harga: Number(e.target.value) })}
|
||||
required
|
||||
/>
|
||||
@@ -194,7 +194,7 @@ function EditPasarDesa() {
|
||||
step={0.1}
|
||||
label="Rating Produk"
|
||||
placeholder="Masukkan rating produk (0-5)"
|
||||
value={formData.rating}
|
||||
defaultValue={formData.rating}
|
||||
onChange={(e) => setFormData({ ...formData, rating: Number(e.target.value) })}
|
||||
required
|
||||
/>
|
||||
@@ -202,7 +202,7 @@ function EditPasarDesa() {
|
||||
<TextInput
|
||||
label="Alamat Usaha"
|
||||
placeholder="Masukkan alamat usaha"
|
||||
value={formData.alamatUsaha}
|
||||
defaultValue={formData.alamatUsaha}
|
||||
onChange={(e) => setFormData({ ...formData, alamatUsaha: e.target.value })}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -144,7 +144,7 @@ export default function CreatePasarDesa() {
|
||||
<TextInput
|
||||
label="Nama Produk"
|
||||
placeholder="Masukkan nama produk"
|
||||
value={statePasar.pasarDesa.create.form.nama}
|
||||
defaultValue={statePasar.pasarDesa.create.form.nama}
|
||||
onChange={(e) => (statePasar.pasarDesa.create.form.nama = e.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -154,7 +154,7 @@ export default function CreatePasarDesa() {
|
||||
type="number"
|
||||
label="Harga Produk"
|
||||
placeholder="Masukkan harga produk"
|
||||
value={statePasar.pasarDesa.create.form.harga}
|
||||
defaultValue={statePasar.pasarDesa.create.form.harga}
|
||||
onChange={(e) => (statePasar.pasarDesa.create.form.harga = Number(e.target.value))}
|
||||
required
|
||||
/>
|
||||
@@ -167,7 +167,7 @@ export default function CreatePasarDesa() {
|
||||
step={0.1}
|
||||
label="Rating Produk (0–5)"
|
||||
placeholder="Masukkan rating produk"
|
||||
value={statePasar.pasarDesa.create.form.rating}
|
||||
defaultValue={statePasar.pasarDesa.create.form.rating}
|
||||
onChange={(e) => {
|
||||
const value = Number(e.target.value);
|
||||
if (value >= 0 && value <= 5) {
|
||||
@@ -180,7 +180,7 @@ export default function CreatePasarDesa() {
|
||||
<TextInput
|
||||
label="Alamat Usaha"
|
||||
placeholder="Masukkan alamat usaha"
|
||||
value={statePasar.pasarDesa.create.form.alamatUsaha}
|
||||
defaultValue={statePasar.pasarDesa.create.form.alamatUsaha}
|
||||
onChange={(e) => (statePasar.pasarDesa.create.form.alamatUsaha = e.target.value)}
|
||||
/>
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function EditProgramKemiskinan() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
value={stateProgram.update.form.nama}
|
||||
defaultValue={stateProgram.update.form.nama}
|
||||
onChange={(e) => {
|
||||
stateProgram.update.form.nama = e.target.value;
|
||||
}}
|
||||
@@ -131,7 +131,7 @@ function EditProgramKemiskinan() {
|
||||
</Text>
|
||||
<TextInput
|
||||
type="number"
|
||||
value={stateProgram.update.form.statistik.jumlah}
|
||||
defaultValue={stateProgram.update.form.statistik.jumlah}
|
||||
onChange={(e) => {
|
||||
stateProgram.update.form.statistik.jumlah = e.target.value;
|
||||
}}
|
||||
@@ -142,7 +142,7 @@ function EditProgramKemiskinan() {
|
||||
|
||||
<TextInput
|
||||
type="number"
|
||||
value={stateProgram.update.form.statistik.tahun}
|
||||
defaultValue={stateProgram.update.form.statistik.tahun}
|
||||
onChange={(e) => {
|
||||
stateProgram.update.form.statistik.tahun = e.target.value;
|
||||
}}
|
||||
|
||||
@@ -90,6 +90,7 @@ function DetailProgramKemiskinan() {
|
||||
fz="md"
|
||||
c="dimmed"
|
||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ function CreateProgramKemiskinan() {
|
||||
<TextInput
|
||||
label="Judul Program"
|
||||
placeholder="Masukkan judul program"
|
||||
value={programState.create.form.nama}
|
||||
defaultValue={programState.create.form.nama}
|
||||
onChange={(val) => (programState.create.form.nama = val.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -128,7 +128,7 @@ function CreateProgramKemiskinan() {
|
||||
<Group grow>
|
||||
<TextInput
|
||||
type="number"
|
||||
value={programState.create.form.statistik.jumlah}
|
||||
defaultValue={programState.create.form.statistik.jumlah}
|
||||
onChange={(val) =>
|
||||
(programState.create.form.statistik.jumlah = val.target.value)
|
||||
}
|
||||
@@ -138,7 +138,7 @@ function CreateProgramKemiskinan() {
|
||||
/>
|
||||
<TextInput
|
||||
type="number"
|
||||
value={programState.create.form.statistik.tahun}
|
||||
defaultValue={programState.create.form.statistik.tahun}
|
||||
onChange={(val) =>
|
||||
(programState.create.form.statistik.tahun = val.target.value)
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ function EditSektorUnggulanDesa() {
|
||||
<TextInput
|
||||
label="Nama Sektor Unggulan"
|
||||
placeholder="Masukkan nama sektor unggulan"
|
||||
value={stateGrafik.update.form.name}
|
||||
defaultValue={stateGrafik.update.form.name}
|
||||
onChange={(val) => {
|
||||
stateGrafik.update.form.name = val.currentTarget.value;
|
||||
}}
|
||||
@@ -110,7 +110,7 @@ function EditSektorUnggulanDesa() {
|
||||
label="Jumlah"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stateGrafik.update.form.value}
|
||||
defaultValue={stateGrafik.update.form.value}
|
||||
onChange={(val) => {
|
||||
stateGrafik.update.form.value = Number(val.currentTarget.value);
|
||||
}}
|
||||
|
||||
@@ -82,7 +82,7 @@ function DetailSektorUnggulanDesa() {
|
||||
|
||||
<Box>
|
||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||
<Text ta={"justify"} fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data.description || '-' }} />
|
||||
<Text ta={"justify"} fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data.description || '-' }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
|
||||
@@ -78,7 +78,7 @@ function CreateSektorUnggulanDesa() {
|
||||
<TextInput
|
||||
label="Nama Sektor Unggulan"
|
||||
placeholder="Masukkan nama sektor unggulan"
|
||||
value={stateGrafik.create.form.name}
|
||||
defaultValue={stateGrafik.create.form.name}
|
||||
onChange={(e) => {
|
||||
stateGrafik.create.form.name = e.currentTarget.value;
|
||||
}}
|
||||
@@ -101,7 +101,7 @@ function CreateSektorUnggulanDesa() {
|
||||
label="Jumlah"
|
||||
type="number"
|
||||
placeholder="Masukkan jumlah"
|
||||
value={stateGrafik.create.form.value}
|
||||
defaultValue={stateGrafik.create.form.value}
|
||||
onChange={(e) => {
|
||||
stateGrafik.create.form.value = Number(e.currentTarget.value);
|
||||
}}
|
||||
|
||||
@@ -83,7 +83,7 @@ export default function EditHubunganOrganisasi() {
|
||||
<TextInput
|
||||
label="Tipe"
|
||||
placeholder="Contoh: langsung_melapor"
|
||||
value={form.tipe}
|
||||
defaultValue={form.tipe}
|
||||
onChange={(e) => setForm({ ...form, tipe: e.currentTarget.value })}
|
||||
/>
|
||||
<Button onClick={handleSubmit} color="blue">Simpan</Button>
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function CreateHubunganOrganisasi() {
|
||||
<TextInput
|
||||
label="Tipe"
|
||||
placeholder="Contoh: langsung_melapor"
|
||||
value={form.tipe}
|
||||
defaultValue={form.tipe}
|
||||
onChange={(e) => setForm({ ...form, tipe: e.currentTarget.value })}
|
||||
/>
|
||||
<Button onClick={handleSubmit} color="blue">Simpan</Button>
|
||||
|
||||
@@ -151,13 +151,13 @@ export default function EditPegawai() {
|
||||
<TextInput
|
||||
label="Nama Lengkap"
|
||||
placeholder="Masukkan nama lengkap"
|
||||
value={formData.namaLengkap}
|
||||
defaultValue={formData.namaLengkap}
|
||||
onChange={(e) => setFormData({ ...formData, namaLengkap: e.target.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Gelar Akademik"
|
||||
placeholder="Contoh: S.Kom"
|
||||
value={formData.gelarAkademik}
|
||||
defaultValue={formData.gelarAkademik}
|
||||
onChange={(e) => setFormData({ ...formData, gelarAkademik: e.target.value })}
|
||||
/>
|
||||
<Box>
|
||||
@@ -217,25 +217,25 @@ export default function EditPegawai() {
|
||||
label="Tanggal Masuk"
|
||||
type="date"
|
||||
placeholder="Contoh: 2022-01-01"
|
||||
value={formatDateForInput(formData.tanggalMasuk)}
|
||||
defaultValue={formatDateForInput(formData.tanggalMasuk)}
|
||||
onChange={(e) => setFormData({ ...formData, tanggalMasuk: e.target.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Email"
|
||||
placeholder="Contoh: email@example.com"
|
||||
value={formData.email}
|
||||
defaultValue={formData.email}
|
||||
onChange={(e) => (formData.email = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Telepon"
|
||||
placeholder="Contoh: 08123456789"
|
||||
value={formData.telepon}
|
||||
defaultValue={formData.telepon}
|
||||
onChange={(e) => (formData.telepon = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder="Contoh: Jl. Contoh No. 1"
|
||||
value={formData.alamat}
|
||||
defaultValue={formData.alamat}
|
||||
onChange={(e) => (formData.alamat = e.currentTarget.value)}
|
||||
/>
|
||||
<Select
|
||||
|
||||
@@ -75,7 +75,7 @@ function DetailPegawai() {
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Email</Text>
|
||||
<Text fz={"lg"}>{statePegawai.findUnique.data?.email}</Text>
|
||||
<Text fz={"lg"} style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{statePegawai.findUnique.data?.email}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Telepon</Text>
|
||||
@@ -83,7 +83,7 @@ function DetailPegawai() {
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Alamat</Text>
|
||||
<Text fz={"lg"}>{statePegawai.findUnique.data?.alamat}</Text>
|
||||
<Text fz={"lg"} style={{ wordBreak: "break-word", whiteSpace: "normal" }}>{statePegawai.findUnique.data?.alamat}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fz={"lg"} fw={"bold"}>Posisi</Text>
|
||||
|
||||
@@ -84,13 +84,13 @@ function CreatePegawai() {
|
||||
<TextInput
|
||||
label="Nama Lengkap"
|
||||
placeholder="Masukkan nama lengkap"
|
||||
value={stateOrganisasi.pegawai.create.form.namaLengkap}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.namaLengkap}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.namaLengkap = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Gelar Akademik"
|
||||
placeholder="Contoh: S.Kom"
|
||||
value={stateOrganisasi.pegawai.create.form.gelarAkademik}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.gelarAkademik}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.gelarAkademik = e.currentTarget.value)}
|
||||
/>
|
||||
<Box>
|
||||
@@ -150,25 +150,25 @@ function CreatePegawai() {
|
||||
label="Tanggal Masuk"
|
||||
type="date"
|
||||
placeholder="Contoh: 2022-01-01"
|
||||
value={stateOrganisasi.pegawai.create.form.tanggalMasuk}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.tanggalMasuk}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.tanggalMasuk = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Email"
|
||||
placeholder="Contoh: email@example.com"
|
||||
value={stateOrganisasi.pegawai.create.form.email}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.email}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.email = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Telepon"
|
||||
placeholder="Contoh: 08123456789"
|
||||
value={stateOrganisasi.pegawai.create.form.telepon}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.telepon}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.telepon = e.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Alamat"
|
||||
placeholder="Contoh: Jl. Contoh No. 1"
|
||||
value={stateOrganisasi.pegawai.create.form.alamat}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.alamat}
|
||||
onChange={(e) => (stateOrganisasi.pegawai.create.form.alamat = e.currentTarget.value)}
|
||||
/>
|
||||
<Select
|
||||
@@ -178,7 +178,7 @@ function CreatePegawai() {
|
||||
value: p.id,
|
||||
label: p.nama
|
||||
})) || []}
|
||||
value={stateOrganisasi.pegawai.create.form.posisiId}
|
||||
defaultValue={stateOrganisasi.pegawai.create.form.posisiId}
|
||||
onChange={(value) => {
|
||||
if (value) stateOrganisasi.pegawai.create.form.posisiId = value;
|
||||
}}
|
||||
|
||||
@@ -114,7 +114,7 @@ function EditPosisiOrganisasi() {
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
value={formData.nama}
|
||||
defaultValue={formData.nama}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, nama: e.target.value })
|
||||
}
|
||||
@@ -137,7 +137,7 @@ function EditPosisiOrganisasi() {
|
||||
|
||||
<TextInput
|
||||
type="number"
|
||||
value={formData.hierarki}
|
||||
defaultValue={formData.hierarki}
|
||||
onChange={(e) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
|
||||
@@ -75,7 +75,7 @@ function CreatePosisiOrganisasi() {
|
||||
<TextInput
|
||||
label="Nama Posisi"
|
||||
placeholder="Contoh: Kepala Desa"
|
||||
value={stateOrganisasi.create.form.nama}
|
||||
defaultValue={stateOrganisasi.create.form.nama}
|
||||
onChange={(e) => (stateOrganisasi.create.form.nama = e.currentTarget.value)}
|
||||
required
|
||||
/>
|
||||
@@ -94,7 +94,7 @@ function CreatePosisiOrganisasi() {
|
||||
label="Hierarki"
|
||||
type="number"
|
||||
placeholder="Contoh: 1"
|
||||
value={stateOrganisasi.create.form.hierarki}
|
||||
defaultValue={stateOrganisasi.create.form.hierarki}
|
||||
onChange={(e) => {
|
||||
const value = parseInt(e.currentTarget.value, 10);
|
||||
if (!isNaN(value)) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user