- Translated UI elements to Indonesian for better localization. - Improved layout by introducing Card components for better visual structure. - Removed unnecessary imports and props related to passkeys and two-factor authentication. - Updated tests to cover new password update scenarios and validation rules. - Ensured proper redirection and error handling for unauthorized access to security settings. - Enhanced user experience by adding success flash messages on password updates.
173 lines
8.5 KiB
TypeScript
173 lines
8.5 KiB
TypeScript
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
|
|
import { DatePicker } from '@/components/date-picker';
|
|
import InputError from '@/components/input-error';
|
|
import { PhoneNumberInput } from '@/components/phone-number-input';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { edit } from '@/routes/profile';
|
|
import { Form, Head } from '@inertiajs/react';
|
|
import { useState } from 'react';
|
|
|
|
type UserData = {
|
|
id: number;
|
|
email: string;
|
|
username: string;
|
|
userProfile: {
|
|
full_name: string;
|
|
phone_number: string | null;
|
|
gender: string | null;
|
|
birth_date: string | null;
|
|
address: string | null;
|
|
} | null;
|
|
};
|
|
|
|
type Props = {
|
|
user: UserData;
|
|
mustVerifyEmail: boolean;
|
|
status?: string;
|
|
};
|
|
|
|
export default function Profile({ user }: Props) {
|
|
const [birthDate, setBirthDate] = useState<Date | undefined>(
|
|
user.userProfile?.birth_date ? new Date(user.userProfile.birth_date) : undefined
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Head title="Profil" />
|
|
|
|
<div className="flex h-full flex-1 flex-col gap-6 overflow-x-auto px-4 md:px-6">
|
|
<Form
|
|
{...ProfileController.update.form()}
|
|
options={{
|
|
preserveScroll: true,
|
|
}}
|
|
>
|
|
{({ processing, errors }) => (
|
|
<div className="grid gap-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Akun</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="email">
|
|
Email <span className="text-destructive">*</span>
|
|
</Label>
|
|
<Input
|
|
id="email"
|
|
name="email"
|
|
type="email"
|
|
placeholder="Masukkan email"
|
|
defaultValue={user.email}
|
|
/>
|
|
<InputError message={errors.email} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="username">
|
|
Username <span className="text-destructive">*</span>
|
|
</Label>
|
|
<Input
|
|
id="username"
|
|
name="username"
|
|
placeholder="Masukkan username"
|
|
defaultValue={user.username}
|
|
/>
|
|
<InputError message={errors.username} />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Profil</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="full_name">
|
|
Nama Lengkap <span className="text-destructive">*</span>
|
|
</Label>
|
|
<Input
|
|
id="full_name"
|
|
name="full_name"
|
|
placeholder="Masukkan nama lengkap"
|
|
defaultValue={user.userProfile?.full_name ?? ''}
|
|
/>
|
|
<InputError message={errors.full_name} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="phone_number">No. Telepon</Label>
|
|
<PhoneNumberInput
|
|
name="phone_number"
|
|
defaultValue={user.userProfile?.phone_number ?? ''}
|
|
/>
|
|
<InputError message={errors.phone_number} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label>Jenis Kelamin</Label>
|
|
<RadioGroup
|
|
name="gender"
|
|
defaultValue={user.userProfile?.gender ?? ''}
|
|
className="flex gap-4"
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="male" id="settings-gender-male" />
|
|
<Label htmlFor="settings-gender-male" className="font-normal">Laki-laki</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="female" id="settings-gender-female" />
|
|
<Label htmlFor="settings-gender-female" className="font-normal">Perempuan</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
<InputError message={errors.gender} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label>Tanggal Lahir</Label>
|
|
<DatePicker
|
|
name="birth_date"
|
|
value={birthDate}
|
|
onChange={setBirthDate}
|
|
placeholder="Pilih tanggal lahir"
|
|
/>
|
|
<InputError message={errors.birth_date} />
|
|
</div>
|
|
<div className="grid gap-2 md:col-span-2">
|
|
<Label htmlFor="address">Alamat</Label>
|
|
<Textarea
|
|
id="address"
|
|
name="address"
|
|
placeholder="Masukkan alamat"
|
|
rows={3}
|
|
defaultValue={user.userProfile?.address ?? ''}
|
|
/>
|
|
<InputError message={errors.address} />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="flex items-center gap-4">
|
|
<Button type="submit" disabled={processing}>
|
|
{processing ? 'Menyimpan...' : 'Simpan'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</Form>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
Profile.layout = {
|
|
breadcrumbs: [
|
|
{
|
|
title: 'Profil',
|
|
href: edit(),
|
|
},
|
|
],
|
|
};
|