API & UI Admin Menu Keamanan Done
This commit is contained in:
85
prisma/migrations/20250703070556_3_jul_2025_1/migration.sql
Normal file
85
prisma/migrations/20250703070556_3_jul_2025_1/migration.sql
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The values [SELESAI,PROSES,GAGAL] on the enum `StatusLaporan` will be removed. If these variants are still used in the database, this will fail.
|
||||||
|
- You are about to drop the column `icon` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `urutan` on the `KontakDaruratKeamanan` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `icon` on the `KontakItem` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterEnum
|
||||||
|
BEGIN;
|
||||||
|
CREATE TYPE "StatusLaporan_new" AS ENUM ('Selesai', 'Proses', 'Gagal');
|
||||||
|
ALTER TABLE "LaporanPublik" ALTER COLUMN "status" TYPE "StatusLaporan_new" USING ("status"::text::"StatusLaporan_new");
|
||||||
|
ALTER TYPE "StatusLaporan" RENAME TO "StatusLaporan_old";
|
||||||
|
ALTER TYPE "StatusLaporan_new" RENAME TO "StatusLaporan";
|
||||||
|
DROP TYPE "StatusLaporan_old";
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "KontakDaruratKeamanan" DROP COLUMN "icon",
|
||||||
|
DROP COLUMN "urutan",
|
||||||
|
ADD COLUMN "imageId" TEXT;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "KontakItem" DROP COLUMN "icon",
|
||||||
|
ADD COLUMN "imageId" TEXT;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LowonganPekerjaan" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"posisi" TEXT NOT NULL,
|
||||||
|
"namaPerusahaan" TEXT NOT NULL,
|
||||||
|
"lokasi" TEXT NOT NULL,
|
||||||
|
"tipePekerjaan" TEXT NOT NULL,
|
||||||
|
"gaji" TEXT NOT NULL,
|
||||||
|
"deskripsi" TEXT NOT NULL,
|
||||||
|
"kualifikasi" TEXT NOT NULL,
|
||||||
|
"tanggalPosting" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "LowonganPekerjaan_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ProgramKemiskinan" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"nama" TEXT NOT NULL,
|
||||||
|
"deskripsi" TEXT NOT NULL,
|
||||||
|
"ikonUrl" TEXT,
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"statistikId" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ProgramKemiskinan_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "StatistikKemiskinan" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"tahun" INTEGER NOT NULL,
|
||||||
|
"jumlah" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "StatistikKemiskinan_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ProgramKemiskinan_statistikId_key" ON "ProgramKemiskinan"("statistikId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "StatistikKemiskinan_tahun_key" ON "StatistikKemiskinan"("tahun");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "KontakDaruratKeamanan" ADD CONSTRAINT "KontakDaruratKeamanan_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "KontakItem" ADD CONSTRAINT "KontakItem_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "FileStorage"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ProgramKemiskinan" ADD CONSTRAINT "ProgramKemiskinan_statistikId_fkey" FOREIGN KEY ("statistikId") REFERENCES "StatistikKemiskinan"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
@@ -1020,9 +1020,9 @@ model PenangananLaporanPublik {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum StatusLaporan {
|
enum StatusLaporan {
|
||||||
SELESAI
|
Selesai
|
||||||
PROSES
|
Proses
|
||||||
GAGAL
|
Gagal
|
||||||
}
|
}
|
||||||
|
|
||||||
model Pelapor {
|
model Pelapor {
|
||||||
|
|||||||
@@ -179,17 +179,20 @@ const keamananLingkunganState = proxy({
|
|||||||
try {
|
try {
|
||||||
keamananLingkunganState.edit.loading = true;
|
keamananLingkunganState.edit.loading = true;
|
||||||
|
|
||||||
const response = await fetch(`/api/keamanan/keamananlingkungan/${this.id}`, {
|
const response = await fetch(
|
||||||
method: "PUT",
|
`/api/keamanan/keamananlingkungan/${this.id}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "PUT",
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify({
|
"Content-Type": "application/json",
|
||||||
name: this.form.name,
|
},
|
||||||
deskripsi: this.form.deskripsi,
|
body: JSON.stringify({
|
||||||
imageId: this.form.imageId,
|
name: this.form.name,
|
||||||
}),
|
deskripsi: this.form.deskripsi,
|
||||||
});
|
imageId: this.form.imageId,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
|
|||||||
273
src/app/admin/(dashboard)/_state/keamanan/laporan-publik.ts
Normal file
273
src/app/admin/(dashboard)/_state/keamanan/laporan-publik.ts
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
import ApiFetch from "@/lib/api-fetch";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import { proxy } from "valtio";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export type Status = "Selesai" | "Proses" | "Gagal";
|
||||||
|
|
||||||
|
const templateForm = z.object({
|
||||||
|
judul: z.string().min(3, "Judul minimal 3 karakter"),
|
||||||
|
lokasi: z.string().min(3, "Lokasi minimal 3 karakter"),
|
||||||
|
tanggalWaktu: z.string().min(3, "Tanggal Waktu minimal 3 karakter"),
|
||||||
|
status: z.enum(["Selesai", "Proses", "Gagal"]),
|
||||||
|
penanganan: z.string(),
|
||||||
|
kronologi: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
judul: string;
|
||||||
|
lokasi: string;
|
||||||
|
tanggalWaktu: string;
|
||||||
|
status: Status;
|
||||||
|
penanganan: string;
|
||||||
|
kronologi: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultForm: FormData = {
|
||||||
|
judul: "",
|
||||||
|
lokasi: "",
|
||||||
|
tanggalWaktu: new Date().toISOString(),
|
||||||
|
status: "Proses",
|
||||||
|
penanganan: "",
|
||||||
|
kronologi: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const laporanPublikState = proxy({
|
||||||
|
create: {
|
||||||
|
form: { ...defaultForm },
|
||||||
|
loading: false,
|
||||||
|
async create() {
|
||||||
|
const cek = templateForm.safeParse(laporanPublikState.create.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const err = `[${cek.error.issues
|
||||||
|
.map((v) => `${v.path.join(".")}`)
|
||||||
|
.join("\n")}] required`;
|
||||||
|
return toast.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
laporanPublikState.create.loading = true;
|
||||||
|
|
||||||
|
// Ensure we have a valid date
|
||||||
|
if (!laporanPublikState.create.form.tanggalWaktu) {
|
||||||
|
return toast.error("Tanggal laporan harus diisi");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the data before sending
|
||||||
|
const formData = {
|
||||||
|
...laporanPublikState.create.form,
|
||||||
|
// Ensure the date is in the correct format for the API
|
||||||
|
tanggalWaktu: new Date(laporanPublikState.create.form.tanggalWaktu).toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Sending form data:", formData); // Debug log
|
||||||
|
|
||||||
|
const res = await ApiFetch.api.keamanan.laporanpublik["create"].post(
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
console.error("API Error:", res.error);
|
||||||
|
throw new Error("Failed to create laporan publik");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
laporanPublikState.findMany.load();
|
||||||
|
return toast.success("success create");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(res);
|
||||||
|
return toast.error("failed create");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating laporan publik:", error);
|
||||||
|
toast.error(error instanceof Error ? error.message : "Gagal membuat laporan publik");
|
||||||
|
throw error; // Re-throw to be handled by the caller
|
||||||
|
} finally {
|
||||||
|
laporanPublikState.create.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetForm() {
|
||||||
|
laporanPublikState.create.form = { ...defaultForm };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findMany: {
|
||||||
|
data: null as
|
||||||
|
| Prisma.LaporanPublikGetPayload<{
|
||||||
|
include: { penanganan: true };
|
||||||
|
}>[]
|
||||||
|
| null,
|
||||||
|
async load() {
|
||||||
|
const res = await ApiFetch.api.keamanan.laporanpublik["find-many"].get();
|
||||||
|
if (res.status === 200) {
|
||||||
|
laporanPublikState.findMany.data = res.data?.data ?? [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findUnique: {
|
||||||
|
data: null as Prisma.LaporanPublikGetPayload<{
|
||||||
|
include: { penanganan: true };
|
||||||
|
}> | null,
|
||||||
|
async load(id: string) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/keamanan/laporanpublik/${id}`);
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
laporanPublikState.findUnique.data = data.data ?? null;
|
||||||
|
} else {
|
||||||
|
console.error("Failed to fetch data", res.status, res.statusText);
|
||||||
|
laporanPublikState.findUnique.data = null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
laporanPublikState.findUnique.data = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetForm() {
|
||||||
|
laporanPublikState.findUnique.data = null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
loading: false,
|
||||||
|
async byId(id: string) {
|
||||||
|
if (!id) return toast.warn("ID tidak valid");
|
||||||
|
|
||||||
|
try {
|
||||||
|
laporanPublikState.delete.loading = true;
|
||||||
|
const response = await fetch(`/api/keamanan/laporanpublik/del/${id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && result?.success) {
|
||||||
|
toast.success(
|
||||||
|
result.message || "Laporan publik berhasil dihapus"
|
||||||
|
);
|
||||||
|
await laporanPublikState.findMany.load(); // refresh list
|
||||||
|
} else {
|
||||||
|
toast.error(result?.message || "Gagal menghapus laporan publik");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal delete:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat menghapus laporan publik");
|
||||||
|
} finally {
|
||||||
|
laporanPublikState.delete.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
id: "",
|
||||||
|
form: { ...defaultForm },
|
||||||
|
loading: false,
|
||||||
|
async load(id: string) {
|
||||||
|
if (!id) {
|
||||||
|
toast.warn("ID tidak valid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/keamanan/laporanpublik/${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 = {
|
||||||
|
judul: data.judul,
|
||||||
|
lokasi: data.lokasi,
|
||||||
|
tanggalWaktu: data.tanggalWaktu,
|
||||||
|
status: data.status,
|
||||||
|
penanganan: data.penanganan,
|
||||||
|
kronologi: data.kronologi,
|
||||||
|
};
|
||||||
|
return data; // Return the loaded data
|
||||||
|
} else {
|
||||||
|
throw new Error(result?.message || "Gagal memuat data");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading keamanan lingkungan:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error ? error.message : "Gagal memuat data"
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async update() {
|
||||||
|
const cek = templateForm.safeParse(laporanPublikState.edit.form);
|
||||||
|
if (!cek.success) {
|
||||||
|
const err = `[${cek.error.issues
|
||||||
|
.map((v) => `${v.path.join(".")}`)
|
||||||
|
.join("\n")}] required`;
|
||||||
|
toast.error(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
laporanPublikState.edit.loading = true;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/keamanan/laporanpublik/${this.id}`,
|
||||||
|
{
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
judul: this.form.judul,
|
||||||
|
lokasi: this.form.lokasi,
|
||||||
|
tanggalWaktu: this.form.tanggalWaktu,
|
||||||
|
status: this.form.status,
|
||||||
|
penanganan: this.form.penanganan,
|
||||||
|
kronologi: this.form.kronologi,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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("Berhasil update laporan publik");
|
||||||
|
await laporanPublikState.findMany.load(); // refresh list
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "Gagal update laporan publik");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating laporan publik:", error);
|
||||||
|
toast.error(
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Terjadi kesalahan saat update laporan publik"
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
laporanPublikState.edit.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
laporanPublikState.edit.id = "";
|
||||||
|
laporanPublikState.edit.form = { ...defaultForm };
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
export default laporanPublikState;
|
||||||
@@ -102,7 +102,7 @@ function ListProgramKemiskinan() {
|
|||||||
{mounted && lineChart.length > 0 ? (<Box style={{ width: '100%', height: 'auto', }}>
|
{mounted && lineChart.length > 0 ? (<Box style={{ width: '100%', height: 'auto', }}>
|
||||||
<Box w={"100%"} style={{overflowX: 'auto'}}>
|
<Box w={"100%"} style={{overflowX: 'auto'}}>
|
||||||
<LineChart
|
<LineChart
|
||||||
width={650}
|
width={820}
|
||||||
height={300}
|
height={300}
|
||||||
data={lineChart}
|
data={lineChart}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
'use client'
|
||||||
|
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
|
||||||
|
import laporanPublikState from '@/app/admin/(dashboard)/_state/keamanan/laporan-publik';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Group, Paper, Select, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
|
import { DateTimePicker } from '@mantine/dates';
|
||||||
|
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';
|
||||||
|
export type Status = "Selesai" | "Proses" | "Gagal";
|
||||||
|
|
||||||
|
function EditLaporanPublik() {
|
||||||
|
const stateLaporan = useProxy(laporanPublikState)
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useParams()
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
judul: stateLaporan.edit.form.judul || '',
|
||||||
|
lokasi: stateLaporan.edit.form.lokasi || '',
|
||||||
|
tanggalWaktu: stateLaporan.edit.form.tanggalWaktu || '',
|
||||||
|
status: stateLaporan.edit.form.status || '',
|
||||||
|
penanganan: stateLaporan.edit.form.penanganan || '',
|
||||||
|
kronologi: stateLaporan.edit.form.kronologi || '',
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadLaporanPublik = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await stateLaporan.edit.load(id);
|
||||||
|
if (data) {
|
||||||
|
setFormData({
|
||||||
|
judul: data.judul || '',
|
||||||
|
lokasi: data.lokasi || '',
|
||||||
|
tanggalWaktu: data.tanggalWaktu || '',
|
||||||
|
status: data.status || '',
|
||||||
|
penanganan: data.penanganan?.map((p: any) => p.deskripsi)[0] || '',
|
||||||
|
kronologi: data.kronologi || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading laporan publik:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadLaporanPublik();
|
||||||
|
}, [params?.id]);
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
stateLaporan.edit.form = {
|
||||||
|
...stateLaporan.edit.form,
|
||||||
|
judul: formData.judul,
|
||||||
|
lokasi: formData.lokasi,
|
||||||
|
tanggalWaktu: formData.tanggalWaktu,
|
||||||
|
status: formData.status,
|
||||||
|
penanganan: formData.penanganan,
|
||||||
|
kronologi: formData.kronologi,
|
||||||
|
}
|
||||||
|
|
||||||
|
await stateLaporan.edit.update();
|
||||||
|
toast.success("Laporan Publik berhasil diperbarui!");
|
||||||
|
router.push("/admin/keamanan/laporan-publik");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating kontak darurat:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat memperbarui kontak darurat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Box mb={10}>
|
||||||
|
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={4}>Edit Laporan Publik</Title>
|
||||||
|
<TextInput
|
||||||
|
value={formData.judul}
|
||||||
|
onChange={(e) => setFormData({ ...formData, judul: e.target.value })}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Judul Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan judul LaporanPublik'
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
value={formData.lokasi}
|
||||||
|
onChange={(e) => setFormData({ ...formData, lokasi: e.target.value })}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Lokasi Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan lokasi LaporanPublik'
|
||||||
|
/>
|
||||||
|
<DateTimePicker
|
||||||
|
label="Tanggal Laporan Publik"
|
||||||
|
value={
|
||||||
|
formData.tanggalWaktu
|
||||||
|
? new Date(formData.tanggalWaktu)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onChange={(val) => {
|
||||||
|
if (val) {
|
||||||
|
setFormData({ ...formData, tanggalWaktu: val.toString() });
|
||||||
|
} else {
|
||||||
|
setFormData({ ...formData, tanggalWaktu: "" }); // Reset kalau dikosongkan
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
value={formData.status}
|
||||||
|
onChange={(e) => setFormData({ ...formData, status: e?.valueOf() as Status })}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Status Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan status LaporanPublik'
|
||||||
|
data={[
|
||||||
|
{ value: "Selesai", label: "Selesai" },
|
||||||
|
{ value: "Proses", label: "Proses" },
|
||||||
|
{ value: "Gagal", label: "Gagal" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
value={formData.kronologi}
|
||||||
|
onChange={(e) => setFormData({ ...formData, kronologi: e.target.value })}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Kronologi Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan kronologi LaporanPublik'
|
||||||
|
/>
|
||||||
|
<Text fw={"bold"} fz={"sm"}>Penanganan Laporan Publik</Text>
|
||||||
|
<Box>
|
||||||
|
<Text fw={"bold"} fz={"sm"}>Deskripsi Laporan Publik</Text>
|
||||||
|
<EditEditor
|
||||||
|
value={formData.penanganan}
|
||||||
|
onChange={(htmlContent) => {
|
||||||
|
setFormData((prev) => ({ ...prev, penanganan: htmlContent }));
|
||||||
|
stateLaporan.edit.form.penanganan = htmlContent;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Group>
|
||||||
|
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditLaporanPublik;
|
||||||
128
src/app/admin/(dashboard)/keamanan/laporan-publik/[id]/page.tsx
Normal file
128
src/app/admin/(dashboard)/keamanan/laporan-publik/[id]/page.tsx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
'use client'
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, Flex, Paper, Skeleton, Stack, Text } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { IconArrowBack, IconEdit, IconX } from '@tabler/icons-react';
|
||||||
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import laporanPublikState from '../../../_state/keamanan/laporan-publik';
|
||||||
|
// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
||||||
|
|
||||||
|
function DetailLaporanPublik() {
|
||||||
|
const [modalHapus, setModalHapus] = useState(false)
|
||||||
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||||
|
const stateLaporan = useProxy(laporanPublikState)
|
||||||
|
const params = useParams()
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
stateLaporan.findUnique.load(params?.id as string)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
if (selectedId) {
|
||||||
|
stateLaporan.delete.byId(selectedId)
|
||||||
|
setModalHapus(false)
|
||||||
|
setSelectedId(null)
|
||||||
|
router.push("/admin/keamanan/laporan-publik")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateLaporan.findUnique.data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Box mb={10}>
|
||||||
|
<Button variant="subtle" onClick={() => router.back()}>
|
||||||
|
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
|
||||||
|
<Stack>
|
||||||
|
<Text fz={"xl"} fw={"bold"}>Detail Laporan Publik</Text>
|
||||||
|
<Paper bg={colors['BG-trans']} p={'md'}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Judul Laporan Publik</Text>
|
||||||
|
<Text fz={"lg"}>{stateLaporan.findUnique.data?.judul}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Tanggal Laporan Publik</Text>
|
||||||
|
<Text fz={"lg"}>
|
||||||
|
{stateLaporan.findUnique.data?.tanggalWaktu
|
||||||
|
? new Date(stateLaporan.findUnique.data.tanggalWaktu).toLocaleString('id-ID')
|
||||||
|
: '-'}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Lokasi</Text>
|
||||||
|
<Text fz={"lg"}>{stateLaporan.findUnique.data?.lokasi}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Status</Text>
|
||||||
|
<Text fz={"lg"}>{stateLaporan.findUnique.data?.status}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Kronologi</Text>
|
||||||
|
<Text fz={"lg"}>
|
||||||
|
{stateLaporan.findUnique.data?.kronologi || '-'}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Penanganan</Text>
|
||||||
|
{stateLaporan.findUnique.data?.penanganan?.map((item, index) => (
|
||||||
|
<Box key={index}>
|
||||||
|
<Text fz={"lg"} fw={"bold"}>Deskripsi Penanganan</Text>
|
||||||
|
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: item.deskripsi || '-' }} />
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
{!stateLaporan.findUnique.data?.penanganan?.length && (
|
||||||
|
<Text fz={"lg"} fs="italic">Belum ada penanganan</Text>
|
||||||
|
)}
|
||||||
|
<Flex gap={"xs"} mt={10}>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (stateLaporan.findUnique.data) {
|
||||||
|
setSelectedId(stateLaporan.findUnique.data.id);
|
||||||
|
setModalHapus(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={stateLaporan.delete.loading || !stateLaporan.findUnique.data}
|
||||||
|
color={"red"}
|
||||||
|
>
|
||||||
|
<IconX size={20} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (stateLaporan.findUnique.data) {
|
||||||
|
router.push(`/admin/keamanan/laporan-publik/${stateLaporan.findUnique.data.id}/edit`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={!stateLaporan.findUnique.data}
|
||||||
|
color={"green"}
|
||||||
|
>
|
||||||
|
<IconEdit size={20} />
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
{/* Modal Konfirmasi Hapus */}
|
||||||
|
<ModalKonfirmasiHapus
|
||||||
|
opened={modalHapus}
|
||||||
|
onClose={() => setModalHapus(false)}
|
||||||
|
onConfirm={handleDelete}
|
||||||
|
text='Apakah anda yakin ingin menghapus laporan publik ini?'
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DetailLaporanPublik;
|
||||||
@@ -1,47 +1,105 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
import { Box, Button, Group, Paper, Select, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react';
|
import { DateTimePicker } from '@mantine/dates';
|
||||||
|
import { IconArrowBack } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { KeamananEditor } from '../../_com/keamananEditor';
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import CreateEditor from '../../../_com/createEditor';
|
||||||
|
import laporanPublikState from '../../../_state/keamanan/laporan-publik';
|
||||||
|
export type Status = "Selesai" | "Proses" | "Gagal";
|
||||||
|
|
||||||
function CreateLaporanPublik() {
|
function CreateLaporanPublik() {
|
||||||
|
const stateLaporan = useProxy(laporanPublikState)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
stateLaporan.create.form = {
|
||||||
|
judul: "",
|
||||||
|
lokasi: "",
|
||||||
|
tanggalWaktu: "",
|
||||||
|
status: "Proses" as Status,
|
||||||
|
penanganan: "",
|
||||||
|
kronologi: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
await stateLaporan.create.create();
|
||||||
|
resetForm();
|
||||||
|
router.push('/admin/keamanan/laporan-publik');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box mb={10}>
|
<Box mb={10}>
|
||||||
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
|
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
|
||||||
<IconArrowBack color={colors['blue-button']} size={25}/>
|
<IconArrowBack color={colors['blue-button']} size={25} />
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Paper w={{base: '100%', md: '50%'}} bg={colors['white-1']} p={'md'}>
|
<Paper w={{ base: '100%', md: '50%' }} bg={colors['white-1']} p={'md'}>
|
||||||
<Stack gap={"xs"}>
|
<Stack gap={"xs"}>
|
||||||
<Title order={4}>Create Laporan Publik</Title>
|
<Title order={4}>Create Laporan Publik</Title>
|
||||||
<Box>
|
|
||||||
<Text fw={"bold"} fz={"sm"}>Masukkan Image</Text>
|
|
||||||
<IconImageInPicture size={50} />
|
|
||||||
</Box>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Judul Laporan Publik</Text>}
|
value={stateLaporan.create.form.judul}
|
||||||
placeholder='Masukkan judul LaporanPublik'
|
onChange={(e) => stateLaporan.create.form.judul = e.target.value}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Judul Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan judul LaporanPublik'
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Tanggal Laporan Publik</Text>}
|
value={stateLaporan.create.form.lokasi}
|
||||||
placeholder='Masukkan tanggal LaporanPublik'
|
onChange={(e) => stateLaporan.create.form.lokasi = e.target.value}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Lokasi Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan lokasi LaporanPublik'
|
||||||
/>
|
/>
|
||||||
|
<DateTimePicker
|
||||||
|
label="Tanggal Laporan Publik"
|
||||||
|
value={
|
||||||
|
stateLaporan.create.form.tanggalWaktu
|
||||||
|
? new Date(stateLaporan.create.form.tanggalWaktu)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
onChange={(val) => {
|
||||||
|
if (val) {
|
||||||
|
stateLaporan.create.form.tanggalWaktu = val.toString();
|
||||||
|
} else {
|
||||||
|
stateLaporan.create.form.tanggalWaktu = ""; // Reset kalau dikosongkan
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
value={stateLaporan.create.form.status}
|
||||||
|
onChange={(e) => stateLaporan.create.form.status = e?.valueOf() as Status}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Status Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan status LaporanPublik'
|
||||||
|
data={[
|
||||||
|
{ value: "Selesai", label: "Selesai" },
|
||||||
|
{ value: "Proses", label: "Proses" },
|
||||||
|
{ value: "Gagal", label: "Gagal" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
value={stateLaporan.create.form.kronologi}
|
||||||
|
onChange={(e) => stateLaporan.create.form.kronologi = e.target.value}
|
||||||
|
label={<Text fw={"bold"} fz={"sm"}>Kronologi Laporan Publik</Text>}
|
||||||
|
placeholder='Masukkan kronologi LaporanPublik'
|
||||||
|
/>
|
||||||
|
<Text fw={"bold"} fz={"sm"}>Penanganan Laporan Publik</Text>
|
||||||
<Box>
|
<Box>
|
||||||
<Text fw={"bold"} fz={"sm"}>Deskripsi Laporan Publik</Text>
|
<Text fw={"bold"} fz={"sm"}>Deskripsi Laporan Publik</Text>
|
||||||
<KeamananEditor
|
<CreateEditor
|
||||||
showSubmit={false}
|
value={stateLaporan.create.form.penanganan}
|
||||||
|
onChange={(e) => stateLaporan.create.form.penanganan = e}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Group>
|
<Group>
|
||||||
<Button bg={colors['blue-button']}>Submit</Button>
|
<Button onClick={handleSubmit} bg={colors['blue-button']}>Submit</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Button, Paper, Stack, Flex, Text, Image } from '@mantine/core';
|
|
||||||
import { IconArrowBack, IconX, IconEdit } from '@tabler/icons-react';
|
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import React from 'react';
|
|
||||||
// import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
|
|
||||||
|
|
||||||
function DetailLaporanPublik() {
|
|
||||||
const router = useRouter();
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Box mb={10}>
|
|
||||||
<Button variant="subtle" onClick={() => router.back()}>
|
|
||||||
<IconArrowBack color={colors['blue-button']} size={25} />
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack>
|
|
||||||
<Text fz={"xl"} fw={"bold"}>Detail Laporan Publik</Text>
|
|
||||||
|
|
||||||
<Paper bg={colors['BG-trans']} p={'md'}>
|
|
||||||
<Stack gap={"xs"}>
|
|
||||||
<Box>
|
|
||||||
<Text fz={"lg"} fw={"bold"}>Judul Laporan Publik</Text>
|
|
||||||
<Text fz={"lg"}>Test Judul</Text>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Text fz={"lg"} fw={"bold"}>Tanggal Laporan Publik</Text>
|
|
||||||
<Text fz={"lg"}>Test Tanggal</Text>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Text fz={"lg"} fw={"bold"}>Deskripsi</Text>
|
|
||||||
<Text fz={"lg"}>Test Deskripsi</Text>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Text fz={"lg"} fw={"bold"}>Gambar</Text>
|
|
||||||
<Image src={"/"} alt="gambar" />
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Text fz={"lg"} fw={"bold"}>Konten</Text>
|
|
||||||
<Text fz={"lg"} >Test Konten</Text>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Flex gap={"xs"}>
|
|
||||||
<Button color="red">
|
|
||||||
<IconX size={20} />
|
|
||||||
</Button>
|
|
||||||
<Button onClick={() => router.push('/admin/keamanan/laporan-publik/edit')} color="green">
|
|
||||||
<IconEdit size={20} />
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
|
|
||||||
{/* Modal Hapus
|
|
||||||
<ModalKonfirmasiHapus
|
|
||||||
opened={modalHapus}
|
|
||||||
onClose={() => setModalHapus(false)}
|
|
||||||
onConfirm={handleHapus}
|
|
||||||
text="Apakah anda yakin ingin menghapus potensi ini?"
|
|
||||||
/> */}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DetailLaporanPublik;
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import colors from '@/con/colors';
|
|
||||||
import { Box, Button, Group, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
|
|
||||||
import { IconArrowBack, IconImageInPicture } from '@tabler/icons-react';
|
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import { KeamananEditor } from '../../_com/keamananEditor';
|
|
||||||
|
|
||||||
function EditLaporanPublik() {
|
|
||||||
const router = useRouter();
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Box mb={10}>
|
|
||||||
<Button onClick={() => router.back()} variant='subtle' color={'blue'}>
|
|
||||||
<IconArrowBack color={colors['blue-button']} size={25}/>
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Paper w={{base: '100%', md: '50%'}} bg={colors['white-1']} p={'md'}>
|
|
||||||
<Stack gap={"xs"}>
|
|
||||||
<Title order={4}>Edit Laporan Publik</Title>
|
|
||||||
<Box>
|
|
||||||
<Text fw={"bold"} fz={"sm"}>Masukkan Image</Text>
|
|
||||||
<IconImageInPicture size={50} />
|
|
||||||
</Box>
|
|
||||||
<TextInput
|
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Judul Laporan Publik</Text>}
|
|
||||||
placeholder='Masukkan judul Laporan Publik'
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
label={<Text fw={"bold"} fz={"sm"}>Tanggal Laporan Publik</Text>}
|
|
||||||
placeholder='Masukkan tanggal Laporan Publik'
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Text fw={"bold"} fz={"sm"}>Deskripsi Laporan Publik</Text>
|
|
||||||
<KeamananEditor
|
|
||||||
showSubmit={false}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Group>
|
|
||||||
<Button bg={colors['blue-button']}>Submit</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EditLaporanPublik;
|
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Paper, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
import { Box, Button, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr } from '@mantine/core';
|
||||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||||
import HeaderSearch from '../../_com/header';
|
import HeaderSearch from '../../_com/header';
|
||||||
import JudulList from '../../_com/judulList';
|
import JudulList from '../../_com/judulList';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import laporanPublikState from '../../_state/keamanan/laporan-publik';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
|
||||||
function LaporanPublik() {
|
function LaporanPublik() {
|
||||||
return (
|
return (
|
||||||
@@ -20,7 +23,20 @@ function LaporanPublik() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ListLaporanPublik() {
|
function ListLaporanPublik() {
|
||||||
|
const stateLaporan = useProxy(laporanPublikState)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
stateLaporan.findMany.load()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!stateLaporan.findMany.data) {
|
||||||
|
return (
|
||||||
|
<Stack py={10}>
|
||||||
|
<Skeleton h={500} />
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={10}>
|
||||||
<Paper bg={colors['white-1']} p={'md'}>
|
<Paper bg={colors['white-1']} p={'md'}>
|
||||||
@@ -33,21 +49,25 @@ function ListLaporanPublik() {
|
|||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Judul Laporan Publik</TableTh>
|
<TableTh>Judul Laporan Publik</TableTh>
|
||||||
<TableTh>Tanggal Laporan Publik</TableTh>
|
<TableTh>Tanggal Laporan Publik</TableTh>
|
||||||
|
<TableTh>Status</TableTh>
|
||||||
<TableTh>Deskripsi</TableTh>
|
<TableTh>Deskripsi</TableTh>
|
||||||
<TableTh>Detail</TableTh>
|
<TableTh>Detail</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
<TableTr>
|
{stateLaporan.findMany.data?.map((item) => (
|
||||||
<TableTd>Laporan Publik 1</TableTd>
|
<TableTr key={item.id}>
|
||||||
<TableTd>0896232831883</TableTd>
|
<TableTd>{item.judul}</TableTd>
|
||||||
<TableTd>Laporan Publik 1</TableTd>
|
<TableTd>{new Date(item.tanggalWaktu).toLocaleDateString('id-ID')}</TableTd>
|
||||||
<TableTd>
|
<TableTd>{item.status}</TableTd>
|
||||||
<Button onClick={() => router.push('/admin/keamanan/laporan-publik/detail')}>
|
<TableTd>{item.kronologi}</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Button onClick={() => router.push(`/admin/keamanan/laporan-publik/${item.id}`)}>
|
||||||
<IconDeviceImac size={20} />
|
<IconDeviceImac size={20} />
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
|
))}
|
||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ type LaporanPublikInput = {
|
|||||||
judul: string;
|
judul: string;
|
||||||
lokasi: string;
|
lokasi: string;
|
||||||
tanggalWaktu: string;
|
tanggalWaktu: string;
|
||||||
status: "SELESAI" | "PROSES" | "GAGAL";
|
status: "Selesai" | "Proses" | "Gagal";
|
||||||
penanganan: string[];
|
penanganan: string;
|
||||||
kronologi?: string;
|
kronologi?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -21,9 +21,9 @@ const laporanPublikCreate = async (context: Context) => {
|
|||||||
tanggalWaktu: new Date(tanggalWaktu),
|
tanggalWaktu: new Date(tanggalWaktu),
|
||||||
status,
|
status,
|
||||||
penanganan: {
|
penanganan: {
|
||||||
create: penanganan.map((item) => ({
|
create: {
|
||||||
deskripsi: item,
|
deskripsi: penanganan,
|
||||||
})),
|
},
|
||||||
},
|
},
|
||||||
kronologi,
|
kronologi,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ const LaporanPublik = new Elysia({
|
|||||||
lokasi: t.String(),
|
lokasi: t.String(),
|
||||||
tanggalWaktu: t.String(), // ISO string
|
tanggalWaktu: t.String(), // ISO string
|
||||||
status: t.Union([
|
status: t.Union([
|
||||||
t.Literal("SELESAI"),
|
t.Literal("Selesai"),
|
||||||
t.Literal("PROSES"),
|
t.Literal("Proses"),
|
||||||
t.Literal("GAGAL"),
|
t.Literal("Gagal"),
|
||||||
]),
|
]),
|
||||||
penanganan: t.Array(t.String()), // 🛠️ ARRAY of strings
|
penanganan: t.String(), // 🛠️ ARRAY of strings
|
||||||
kronologi: t.Optional(t.String()),
|
kronologi: t.Optional(t.String()),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
@@ -31,11 +31,11 @@ const LaporanPublik = new Elysia({
|
|||||||
lokasi: t.String(),
|
lokasi: t.String(),
|
||||||
tanggalWaktu: t.String(), // ISO string
|
tanggalWaktu: t.String(), // ISO string
|
||||||
status: t.Union([
|
status: t.Union([
|
||||||
t.Literal("SELESAI"),
|
t.Literal("Selesai"),
|
||||||
t.Literal("PROSES"),
|
t.Literal("Proses"),
|
||||||
t.Literal("GAGAL"),
|
t.Literal("Gagal"),
|
||||||
]),
|
]),
|
||||||
penanganan: t.Array(t.String()), // 🛠️ ARRAY of strings
|
penanganan: t.String(), // 🛠️ ARRAY of strings
|
||||||
kronologi: t.Optional(t.String()),
|
kronologi: t.Optional(t.String()),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ type LaporanPublikUpdateInput = {
|
|||||||
judul: string;
|
judul: string;
|
||||||
lokasi: string;
|
lokasi: string;
|
||||||
tanggalWaktu: string;
|
tanggalWaktu: string;
|
||||||
status: "SELESAI" | "PROSES" | "GAGAL";
|
status: "Selesai" | "Proses" | "Gagal";
|
||||||
penanganan: string[];
|
penanganan: string;
|
||||||
kronologi?: string;
|
kronologi?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ const LaporanPublikUpdate = async (context: Context) => {
|
|||||||
status,
|
status,
|
||||||
kronologi,
|
kronologi,
|
||||||
penanganan: {
|
penanganan: {
|
||||||
create: penanganan.map((item) => ({
|
create: {
|
||||||
deskripsi: item,
|
deskripsi: penanganan,
|
||||||
})),
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ const menuTipsKeamananDelete = async (context: Context) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 200,
|
success: true,
|
||||||
body: deleted,
|
message: "Success delete menu tips keamanan",
|
||||||
|
data: deleted,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export default menuTipsKeamananDelete;
|
export default menuTipsKeamananDelete;
|
||||||
Reference in New Issue
Block a user