dress/resources/js/pages/admin/master/user/create.tsx

473 lines
24 KiB
TypeScript

import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Field, FieldError } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover';
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxItem,
ComboboxList,
ComboboxValue,
useComboboxAnchor,
} from '@/components/ui/combobox';
import { Textarea } from '@/components/ui/textarea';
import userRoutes from '@/routes/user';
import { Head, Link, useForm } from '@inertiajs/react';
import { ArrowLeft, Loader, Save } from 'lucide-react';
import React from 'react';
import { NumericFormat } from 'react-number-format';
import { toast } from 'sonner';
export default function UserCreate({ roles }: { roles: any[] }) {
const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
const { data, setData, post, processing, errors } = useForm({
username: '',
email: '',
nik: '',
full_name: '',
phone_number: '',
address: '',
birth_place: '',
birth_date: '',
base_salary: 0,
roles: [] as string[],
});
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
post(userRoutes.store().url, {
onSuccess: (response: any) => {
const flash = response.props.flash;
if (flash?.error) {
toast.error(flash.error);
} else if (flash?.success) {
toast.success(flash.success);
}
},
});
};
const anchor = useComboboxAnchor();
return (
<div className="flex flex-col gap-6 p-6">
<Head title="Tambah Pegawai" />
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">
Tambah Pegawai
</h1>
</div>
<Link href={userRoutes.index().url}>
<Button variant="outline" className="gap-2">
<ArrowLeft className="size-4" />
Kembali
</Button>
</Link>
</div>
<form onSubmit={onSubmit} className="space-y-6">
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
<div className="space-y-6 lg:col-span-2">
<Card className="overflow-hidden border-none bg-card/50 shadow-lg backdrop-blur-sm">
<CardHeader className="border-b">
<CardTitle>Informasi Profil</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<Field>
<Label htmlFor="full_name" required>
Nama Lengkap
</Label>
<Input
id="full_name"
name="full_name"
value={data.full_name}
onChange={(e) =>
setData(
'full_name',
e.target.value,
)
}
autoComplete="off"
placeholder="Contoh: John Doe"
/>
<FieldError
error={errors.full_name}
label="Nama Lengkap"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="nik" required>
NIK
</Label>
<Input
id="nik"
name="nik"
value={data.nik}
onChange={(e) =>
setData('nik', e.target.value)
}
autoComplete="off"
placeholder="Contoh: 3213051307900001"
maxLength={16}
/>
<FieldError
error={errors.nik}
label="NIK"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="phone_number" required>
Nomor Telepon
</Label>
<Input
id="phone_number"
name="phone_number"
value={data.phone_number}
onChange={(e) =>
setData(
'phone_number',
e.target.value,
)
}
autoComplete="off"
placeholder="Contoh: 08123456789"
/>
<FieldError
error={errors.phone_number}
label="Nomor Telepon"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="base_salary" required>
Gaji Pokok
</Label>
<NumericFormat
id="base_salary"
customInput={Input}
thousandSeparator="."
decimalSeparator=","
prefix="Rp "
value={data.base_salary}
onValueChange={(values) => {
setData(
'base_salary',
values.floatValue || 0,
);
}}
placeholder="Rp 0"
autoComplete="off"
/>
<FieldError
error={errors.base_salary}
label="Gaji Pokok"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="birth_place" required>
Tempat Lahir
</Label>
<Input
id="birth_place"
name="birth_place"
value={data.birth_place}
onChange={(e) =>
setData(
'birth_place',
e.target.value,
)
}
autoComplete="off"
placeholder="Contoh: Jakarta"
/>
<FieldError
error={errors.birth_place}
label="Tempat Lahir"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="birth_date" required>
Tanggal Lahir
</Label>
<Popover
open={isCalendarOpen}
onOpenChange={setIsCalendarOpen}
>
<PopoverTrigger asChild>
<Button
variant="outline"
id="birth_date"
className="w-full justify-start font-normal"
>
{data.birth_date ? (
new Intl.DateTimeFormat(
'id-ID',
{
day: 'numeric',
month: 'long',
year: 'numeric',
},
).format(
new Date(
data.birth_date,
),
)
) : (
<span className="text-muted-foreground">
Pilih Tanggal
</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent
className="w-auto overflow-hidden p-0"
align="start"
>
<Calendar
mode="single"
selected={
data.birth_date
? new Date(
data.birth_date,
)
: undefined
}
defaultMonth={
data.birth_date
? new Date(
data.birth_date,
)
: new Date(
2000,
0,
1,
)
}
captionLayout="dropdown"
onSelect={(
selectedDate:
| Date
| undefined,
) => {
if (selectedDate) {
setData(
'birth_date',
selectedDate.getFullYear() +
'-' +
String(
selectedDate.getMonth() +
1,
).padStart(
2,
'0',
) +
'-' +
String(
selectedDate.getDate(),
).padStart(
2,
'0',
),
);
} else {
setData(
'birth_date',
'',
);
}
setIsCalendarOpen(
false,
);
}}
/>
</PopoverContent>
</Popover>
<FieldError
error={errors.birth_date}
label="Tanggal Lahir"
className="text-xs"
/>
</Field>
</div>
<Field>
<Label htmlFor="address" required>
Alamat
</Label>
<Textarea
id="address"
name="address"
value={data.address}
onChange={(e) =>
setData('address', e.target.value)
}
placeholder="Contoh: Kp. Bakan Sampeu"
/>
<FieldError
error={errors.address}
label="Alamat"
className="text-xs"
/>
</Field>
</CardContent>
</Card>
</div>
<div className="space-y-6">
<Card className="overflow-hidden border-none bg-card/50 shadow-lg backdrop-blur-sm">
<CardHeader className="border-b">
<CardTitle>Kredensial Akun</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<Field>
<Label htmlFor="email" required>
Alamat Surel
</Label>
<Input
id="email"
name="email"
type="email"
value={data.email}
onChange={(e) =>
setData('email', e.target.value)
}
autoComplete="off"
placeholder="Contoh: john@example.com"
/>
<FieldError
error={errors.email}
label="Alamat Surel"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="username" required>
Nama Pengguna
</Label>
<Input
id="username"
name="username"
value={data.username}
onChange={(e) =>
setData('username', e.target.value)
}
autoComplete="off"
placeholder="Contoh: johndoe"
/>
<FieldError
error={errors.username}
label="Nama Pengguna"
className="text-xs"
/>
</Field>
<Field>
<Label htmlFor="roles" required>
Peran
</Label>
<Combobox
multiple
autoHighlight
items={roles.map((r) => r.name)}
value={data.roles}
onValueChange={(val) =>
setData('roles', val)
}
>
<ComboboxChips
ref={anchor}
className="w-full"
>
<ComboboxValue>
{(values) => (
<React.Fragment>
{values.map(
(value: string) => (
<ComboboxChip
key={value}
value={value}
>
{value}
</ComboboxChip>
),
)}
<ComboboxChipsInput placeholder="Pilih Peran" />
</React.Fragment>
)}
</ComboboxValue>
</ComboboxChips>
<ComboboxContent anchor={anchor}>
<ComboboxEmpty>
Peran tidak ditemukan
</ComboboxEmpty>
<ComboboxList>
{(item: string) => (
<ComboboxItem
key={item}
value={item}
>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<FieldError
error={errors.roles}
label="Peran"
className="text-xs"
/>
</Field>
</CardContent>
</Card>
</div>
</div>
<Button type="submit" disabled={processing}>
{processing ? (
<Loader className="size-4 animate-spin" />
) : (
<Save className="size-4" />
)}
{processing ? 'Menyimpan...' : 'Simpan'}
</Button>
</form>
</div>
);
}
UserCreate.layout = {
breadcrumbs: [
{
title: 'Master',
},
],
};