feat: add base salary field to user profile management with validation and UI integration
This commit is contained in:
parent
6c21c66e12
commit
8e32df7307
@ -45,6 +45,7 @@ public function store(UserRequest $request): RedirectResponse
|
||||
'address' => $validated['address'],
|
||||
'birth_place' => $validated['birth_place'],
|
||||
'birth_date' => $validated['birth_date'],
|
||||
'base_salary' => $validated['base_salary'],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -77,6 +78,7 @@ public function update(UserRequest $request, User $user): RedirectResponse
|
||||
'address' => $validated['address'],
|
||||
'birth_place' => $validated['birth_place'],
|
||||
'birth_date' => $validated['birth_date'],
|
||||
'base_salary' => $validated['base_salary'],
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ public function rules(): array
|
||||
'address' => ['required', 'string'],
|
||||
'birth_place' => ['required', 'string', 'max:100'],
|
||||
'birth_date' => ['required', 'date'],
|
||||
'base_salary' => ['required', 'integer', 'min:0'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,13 @@ class UserProfile extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'base_salary' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
|
||||
@ -20,6 +20,7 @@ public function up(): void
|
||||
$table->text('address');
|
||||
$table->string('birth_place', 100);
|
||||
$table->date('birth_date');
|
||||
$table->unsignedInteger('base_salary')->default(0);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
|
||||
@ -26,6 +26,7 @@ public function run(): void
|
||||
'address' => 'Jl. Contoh No. 123',
|
||||
'birth_place' => 'Jakarta',
|
||||
'birth_date' => '1990-01-01',
|
||||
'base_salary' => 1500000,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
import { NumericFormat } from 'react-number-format';
|
||||
|
||||
export default function UserCreate() {
|
||||
const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
|
||||
@ -28,6 +29,7 @@ export default function UserCreate() {
|
||||
address: '',
|
||||
birth_place: '',
|
||||
birth_date: '',
|
||||
base_salary: 0,
|
||||
});
|
||||
|
||||
const onSubmit = (e: React.FormEvent) => {
|
||||
@ -62,20 +64,20 @@ export default function UserCreate() {
|
||||
<CardTitle>Informasi Profil</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<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'
|
||||
/>
|
||||
{errors.full_name && <p className="text-xs text-red-500">{errors.full_name}</p>}
|
||||
</Field>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<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'
|
||||
/>
|
||||
{errors.full_name && <p className="text-xs text-red-500">{errors.full_name}</p>}
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<Label htmlFor="nik" required>NIK</Label>
|
||||
<Input
|
||||
@ -103,6 +105,24 @@ export default function UserCreate() {
|
||||
{errors.phone_number && <p className="text-xs text-red-500">{errors.phone_number}</p>}
|
||||
</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'
|
||||
/>
|
||||
{errors.base_salary && <p className="text-xs text-red-500">{errors.base_salary}</p>}
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<Label htmlFor="birth_place" required>Tempat Lahir</Label>
|
||||
<Input
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
import { NumericFormat } from 'react-number-format';
|
||||
|
||||
export default function UserEdit({ user }: { user: any }) {
|
||||
const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
|
||||
@ -28,6 +29,7 @@ export default function UserEdit({ user }: { user: any }) {
|
||||
address: user.profile?.address || '',
|
||||
birth_place: user.profile?.birth_place || '',
|
||||
birth_date: user.profile?.birth_date || '',
|
||||
base_salary: user.profile?.base_salary || 0,
|
||||
_method: 'PATCH',
|
||||
});
|
||||
|
||||
@ -63,19 +65,6 @@ export default function UserEdit({ user }: { user: any }) {
|
||||
<CardTitle>Informasi Profil</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<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'
|
||||
/>
|
||||
{errors.full_name && <p className="text-xs text-red-500">{errors.full_name}</p>}
|
||||
</Field>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<Field>
|
||||
<Label htmlFor="nik" required>NIK</Label>
|
||||
@ -91,6 +80,19 @@ export default function UserEdit({ user }: { user: any }) {
|
||||
{errors.nik && <p className="text-xs text-red-500">{errors.nik}</p>}
|
||||
</Field>
|
||||
|
||||
<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'
|
||||
/>
|
||||
{errors.full_name && <p className="text-xs text-red-500">{errors.full_name}</p>}
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<Label htmlFor="phone_number" required>Nomor Telepon</Label>
|
||||
<Input
|
||||
@ -104,6 +106,24 @@ export default function UserEdit({ user }: { user: any }) {
|
||||
{errors.phone_number && <p className="text-xs text-red-500">{errors.phone_number}</p>}
|
||||
</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'
|
||||
/>
|
||||
{errors.base_salary && <p className="text-xs text-red-500">{errors.base_salary}</p>}
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<Label htmlFor="birth_place" required>Tempat Lahir</Label>
|
||||
<Input
|
||||
|
||||
Loading…
Reference in New Issue
Block a user