skl/resources/js/components/modals/add-perusahaan-modal.tsx

813 lines
34 KiB
TypeScript

import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import Select from "react-select";
import { useState } from "react";
import { Checkbox } from "@/components/ui/checkbox";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { format } from "date-fns";
import { cn } from "@/lib/utils";
import {
Calendar as CalendarIcon,
FileText,
Hotel,
LocateFixed,
MapPinned,
UsersRound,
Verified,
VerifiedIcon,
} from "lucide-react";
import { Separator } from "../ui/separator";
import { Textarea } from "../ui/textarea";
import {
JenisDokIL,
JenisKegiatan,
Verifikator,
Kabupaten,
Kecamatan,
Kelurahan,
Perusahaan,
Kawasan,
} from "@/types/perusahaan";
import { useForm, usePage } from "@inertiajs/react";
import { useToast } from "@/hooks/use-toast";
interface FormDataType {
NomorInduk: string;
JenisKegiatanId: string;
NamaPerusahaan: string;
Alamat: string;
KelurahanId: string;
KodePos: string;
Telepon: string;
Fax: string;
Email: string;
Lintang: string;
Bujur: string;
CPNama: string;
CPTelepon: string;
JenisDokILId: string;
VerifikatorId: string;
IsPublish: boolean;
ILNomor: string;
ILTanggal: string;
ILDokumen: File | null;
ReportLocked: true;
PerusahaanId: string;
}
// interface ExistingPerusahaan {
// NamaPerusahaan: string;
// PerusahaanId: string;
// }
interface ExistingInduk {
NomorInduk: string;
}
interface AddPerusahaanModalProps {
open: boolean;
onClose: () => void;
onSuccess: () => void;
jenisKegiatan: JenisKegiatan[];
jenisDokIL: JenisDokIL[];
verifikator: Verifikator[];
kabupaten: Kabupaten[];
kecamatan: Kecamatan[];
kelurahan: Kelurahan[];
perusahaan: Perusahaan[];
// kawasan: Kawasan[];
// existingPerusahaan: ExistingPerusahaan[];
// existingInduk: ExistingInduk[];
}
export function AddPerusahaanModal({
open,
onClose,
onSuccess,
jenisKegiatan,
jenisDokIL,
verifikator,
kabupaten,
kecamatan,
kelurahan,
perusahaan,
}: // existingPerusahaan,
// existingInduk,
// kawasan,
AddPerusahaanModalProps) {
const { toast } = useToast();
const [loading, setLoading] = useState(false);
const [date, setDate] = useState<Date>();
const { data, setData, post, reset } = useForm({
NomorInduk: "",
PerusahaanId: "",
JenisKegiatanId: "",
NamaPerusahaan: "",
Alamat: "",
KelurahanId: "",
KodePos: "",
Telepon: "",
Fax: "",
Email: "",
Lintang: "",
Bujur: "",
CPNama: "",
CPTelepon: "",
JenisDokILId: "",
VerifikatorId: "",
IsPublish: true,
ILDokumen: null as File | null,
ILNomor: "",
ILTanggal: "",
ReportLocked: true,
});
const [selectedKabupaten, setSelectedKabupaten] = useState<{
value: number;
label: string;
} | null>(null);
const [selectedKecamatan, setSelectedKecamatan] = useState<{
value: number;
label: string;
} | null>(null);
const [selectedKelurahan, setSelectedKelurahan] = useState<{
value: number;
label: string;
} | null>(null);
const [selectedPerusahaan, setSelectedPerusahaan] = useState<{
value: number;
label: string;
} | null>(null);
const jenisKegiatanOptions = jenisKegiatan.map((jk) => ({
value: jk.JenisKegiatanId,
label: jk.NamaJenisKegiatan,
}));
const jenisDokILOptions = jenisDokIL.map((jdi) => ({
value: jdi.JenisDokILId,
label: jdi.NamaJenisDokIL,
}));
const verifikatorOptions = verifikator.map((v) => ({
value: v.VerifikatorId,
label: v.NamaUnitKerja,
}));
const kabupatenOptions = kabupaten.map((k) => ({
value: k.KabupatenId,
label: k.NamaKabupaten,
}));
const perusahaanOptions = perusahaan.map((per) => ({
value: per.PerusahaanId,
label: per.NamaPerusahaan,
}));
const kecamatanOptions = kecamatan
.filter(
(kec) =>
selectedKabupaten && kec.KabupatenId === selectedKabupaten.value
)
.map((kec) => ({
value: kec.KecamatanId,
label: kec.NamaKecamatan,
}));
const kelurahanOptions = kelurahan
.filter(
(kel) =>
selectedKecamatan && kel.KecamatanId === selectedKecamatan.value
)
.map((kel) => ({
value: kel.KelurahanId,
label: kel.NamaKelurahan,
}));
const [showAlert, setShowAlert] = useState(false);
const [errors, setErrors] = useState<Record<string, string>>({});
const validateForm = () => {
const newErrors: Record<string, string> = {};
// const titleExists = existingPerusahaan.some(
// (perus) =>
// perus.PerusahaanId.toLowerCase() ===
// data.PerusahaanId.toLowerCase()
// );
// const indukExists = existingInduk.some(
// (induk) =>
// induk.NomorInduk.toLowerCase() === data.NomorInduk.toLowerCase()
// );
// if (indukExists) {
// setShowAlert(true);
// newErrors.NomorInduk = "Nomor Induk sudah ada";
// // Auto-hide alert after 5 seconds
// setTimeout(() => setShowAlert(false), 5000);
// }
// if (titleExists) {
// setShowAlert(true);
// newErrors.NamaPerusahaan = "Nama Perusahaan sudah ada";
// // Auto-hide alert after 5 seconds
// setTimeout(() => setShowAlert(false), 5000);
// }
// if (!data.PerusahaanId) {
// newErrors.PerusahaanId = "Perusahaan harus diisi";
// }
if (!data.JenisKegiatanId) {
newErrors.JenisKegiatanId = "Jenis Kegiatan harus dipilih";
}
if (!data.VerifikatorId) {
newErrors.VerifikatorId = "Admin harus dipilih";
}
if (!data.Email) {
newErrors.Email = "Email harus diisi";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) {
toast({
title: "Validasi Gagal",
description: "Silakan periksa kembali form anda",
variant: "destructive",
});
return;
}
setLoading(true);
const formData = new FormData();
formData.append("NomorInduk", data.NomorInduk);
formData.append("JenisKegiatanId", data.JenisKegiatanId);
formData.append("VerifikatorId", data.VerifikatorId);
formData.append("KelurahanId", data.KelurahanId);
formData.append("NamaPerusahaan", data.NamaPerusahaan);
formData.append("Alamat", data.Alamat);
formData.append("KodePos", data.KodePos);
formData.append("Telepon", data.Telepon);
formData.append("Fax", data.Fax);
formData.append("Email", data.Email);
formData.append("Lintang", data.Lintang);
formData.append("Bujur", data.Bujur);
formData.append("CPNama", data.CPNama);
formData.append("CPTelepon", data.CPTelepon);
formData.append("JenisDokILId", data.JenisDokILId);
formData.append("IsPublish", data.IsPublish.toString());
formData.append("ILNomor", data.ILNomor);
formData.append("ILTanggal", data.ILTanggal);
formData.append("ReportLocked", data.ReportLocked.toString());
if (data.ILDokumen) {
formData.append("ILDokumen", data.ILDokumen);
}
post("/admin/perusahaan", {
data: formData,
forceFormData: true,
onSuccess: (response) => {
toast({
title: "Berhasil",
description: "Perusahaan berhasil ditambahkan",
variant: "default",
});
reset();
onSuccess();
onClose();
},
onError: (error) => {
console.error("Error:", error);
toast({
title: "Gagal",
description:
"Terjadi kesalahan saat menambahkan perusahaan",
variant: "destructive",
});
},
});
};
return (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Tambah Perusahaan Baru</DialogTitle>
<DialogDescription>
Masukkan informasi perusahaan yang akan ditambahkan ke
dalam sistem.
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="flex flex-row gap-6">
{/* Sisi Kiri */}
<div className="w-1/2">
<div className="space-y-4">
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<Hotel size={16} />
<h3 className="text-sm ">
Data Perusahaan
</h3>
</div>
<div className="space-y-2">
<Label htmlFor="NomorInduk">
Nomor Induk
</Label>
<Input
id="NomorInduk"
value={data.NomorInduk}
onChange={(e) =>
setData({
...data,
NomorInduk: e.target.value,
})
}
/>
{errors.NomorInduk && (
<p className="text-red-500 text-sm">
{errors.NomorInduk}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="NamaPerusahaan">
Nama Perusahaan *
</Label>
<Input
id="NamaPerusahaan"
required
value={data.NamaPerusahaan}
onChange={(e) =>
setData({
...data,
NamaPerusahaan: e.target.value,
})
}
/>
{errors.PerusahaanId && (
<p className="text-red-500 text-sm">
{errors.PerusahaanId}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="NamaPerusahaan">
Jenis Kegiatan *
</Label>
<Select
id="JenisKegiatanId"
options={jenisKegiatanOptions}
required
placeholder="Pilih Jenis Kegiatan"
onChange={(option) =>
setData({
...data,
JenisKegiatanId:
option?.value?.toString() ||
"",
})
}
/>
{errors.JenisKegiatanId && (
<p className="text-red-500 text-sm">
{errors.JenisKegiatanId}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="NamaUnitKerja">
Admin *
</Label>
<Select
id="VerifikatorId"
options={verifikatorOptions}
required
placeholder="Pilih Admin"
onChange={(option) =>
setData({
...data,
VerifikatorId:
option?.value?.toString() ||
"",
})
}
/>
{errors.VerifikatorId && (
<p className="text-red-500 text-sm">
{errors.VerifikatorId}
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="PerusahaanId">
Pengelola Kawasan
</Label>
<Select
id="PerusahaanId"
options={perusahaanOptions}
placeholder="Pilih Pengelola Kawasan"
onChange={(option) =>
setData({
...data,
NamaPerusahaan:
option?.value?.toString() ||
"",
})
}
/>
</div>
<Separator />
{/* Kontak Person */}
<div className="space-y-4">
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<UsersRound size={16} />
<h3 className="text-sm ">
Kontak Person
</h3>
</div>
<div className="space-y-2">
<Label htmlFor="CPNama">Nama</Label>
<Input
id="CPNama"
value={data.CPNama}
onChange={(e) =>
setData({
...data,
CPNama: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="CPTelepon">
Telepon
</Label>
<Input
id="CPTelepon"
value={data.CPTelepon}
onChange={(e) =>
setData({
...data,
CPTelepon: e.target.value,
})
}
/>
</div>
</div>
<Separator className="space-y-4" />
{/* Dokumen Izin */}
<div className="space-y-4">
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<FileText size={16} />
<h3 className="text-sm ">
Dokumen Izin
</h3>
</div>
<div className="space-y-2">
<Label htmlFor="ILNomor">Nomor</Label>
<Input
id="ILNomor"
value={data.ILNomor}
onChange={(e) =>
setData({
...data,
ILNomor: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="ILTanggal">
Tanggal
</Label>
<Input
id="ILTanggal"
type="date"
value={data.ILTanggal}
onChange={(e) =>
setData({
...data,
ILTanggal: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="JenisDokILId">
Jenis Dokumen
</Label>
<Select
id="JenisDokILId"
options={jenisDokILOptions}
placeholder="Pilih Jenis Dokumen"
onChange={(option) =>
setData({
...data,
JenisDokILId:
option?.value?.toString() ||
"",
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="ILDokumen">
Unggah Dokumen
</Label>
<Input
id="ILDokumen"
type="file"
accept="pdf"
onChange={(e) =>
setData({
...data,
ILDokumen: e.target.files
? e.target.files[0]
: null,
})
}
/>
</div>
</div>
</div>
</div>
{/* Sisi Kanan */}
<div className="w-1/2">
<div className="space-y-4">
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<MapPinned size={16} />
<h3 className="text-sm ">
Alamat Perusahaan
</h3>
</div>
<div className="space-y-2">
<Label htmlFor="KelurahanId">
Kabupaten/Kota *
</Label>
<Select
id="KabupatenId"
options={kabupatenOptions}
value={selectedKabupaten}
onChange={(value) => {
setSelectedKabupaten(value);
setSelectedKecamatan(null);
setSelectedKelurahan(null);
}}
placeholder="Pilih Kabupaten/Kota"
isSearchable
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="KelurahanId">
Kecamatan *
</Label>
<Select
id="KecamatanId"
options={kecamatanOptions}
value={selectedKecamatan}
onChange={(value) => {
setSelectedKecamatan(value);
setSelectedKelurahan(null);
}}
placeholder="Pilih Kecamatan"
isSearchable
isDisabled={!selectedKabupaten}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="KelurahanId">
Kelurahan *
</Label>
<Select
id="KelurahanId"
options={kelurahanOptions}
value={selectedKelurahan}
onChange={(value) => {
setSelectedKelurahan(value);
setData({
...data,
KelurahanId:
value?.value?.toString() ||
"",
});
}}
placeholder="Pilih Kelurahan"
isSearchable
isDisabled={!selectedKecamatan}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="Alamat">Alamat</Label>
<Textarea
id="Alamat"
value={data.Alamat}
onChange={(e) =>
setData({
...data,
Alamat: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="KodePos">Kode Pos</Label>
<Input
id="KodePos"
value={data.KodePos}
onChange={(e) =>
setData({
...data,
KodePos: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="Telepon">Telepon</Label>
<Input
id="Telepon"
value={data.Telepon}
onChange={(e) =>
setData({
...data,
Telepon: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="Fax">Fax</Label>
<Input
id="Fax"
value={data.Fax}
onChange={(e) =>
setData({
...data,
Fax: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="Email">Email *</Label>
<Input
id="Email"
type="email"
required
value={data.Email}
onChange={(e) =>
setData({
...data,
Email: e.target.value,
})
}
/>
</div>
<Separator className="space-y-4" />
{/* Kontak dan Koordinat */}
<div className="space-y-4">
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<LocateFixed size={16} />
<h3 className="text-sm ">Koordinat</h3>
</div>
<div className="space-y-2">
<Label htmlFor="Lintang">Lintang</Label>
<Input
id="Lintang"
value={data.Lintang}
onChange={(e) =>
setData({
...data,
Lintang: e.target.value,
})
}
/>
</div>
<div className="space-y-2">
<Label htmlFor="Bujur">Bujur</Label>
<Input
id="Bujur"
value={data.Bujur}
onChange={(e) =>
setData({
...data,
Bujur: e.target.value,
})
}
/>
</div>
</div>
<Separator className="space-y-4" />
<div className="flex flex-row bg-green-200 px-2 py-1 rounded w-fit gap-2 items-center">
<VerifiedIcon size={16} />
<h3 className="text-sm">Status</h3>
</div>
<div className="flex space-x-4">
<div className="flex items-center space-x-2">
<Checkbox
id="IsPublishActive"
checked={data.IsPublish === true}
onCheckedChange={() =>
setData({
...data,
IsPublish: true,
})
}
/>
<Label htmlFor="IsPublishActive">
Aktif
</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="IsPublishInactive"
checked={data.IsPublish === false}
onCheckedChange={() =>
setData({
...data,
IsPublish: false,
})
}
/>
<Label htmlFor="IsPublishInactive">
Non Aktif
</Label>
</div>
</div>
</div>
</div>
</div>
<Separator className="space-y-4" />
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={onClose}
disabled={loading}
>
Batal
</Button>
<Button type="submit" disabled={loading}>
{loading ? "Menyimpan..." : "Simpan"}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}