diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3783364..d64f11e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -110,7 +110,8 @@ model CategoryPelayanan { id String @id @default(cuid()) name String syaratDokumen Json[] - dataText String[] + dataText String[] @default([]) + dataPelengkap Json[] @default([]) isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/src/components/FullScreenLoading.tsx b/src/components/FullScreenLoading.tsx new file mode 100644 index 0000000..f72d611 --- /dev/null +++ b/src/components/FullScreenLoading.tsx @@ -0,0 +1,43 @@ +import { Center, Loader, Overlay, Stack, Text } from "@mantine/core" + +type FullScreenLoadingProps = { + visible: boolean + text?: string +} + +export default function FullScreenLoading({ + visible, + text = "Memproses data..." +}: FullScreenLoadingProps) { + if (!visible) return null + + return ( + +
+ + + + {text} + + +
+
+ ) +} + +const overlayStyle: React.CSSProperties = { + position: "fixed", + inset: 0, + zIndex: 9999, + backdropFilter: "blur(6px)", + backgroundColor: "rgba(255, 255, 255, 0.6)" +} + +const contentStyle: React.CSSProperties = { + flexDirection: "column" +} diff --git a/src/components/SuccessPengajuanSurat.tsx b/src/components/SuccessPengajuanSurat.tsx new file mode 100644 index 0000000..07965f5 --- /dev/null +++ b/src/components/SuccessPengajuanSurat.tsx @@ -0,0 +1,50 @@ +import { Badge, Button, Card, Center, Stack, Text, Title } from "@mantine/core" +import { IconCheck } from "@tabler/icons-react" + +type SuccessPengajuanProps = { + noPengajuan: string + onClose?: () => void +} + +export default function SuccessPengajuan({ + noPengajuan, + onClose +}: SuccessPengajuanProps) { + return ( +
+ + + + + + Pengajuan Berhasil Dibuat + + + + Pengajuan layanan surat sudah dibuat dengan nomor: + + + + {noPengajuan} + + + + Nomor ini akan digunakan untuk mengakses dan memantau status + pengajuan surat Anda. + + + + + +
+ ) +} diff --git a/src/lib/categoryPelayananSurat.ts b/src/lib/categoryPelayananSurat.ts index c03ee14..c0e2f48 100644 --- a/src/lib/categoryPelayananSurat.ts +++ b/src/lib/categoryPelayananSurat.ts @@ -3,107 +3,369 @@ export const categoryPelayananSurat = [ id: "skbedabiodata", name: "Surat Keterangan Beda Biodata Diri", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas di Wilayah Masing-masing" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" }, - { name: "dokumen yang beda", desc: "Fotokopi dokumen bersangkutan yang terdapat perbedaan biodata diri, misalnya: Sertifikat Tanah, Ijazah, Polis Asuransi, dan lainnya." } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas di Wilayah Masing-masing" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + }, + { + key: "dokumen_beda", + name: "Dokumen Pendukung", + desc: "Fotokopi dokumen yang terdapat perbedaan biodata (ijazah, sertifikat, dll)" + } ], - dataText: ["nik", "nama", "tempat tanggal lahir", "jenis kelamin", "alamat", "pekerjaan", "dokumen", "tertulis pada dokumen a", "tertulis pada dokumen b"] + dataText: [], + dataPelengkap: [ + { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" }, + { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir pemohon" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" }, + { key: "alamat", name: "Alamat", desc: "Alamat lengkap tempat tinggal" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" }, + { key: "dokumen", name: "Nama Dokumen", desc: "Jenis dokumen yang mengalami perbedaan biodata" }, + { key: "dokumen_a", name: "Data pada Dokumen A", desc: "Data biodata yang tertulis pada dokumen pertama" }, + { key: "dokumen_b", name: "Data pada Dokumen B", desc: "Data biodata yang tertulis pada dokumen kedua" } + ] }, { id: "skbelumkawin", name: "Surat Keterangan Belum Kawin", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" }, - { name: "akta cerai", desc: "Fotokopi Akta Cerai bagi yang berstatus janda/duda" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + }, + { + key: "akta_cerai", + name: "Akta Cerai", + desc: "Fotokopi akta cerai (jika berstatus janda/duda)" + } ], - dataText: ["nik", "nama", "tempat tanggal lahir", "jenis kelamin", "alamat", "agama", "pekerjaan"] + dataText: [], + dataPelengkap: [ + { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" }, + { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" }, + { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" }, + { key: "agama", name: "Agama", desc: "Agama pemohon" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" } + ] }, { id: "skdomisiliorganisasi", name: "Surat Keterangan Domisili Organisasi", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "skt organisasi", desc: "Fotokopi Surat Keterangan Terdaftar (SKT) Organisasi atau Pengukuhan Kelompok" }, - { name: "susunan pengurus", desc: "Jika Pengajuan baru pembuatan SKT maka melengkapi Susunan Pengurus lengkap denganKop Organisasi" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "skt_organisasi", + name: "SKT Organisasi", + desc: "Fotokopi SKT Organisasi atau pengukuhan kelompok" + }, + { + key: "susunan_pengurus", + name: "Susunan Pengurus", + desc: "Susunan pengurus lengkap dengan kop organisasi" + } ], - dataText: ["nama organisasi", "jenis organisasi", "alamat organisasi/sekretariat", "no telepon", "nama pimpinan", "keperluan"] + dataText: [], + dataPelengkap: [ + { key: "nama_organisasi", name: "Nama Organisasi", desc: "Nama resmi organisasi" }, + { key: "jenis_organisasi", name: "Jenis Organisasi", desc: "Jenis atau bentuk organisasi" }, + { key: "alamat_organisasi", name: "Alamat Organisasi", desc: "Alamat sekretariat organisasi" }, + { key: "no_telepon", name: "Nomor Telepon", desc: "Nomor telepon organisasi" }, + { key: "nama_pimpinan", name: "Nama Pimpinan", desc: "Nama pimpinan organisasi" }, + { key: "keperluan", name: "Keperluan", desc: "Keperluan pembuatan surat" } + ] }, { id: "skkelahiran", name: "Surat Keterangan Kelahiran", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "surat lahir", desc: "Fotokopi Surat Keterangan Lahir dari Bidan/Dokter (jika ada)" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "surat_lahir", + name: "Surat Keterangan Lahir", + desc: "Surat keterangan lahir dari bidan/dokter (jika ada)" + } ], - dataText: ["nama ayah", "nama ibu", "nama anak", "tanggal lahir anak", "pukul lahir anak", "tempat lahir anak", "jenis kelamin anak", "anak ke", "nik ibu", "tempat tanggal lahir ibu", "pekerjaan ibu", "alamat ibu", "nik ayah", "tempat tanggal lahir ayah", "pekerjaan ayah", "alamat ayah", "nama pelapor", "hubungan pelapor", "alamat pelapor"] + dataText: [], + dataPelengkap: [ + { key: "nama_ayah", name: "Nama Ayah", desc: "Nama lengkap ayah" }, + { key: "nama_ibu", name: "Nama Ibu", desc: "Nama lengkap ibu" }, + { key: "nama_anak", name: "Nama Anak", desc: "Nama bayi/anak" }, + { key: "tanggal_lahir_anak", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak" }, + { key: "pukul_lahir", name: "Pukul Lahir", desc: "Waktu kelahiran anak" }, + { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat kelahiran anak" }, + { key: "jenis_kelamin", name: "Jenis Kelamin Anak", desc: "Jenis kelamin anak" }, + { key: "anak_ke", name: "Anak Ke-", desc: "Urutan kelahiran anak" }, + { key: "nik_ibu", name: "NIK Ibu", desc: "NIK ibu kandung" }, + { key: "nik_ayah", name: "NIK Ayah", desc: "NIK ayah kandung" }, + { key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pihak yang melaporkan" }, + { key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan pelapor dengan anak" }, + { key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor" } + ] }, { id: "skkelakuanbaik", name: "Surat Keterangan Kelakuan Baik (Pengantar SKCK)", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + } ], - dataText: ["nik", "nama", "tempat tanggal lahir", "jenis kelamin", "agama", "alamat", "pekerjaan", "polsek"] + dataText: [], + dataPelengkap: [ + { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" }, + { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" }, + { key: "agama", name: "Agama", desc: "Agama pemohon" }, + { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" }, + { key: "polsek", name: "Polsek Tujuan", desc: "Polsek tujuan pembuatan SKCK" } + ] }, { id: "skkematian", name: "Surat Keterangan Kematian", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" }, - { name: "surat kematian", desc: "Surat Keterangan Kematian dari Rumah Sakit/Dokter (jika ada)" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + }, + { + key: "surat_kematian", + name: "Surat Keterangan Kematian", + desc: "Surat keterangan kematian dari rumah sakit/dokter (jika ada)" + } ], - dataText: ["nik pelapor", "nama pelapor", "pekerjaan pelapor", "alamat pelapor", "hubungan pelapor dengan almarhum", "nama almarhum", "nik almarhum", "tempat tanggal lahir almarhum", "alamat almarhum", "agama almarhum", "tanggal kematian", "waktu kematian", "tempat kematian", "penyebab kematian"] + dataText: [], + dataPelengkap: [ + { key: "nik_pelapor", name: "NIK Pelapor", desc: "Nomor Induk Kependudukan pelapor" }, + { key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama lengkap pelapor" }, + { key: "pekerjaan_pelapor", name: "Pekerjaan Pelapor", desc: "Pekerjaan pelapor" }, + { key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat tempat tinggal pelapor" }, + { key: "hubungan_pelapor", name: "Hubungan dengan Almarhum", desc: "Hubungan pelapor dengan almarhum" }, + { key: "nama_almarhum", name: "Nama Almarhum", desc: "Nama lengkap almarhum" }, + { key: "nik_almarhum", name: "NIK Almarhum", desc: "Nomor Induk Kependudukan almarhum" }, + { key: "ttl_almarhum", name: "Tempat & Tanggal Lahir Almarhum", desc: "Tempat dan tanggal lahir almarhum" }, + { key: "alamat_almarhum", name: "Alamat Almarhum", desc: "Alamat terakhir almarhum" }, + { key: "agama_almarhum", name: "Agama Almarhum", desc: "Agama almarhum" }, + { key: "tanggal_kematian", name: "Tanggal Kematian", desc: "Tanggal meninggal dunia" }, + { key: "waktu_kematian", name: "Waktu Kematian", desc: "Waktu meninggal dunia" }, + { key: "tempat_kematian", name: "Tempat Kematian", desc: "Tempat meninggal dunia" }, + { key: "penyebab_kematian", name: "Penyebab Kematian", desc: "Penyebab meninggal dunia" } + ] }, { id: "skpenghasilan", name: "Surat Keterangan Penghasilan", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp ortu/kk", desc: "Fotokopi KTP orang tua atau Kartu Keluarga" }, - { name: "surat pernyataan", desc: "Surat Pernyataan Penghasilan bermaterai" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_ortu_kk", + name: "KTP Orang Tua / KK", + desc: "Fotokopi KTP orang tua atau Kartu Keluarga" + }, + { + key: "surat_pernyataan", + name: "Surat Pernyataan", + desc: "Surat pernyataan penghasilan bermaterai" + } ], - dataText: ["nama", "tempat tanggal lahir", "jenis kelamin", "alamat", "pekerjaan", "penghasilan", "alasan permohonan"] + dataText: [], + dataPelengkap: [ + { key: "nama", name: "Nama Lengkap", desc: "Nama pemohon" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" }, + { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon/orang tua" }, + { key: "penghasilan", name: "Penghasilan", desc: "Jumlah penghasilan per bulan" }, + { key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan surat penghasilan" } + ] }, { id: "sktempatusaha", name: "Surat Keterangan Tempat Usaha", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" }, - { name: "foto lokasi", desc: "Foto lokasi usaha dicetak dalam selembar kertas, diparaf dan distempel oleh Kelian" }, - { name: "sppt/sertifikat/sewa", desc: "Fotokopi SPPT, Sertifikat Hak Milik, Surat Perjanjian Sewa, atau Kwitansi Pembayaran Sewa 3 bulan terakhir" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + }, + { + key: "foto_lokasi", + name: "Foto Lokasi Usaha", + desc: "Foto lokasi usaha dicetak dan distempel oleh Kelian" + }, + { + key: "dokumen_lahan", + name: "Dokumen Lahan", + desc: "SPPT, Sertifikat, atau surat sewa tempat usaha" + } ], - dataText: ["nik", "nama pemilik", "tempat tanggal lahir", "alamat pemilik", "nama usaha", "bidang usaha", "alamat usaha", "status tempat usaha", "luas tempat usaha", "jumlah karyawan", "tujuan pembuatan surat"] + dataText: [], + dataPelengkap: [ + { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" }, + { key: "nama_pemilik", name: "Nama Pemilik", desc: "Nama pemilik usaha" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" }, + { key: "alamat_pemilik", name: "Alamat Pemilik", desc: "Alamat pemilik usaha" }, + { key: "nama_usaha", name: "Nama Usaha", desc: "Nama usaha" }, + { key: "bidang_usaha", name: "Bidang Usaha", desc: "Bidang atau jenis usaha" }, + { key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha" }, + { key: "status_tempat", name: "Status Tempat Usaha", desc: "Status kepemilikan tempat usaha" }, + { key: "luas_usaha", name: "Luas Tempat Usaha", desc: "Luas tempat usaha (m²)" }, + { key: "jumlah_karyawan", name: "Jumlah Karyawan", desc: "Jumlah tenaga kerja" }, + { key: "tujuan", name: "Tujuan Pembuatan Surat", desc: "Tujuan pembuatan surat keterangan" } + ] }, { id: "sktidakmampu", name: "Surat Keterangan Tidak Mampu", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kia/kk", desc: "Fotokopi KTP, KIA, atau Kartu Keluarga" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kia_kk", + name: "KTP / KIA / KK", + desc: "Fotokopi KTP, KIA, atau Kartu Keluarga" + } ], - dataText: ["nik", "nama", "tempat tanggal lahir", "alamat", "alasan permohonan"] + dataText: [], + dataPelengkap: [ + { + key: "nik", + name: "NIK", + desc: "Nomor Induk Kependudukan pemohon" + }, + { + key: "nama", + name: "Nama Lengkap", + desc: "Nama lengkap pemohon" + }, + { + key: "ttl", + name: "Tempat & Tanggal Lahir", + desc: "Tempat dan tanggal lahir pemohon" + }, + { + key: "alamat", + name: "Alamat", + desc: "Alamat tempat tinggal pemohon" + }, + { + key: "alasan", + name: "Alasan Permohonan", + desc: "Alasan pengajuan Surat Keterangan Tidak Mampu" + } + ] }, { id: "skusaha", name: "Surat Keterangan Usaha", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kk", desc: "Fotokopi KTP atau Kartu Keluarga" }, - { name: "foto lokasi", desc: "Foto lokasi usaha dicetak dalam selembar kertas, diparaf dan distempel oleh Kelian" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kk", + name: "KTP / KK", + desc: "Fotokopi KTP atau Kartu Keluarga" + }, + { + key: "foto_lokasi", + name: "Foto Lokasi Usaha", + desc: "Foto lokasi usaha dicetak dan distempel oleh Kelian" + } ], - dataText: ["nama", "jenis kelamin", "tempat tanggal lahir", "negara", "agama", "status perkawinan", "alamat", "pekerjaan", "jenis usaha", "alamat usaha"] + dataText: [], + dataPelengkap: [ + { key: "nama", name: "Nama Lengkap", desc: "Nama pemilik usaha" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemilik usaha" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" }, + { key: "negara", name: "Kewarganegaraan", desc: "Kewarganegaraan pemilik usaha" }, + { key: "agama", name: "Agama", desc: "Agama pemilik usaha" }, + { key: "status_perkawinan", name: "Status Perkawinan", desc: "Status perkawinan" }, + { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemilik usaha" }, + { key: "jenis_usaha", name: "Jenis Usaha", desc: "Jenis usaha yang dijalankan" }, + { key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha" } + ] }, { id: "skyatimpiatu", name: "Surat Keterangan Yatim / Piatu / Yatim Piatu", syaratDokumen: [ - { name: "pengantar kelian", desc: "Surat Pengantar Kelian Banjar Dinas" }, - { name: "ktp/kia/kk", desc: "Fotokopi KTP, KIA, atau Kartu Keluarga" } + { + key: "pengantar_kelian", + name: "Pengantar Kelian", + desc: "Surat Pengantar Kelian Banjar Dinas" + }, + { + key: "ktp_kia_kk", + name: "KTP / KIA / KK", + desc: "Fotokopi KTP, KIA, atau Kartu Keluarga" + } ], - dataText: ["nik", "nama", "tempat tanggal lahir", "jenis kelamin", "alamat", "pekerjaan", "nama ayah", "status ayah", "nama ibu", "status ibu"] + dataText: [], + dataPelengkap: [ + { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" }, + { key: "nama", name: "Nama Lengkap", desc: "Nama anak" }, + { key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir anak" }, + { key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin anak" }, + { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" }, + { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan (jika ada)" }, + { key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah kandung" }, + { key: "status_ayah", name: "Status Ayah", desc: "Status ayah (hidup / meninggal)" }, + { key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu kandung" }, + { key: "status_ibu", name: "Status Ibu", desc: "Status ibu (hidup / meninggal)" } + ] } ]; diff --git a/src/pages/darmasaba/surat.tsx b/src/pages/darmasaba/surat.tsx index 4a40569..6c9dc0c 100644 --- a/src/pages/darmasaba/surat.tsx +++ b/src/pages/darmasaba/surat.tsx @@ -1,6 +1,8 @@ +import FullScreenLoading from "@/components/FullScreenLoading"; import notification from "@/components/notificationGlobal"; +import SuccessPengajuan from "@/components/SuccessPengajuanSurat"; import apiFetch from "@/lib/apiFetch"; -import { capitalizeWords, fromSlug, toSlug } from "@/server/lib/slug_converter"; +import { fromSlug, toSlug } from "@/server/lib/slug_converter"; import { ActionIcon, Badge, @@ -9,7 +11,8 @@ import { Card, Container, Divider, - FileButton, + FileInput, + Flex, Grid, Group, Select, @@ -30,20 +33,22 @@ import { useLocation, useNavigate } from "react-router-dom"; import useSWR from "swr"; type DataItem = { - jenis: string; + key: string; value: string; }; type FormSurat = { - kategoryId: string; + kategoriId: string; nama: string; phone: string; - dataText: DataItem[]; + dataPelengkap: DataItem[]; syaratDokumen: DataItem[]; }; export default function FormSurat() { + const [noPengajuan, setNoPengajuan] = useState("") + const [submitLoading, setSubmitLoading] = useState(false) const navigate = useNavigate(); const { search } = useLocation(); const query = new URLSearchParams(search); @@ -56,13 +61,25 @@ export default function FormSurat() { const [formSurat, setFormSurat] = useState({ nama: "", phone: "", - kategoryId: "", - dataText: [], + kategoriId: "", + dataPelengkap: [], syaratDokumen: [], }) const listCategory = data?.data || []; + function onResetAll() { + setNoPengajuan("") + setSubmitLoading(false) + setFormSurat({ + nama: "", + phone: "", + kategoriId: "", + dataPelengkap: [], + syaratDokumen: [], + }) + } + function onGetJenisSurat() { try { if (!jenisSurat || jenisSurat == "null") { @@ -86,18 +103,19 @@ export default function FormSurat() { id: jenisSuratFix.id, }, }) + setDataSurat(get.data) setFormSurat({ - kategoryId: jenisSuratFix.id, + kategoriId: jenisSuratFix.id, nama: "", phone: "", - dataText: (get.data?.dataText || []).map((item: string) => ({ - jenis: item, + dataPelengkap: (get.data?.dataPelengkap || []).map((item: { key: string }) => ({ + key: item.key, value: "", })), syaratDokumen: (get.data?.syaratDokumen || []).map( - (item: { name: string }) => ({ - jenis: item.name, + (item: { key: string }) => ({ + key: item.key, value: "", }) ), @@ -126,49 +144,129 @@ export default function FormSurat() { } }, [jenisSuratFix.id]); - function onSubmit() { + async function onSubmit() { const isFormKosong = Object.values(formSurat).some((value) => { if (Array.isArray(value)) { return ( value.length === 0 || - value.some((item) => !item.value?.trim()) - ); + value.some( + (item) => typeof item.value === "string" && item.value.trim() === "" + ) + ) } if (typeof value === "string") { - return value.trim() === ""; + return value.trim() === "" } - return false; - }); + return false + }) if (isFormKosong) { return notification({ title: "Gagal", message: "Silahkan lengkapi form surat", type: "error", - }); + }) } - console.log("READY SUBMIT", formSurat); + try { + setSubmitLoading(true) + // 🔥 CLONE state SEKALI + let finalFormSurat = structuredClone(formSurat) + + // 2️⃣ Upload satu per satu + for (const itemUpload of finalFormSurat.syaratDokumen) { + const updImg = await apiFetch.api.pengaduan.upload.post({ + file: itemUpload.value, + folder: "syarat-dokumen", + }) + + if (updImg.status === 200) { + // 🔥 UPDATE OBJECT LOKAL (BUKAN STATE) + finalFormSurat.syaratDokumen = updateArrayByKey( + finalFormSurat.syaratDokumen, + itemUpload.key, + updImg.data?.filename || "" + ) + } + } + + // 3️⃣ SET STATE SEKALI (optional, untuk UI) + setFormSurat(finalFormSurat) + + // 4️⃣ SUBMIT KE API + const res = await apiFetch.api.pelayanan.create.post(finalFormSurat) + + if (res.status === 200) { + notification({ + title: "Berhasil", + message: res.data?.message || "Pengajuan surat berhasil dibuat", + type: "success", + }) + } else { + notification({ + title: "Gagal", + message: "Pengajuan surat gagal dibuat, silahkan coba beberapa saat lagi", + type: "error", + }) + } + } catch (error) { + notification({ + title: "Gagal", + message: "Server Error", + type: "error" + }) + } finally { + setSubmitLoading(false) + } } + function updateArrayByKey(list: DataItem[], targetKey: string, value: string): DataItem[] { + return list.map(item => + item.key === targetKey + ? { ...item, value } + : item + ) + } + + function validationForm({ key, value }: { key: 'nama' | 'phone' | 'dataPelengkap' | 'syaratDokumen', value: any }) { + if (key == "dataPelengkap" || key == "syaratDokumen") { + setFormSurat(prev => ({ + ...prev, + [key]: updateArrayByKey( + prev[key], + value.key, + value.value + ) + })) + } else { + setFormSurat({ + ...formSurat, + [key]: value, + }) + } + } + return ( + + { + noPengajuan != "" && + { onResetAll(); navigate("/darmasaba/surat") }} /> + } - +
- Surat Keterangan Tidak Mampu (SKTM) + Layanan Pengajuan Surat Administrasi - Blangko resmi untuk pengajuan Surat Keterangan Tidak Mampu — - digunakan untuk keperluan pendidikan, kesehatan, atau - administrasi. + Formulir resmi untuk mengajukan berbagai jenis surat administrasi desa/kelurahan secara online.
@@ -188,11 +286,13 @@ export default function FormSurat() { } placeholder="Budi Setiawan" + value={formSurat.nama} + onChange={(e) => validationForm({ key: "nama", value: e.target.value })} /> @@ -205,6 +305,8 @@ export default function FormSurat() { /> } placeholder="08123456789" + value={formSurat.phone} + onChange={(e) => validationForm({ key: "phone", value: e.target.value })} /> @@ -227,7 +329,7 @@ export default function FormSurat() { { - jenisSuratFix.id != "" && dataSurat && dataSurat.dataText && + jenisSuratFix.id != "" && dataSurat && dataSurat.dataPelengkap && <> { - dataSurat.dataText.map((item: any, index: number) => ( + dataSurat.dataPelengkap.map((item: any, index: number) => ( } - placeholder={dataSurat.dataText[index] == "nik" ? "NIK" : capitalizeWords(dataSurat.dataText[index])} + placeholder={item.name} + onChange={(e) => validationForm({ key: "dataPelengkap", value: { key: item.key, value: e.target.value } })} + value={formSurat.dataPelengkap.find((n: any) => n.key == item.key)?.value} /> )) @@ -259,28 +364,13 @@ export default function FormSurat() { { dataSurat.syaratDokumen.map((item: any, index: number) => ( - validationForm({ key: "syaratDokumen", value: { key: item.key, value: file } })} + name={item.name} /> - { - if (!file) return; - // const base64 = await fileToBase64(file); - // form.setFieldValue("foto", base64); - // setFotoName(file.name); - }} - accept="image/*" - > - {(props) => ( - - )} - )) } @@ -319,36 +409,6 @@ function FieldLabel({ label, hint }: { label: string; hint?: string }) { ); } -function FieldLabelUpload({ - label, - description, -}: { - label: React.ReactNode; - description?: string; -}) { - return ( -
- - - - {label} - - {description && ( - - - - )} - - - {description && ( - - {description} - - )} -
- ); -} - function FormSection({ title, icon, @@ -375,3 +435,62 @@ function FormSection({ ); } + +function FileInputWrapper({ + label, + placeholder, + accept, + onChange, + preview, + name, + description, +}: { + label: string; + placeholder?: string; + accept?: string; + onChange: (file: File | null) => void; + preview?: string | null; + name: string; + description?: string; +}) { + return ( + + + + {label} + + {description && ( + + {description} + + )} + + + onChange(f)} + leftSection={} + aria-label={label} + name={name} + /> + + {preview ? ( +
+ + Preview: + + {/* If preview is an image it will show; pdf preview might not render as image */} + {/* Use or depending on file type — keep simple here */} +
+ {`${label} +
+ + ) : null} + + ); +} diff --git a/src/server/routes/pelayanan_surat_route.ts b/src/server/routes/pelayanan_surat_route.ts index a21981a..b50b6ab 100644 --- a/src/server/routes/pelayanan_surat_route.ts +++ b/src/server/routes/pelayanan_surat_route.ts @@ -114,8 +114,14 @@ const PelayananRoute = new Elysia({ return; } - const dataText: string[] = Array.isArray(data.dataText) - ? data.dataText.filter((v): v is string => typeof v === "string") + const dataPelengkap: { key: string }[] = Array.isArray(data.dataPelengkap) + ? data.dataPelengkap.filter( + (v): v is { key: string } => + typeof v === "object" && + v !== null && + "key" in v && + typeof (v as any).key === "string" + ) : []; const syaratDokumen: { name: string }[] = Array.isArray(data.syaratDokumen) @@ -132,7 +138,7 @@ const PelayananRoute = new Elysia({ return { id: data.id, name: data.name, - dataText, + dataPelengkap, syaratDokumen, }; }, { @@ -208,8 +214,8 @@ const PelayananRoute = new Elysia({ CategoryPelayanan: { select: { name: true, - dataText: true, syaratDokumen: true, + dataPelengkap:true } }, Warga: { @@ -275,10 +281,11 @@ const PelayananRoute = new Elysia({ const syaratDokumen = (data?.CategoryPelayanan?.syaratDokumen ?? []) as { name: string; desc: string; + key: string; }[]; const dataSyaratFix = dataSyarat.map((item) => { - const desc = syaratDokumen.find((v) => v.name == item.jenis)?.desc + const desc = syaratDokumen.find((v) => v.key == item.jenis)?.desc return { id: item.id, jenis: desc, @@ -286,11 +293,17 @@ const PelayananRoute = new Elysia({ } }) + const dataTextCategory = (data?.CategoryPelayanan?.dataPelengkap ?? []) as { + name: string; + desc: string; + key: string; + }[]; + const dataTextFix = dataText.map((item) => { - const desc = data?.CategoryPelayanan?.dataText.find((v) => v == item.jenis) + const nama = dataTextCategory.find((v) => v.key == item.jenis)?.name return { id: item.id, - jenis: item.jenis, + jenis: nama, value: item.value, } }) @@ -360,9 +373,9 @@ const PelayananRoute = new Elysia({ } }) .post("/create", async ({ body, headers }) => { - const { kategoriId, dataText, syaratDokumen } = body - const namaWarga = headers['x-user'] || "" - const noTelepon = headers['x-phone'] || "" + const { kategoriId, dataPelengkap, syaratDokumen, nama, phone } = body + // const namaWarga = headers['x-user'] || "" + // const noTelepon = headers['x-phone'] || "" const noPengajuan = await generateNoPengajuanSurat() let idCategoryFix = kategoriId let idWargaFix = "" @@ -388,21 +401,21 @@ const PelayananRoute = new Elysia({ } - if (!isValidPhone(noTelepon)) { + if (!isValidPhone(phone)) { return { success: false, message: 'nomor telepon tidak valid, harap masukkan nomor yang benar' } } - const nomorHP = normalizePhoneNumber({ phone: noTelepon }) + const nomorHP = normalizePhoneNumber({ phone: phone }) const dataWarga = await prisma.warga.upsert({ where: { phone: nomorHP }, create: { - name: namaWarga, + name: nama, phone: nomorHP, }, update: { - name: namaWarga, + name: nama, }, select: { id: true @@ -433,16 +446,16 @@ const PelayananRoute = new Elysia({ dataInsertSyaratDokumen.push({ idPengajuanLayanan: pengaduan.id, idCategory: idCategoryFix, - jenis: item.jenis, + jenis: item.key, value: item.value, }) } - for (const item of dataText) { + for (const item of dataPelengkap) { dataInsertDataText.push({ idPengajuanLayanan: pengaduan.id, idCategory: idCategoryFix, - jenis: item.jenis, + jenis: item.key, value: item.value, }) } @@ -464,7 +477,7 @@ const PelayananRoute = new Elysia({ } }) - return { success: true, message: 'pengajuan layanan surat sudah dibuat dengan nomer ' + noPengajuan + ', nomer ini akan digunakan untuk mengakses pengajuan ini' } + return { success: true, message: 'Pengajuan layanan surat sudah dibuat dengan nomer ' + noPengajuan + ', nomer ini akan digunakan untuk mengakses pengajuan ini' } }, { body: t.Object({ kategoriId: t.String({ @@ -472,21 +485,20 @@ const PelayananRoute = new Elysia({ examples: ["skusaha"], error: "ID kategori harus diisi" }), - // namaWarga: t.String({ - // description: "Nama warga", - // examples: ["Budi Santoso"], - // error: "Nama warga harus diisi" - // }), + nama: t.String({ + description: "Nama warga", + examples: ["Budi Santoso"], + error: "Nama warga harus diisi" + }), + phone: t.String({ + error: "Nomor telepon harus diisi", + examples: ["08123456789", "+628123456789"], + description: "Nomor telepon warga pelapor" + }), - // noTelepon: t.String({ - // error: "Nomor telepon harus diisi", - // examples: ["08123456789", "+628123456789"], - // description: "Nomor telepon warga pelapor" - // }), - - dataText: t.Array( + dataPelengkap: t.Array( t.Object({ - jenis: t.String({ + key: t.String({ description: "Jenis field yang dibutuhkan oleh kategori pelayanan. Biasanya dinamis.", examples: ["nama", "jenis kelamin", "tempat tanggal lahir", "negara", "agama", "status perkawinan", "alamat", "pekerjaan", "jenis usaha", "alamat usaha"], error: "jenis harus diisi" @@ -501,25 +513,25 @@ const PelayananRoute = new Elysia({ description: "Kumpulan data text dinamis sesuai kategori layanan.", examples: [ [ - { jenis: "nama", value: "Budi Santoso" }, - { jenis: "jenis kelamin", value: "Laki-laki" }, - { jenis: "tempat tanggal lahir", value: "Denpasar, 28 Februari 1990" }, - { jenis: "negara", value: "Indonesia" }, - { jenis: "agama", value: "Islam" }, - { jenis: "status perkawinan", value: "Belum menikah" }, - { jenis: "alamat", value: "Jl. Mawar No. 10" }, - { jenis: "pekerjaan", value: "Karyawan Swasta" }, - { jenis: "jenis usaha", value: "usaha makanan" }, - { jenis: "alamat usaha", value: "Jl. Melati No. 21" }, + { key: "nama", value: "Budi Santoso" }, + { key: "jenis kelamin", value: "Laki-laki" }, + { key: "tempat tanggal lahir", value: "Denpasar, 28 Februari 1990" }, + { key: "negara", value: "Indonesia" }, + { key: "agama", value: "Islam" }, + { key: "status perkawinan", value: "Belum menikah" }, + { key: "alamat", value: "Jl. Mawar No. 10" }, + { key: "pekerjaan", value: "Karyawan Swasta" }, + { key: "jenis usaha", value: "usaha makanan" }, + { key: "alamat usaha", value: "Jl. Melati No. 21" }, ] ], - error: "dataText harus berupa array" + error: "Data Pelengkap harus berupa array" } ), syaratDokumen: t.Array( t.Object({ - jenis: t.String({ + key: t.String({ description: "Jenis dokumen persyaratan yang diminta oleh kategori layanan.", examples: ["ktp", "kk", "surat_pengantar_rt"], error: "jenis harus diisi" @@ -534,19 +546,18 @@ const PelayananRoute = new Elysia({ description: "Kumpulan dokumen yang wajib diupload sesuai persyaratan layanan.", examples: [ [ - { jenis: "pengantar kelian", value: "pengantar_kelurahan_budi.png" }, - { jenis: "ktp/kk", value: "kk_budi.png" }, - { jenis: "foto lokasi", value: "foto_lokasi_budi.png" } + { key: "pengantar kelian", value: "pengantar_kelurahan_budi.png" }, + { key: "ktp/kk", value: "kk_budi.png" }, + { key: "foto lokasi", value: "foto_lokasi_budi.png" } ] ], - error: "syaratDokumen harus berupa array" + error: "Syarat Dokumen harus berupa array" } ), }), detail: { summary: "Buat Pengajuan Pelayanan Surat", description: `tool untuk membuat pengajuan pelayanan surat dengan syarat dokumen serta data text sesuai kategori pelayanan surat yang dipilih`, - tags: ["mcp"] } }) .post("/detail-data", async ({ body }) => { @@ -698,7 +709,6 @@ const PelayananRoute = new Elysia({ dataText: dataTextFix, } - console.log('detail data syarat==', dataSyaratFix) return datafix @@ -778,7 +788,6 @@ const PelayananRoute = new Elysia({ .post("/update", async ({ body }) => { const { nomerPengajuan, syaratDokumen, dataText } = body let dataUpdate = [] - console.log(body) const pengajuan = await prisma.pelayananAjuan.findFirst({ where: { @@ -787,18 +796,15 @@ const PelayananRoute = new Elysia({ }) if (!pengajuan) { - console.log("data pengajuan surat tidak ditemukan") return { success: false, message: 'data pengajuan surat tidak ditemukan' } } if (pengajuan.status != "ditolak" && pengajuan.status != "antrian") { - console.log("pengajuan surat tidak dapat diupdate karena status " + pengajuan.status) return { success: false, message: 'pengajuan surat tidak dapat diupdate karena status ' + pengajuan.status } } if (dataText && dataText.length > 0) { - console.log("dataText") for (const item of dataText) { dataUpdate.push(item.jenis) const hasil = await prisma.dataTextPelayanan.findFirst({ @@ -842,10 +848,8 @@ const PelayananRoute = new Elysia({ if (syaratDokumen && syaratDokumen.length > 0) { - console.log("syaratDokumen") for (const item of syaratDokumen) { const pilih = syarat?.find((cat) => cat.desc.toLowerCase() == item.jenis.toLowerCase() || cat.name.toLowerCase() == item.jenis.toLowerCase())?.name; - console.log(syarat, pilih) dataUpdate.push(pilih) const hasil = await prisma.syaratDokumenPelayanan.findFirst({ @@ -854,7 +858,6 @@ const PelayananRoute = new Elysia({ jenis: pilih, } }) - console.log(hasil, item) if (hasil && hasil.id) { const upd = await prisma.syaratDokumenPelayanan.upsert({ @@ -898,7 +901,6 @@ const PelayananRoute = new Elysia({ } }) - console.log("pengajuan surat sudah diperbarui") return { success: true, message: 'pengajuan surat sudah diperbarui' }