145 lines
7.7 KiB
TypeScript
145 lines
7.7 KiB
TypeScript
import { FormEventHandler } from 'react';
|
|
import InputError from '@/Components/InputError';
|
|
import { Input } from '@/Components/ui/input';
|
|
import { Label } from '@/Components/ui/label';
|
|
import { Button } from '@/Components/ui/button';
|
|
import { Transition } from '@headlessui/react';
|
|
import { Link, useForm, usePage } from '@inertiajs/react';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/Components/ui/card';
|
|
import { Lock, User as UserIcon, CheckCircle2, Shield } from 'lucide-react';
|
|
import { PageProps } from '@/types';
|
|
|
|
export default function UpdateProfileInformation({
|
|
mustVerifyEmail,
|
|
status,
|
|
className = '',
|
|
}: {
|
|
mustVerifyEmail: boolean;
|
|
status?: string;
|
|
className?: string;
|
|
}) {
|
|
const user = usePage<PageProps>().props.auth.user;
|
|
|
|
const { data, setData, patch, errors, processing, recentlySuccessful } =
|
|
useForm({
|
|
name: user.name,
|
|
email: user.email,
|
|
});
|
|
|
|
const submit: FormEventHandler = (e) => {
|
|
e.preventDefault();
|
|
patch(route('profile.update'));
|
|
};
|
|
|
|
return (
|
|
<Card className={`border-slate-200/80 dark:border-slate-800 shadow-xs bg-white dark:bg-slate-900 overflow-hidden ${className}`}>
|
|
<CardHeader className="bg-slate-50/70 dark:bg-slate-800/50 border-b border-slate-100 dark:border-slate-800/80 py-4 px-6">
|
|
<CardTitle className="text-base font-bold text-slate-800 dark:text-slate-100 flex items-center gap-2">
|
|
<div className="p-1.5 rounded-lg bg-emerald-50 dark:bg-emerald-950/50 text-emerald-600 dark:text-emerald-400">
|
|
<UserIcon className="h-4 w-4" />
|
|
</div>
|
|
Profile Information
|
|
</CardTitle>
|
|
<CardDescription className="text-xs text-slate-500 dark:text-slate-400">
|
|
Update your display name across all modules and audit activity logs.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="p-6">
|
|
<form onSubmit={submit} className="space-y-5">
|
|
{/* Text Fields */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div className="space-y-1.5">
|
|
<Label htmlFor="name" className="text-xs font-bold text-slate-700 dark:text-slate-300">
|
|
Full Name
|
|
</Label>
|
|
<Input
|
|
id="name"
|
|
className="bg-white dark:bg-slate-950 text-xs border-slate-200 dark:border-slate-800 focus-visible:ring-emerald-500 focus-visible:border-emerald-500 h-9 font-medium"
|
|
value={data.name}
|
|
onChange={(e) => setData('name', e.target.value)}
|
|
required
|
|
autoComplete="name"
|
|
placeholder="Your full name"
|
|
/>
|
|
<InputError className="mt-1" message={errors.name} />
|
|
</div>
|
|
|
|
<div className="space-y-1.5">
|
|
<div className="flex items-center justify-between">
|
|
<Label htmlFor="email" className="text-xs font-bold text-slate-700 dark:text-slate-300">
|
|
Email Address
|
|
</Label>
|
|
<span className="text-[10px] text-slate-400 dark:text-slate-500 font-semibold flex items-center gap-1 bg-slate-100 dark:bg-slate-800 px-1.5 py-0.5 rounded">
|
|
<Lock className="h-2.5 w-2.5" /> Locked
|
|
</span>
|
|
</div>
|
|
<Input
|
|
id="email"
|
|
type="email"
|
|
className="bg-slate-50 dark:bg-slate-950/50 text-xs border-slate-200 dark:border-slate-800 text-slate-500 dark:text-slate-400 cursor-not-allowed h-9 select-none font-medium"
|
|
value={data.email}
|
|
disabled
|
|
readOnly
|
|
autoComplete="username"
|
|
/>
|
|
<p className="text-[11px] text-slate-400 dark:text-slate-500 mt-1">
|
|
Primary login email is managed by your system administrator.
|
|
</p>
|
|
<InputError className="mt-1" message={errors.email} />
|
|
</div>
|
|
</div>
|
|
|
|
{mustVerifyEmail && user.email_verified_at === null && (
|
|
<div className="bg-amber-50/70 dark:bg-amber-950/30 border border-amber-200 dark:border-amber-900/50 p-3 rounded-lg flex items-start gap-2.5">
|
|
<Shield className="h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 shrink-0" />
|
|
<div className="text-xs text-amber-800 dark:text-amber-300">
|
|
<p>
|
|
Your email address is unverified.
|
|
<Link
|
|
href={route('verification.send')}
|
|
method="post"
|
|
as="button"
|
|
className="ml-1.5 font-semibold text-amber-700 dark:text-amber-400 underline hover:text-amber-900 focus:outline-none"
|
|
>
|
|
Click here to re-send verification link.
|
|
</Link>
|
|
</p>
|
|
{status === 'verification-link-sent' && (
|
|
<div className="mt-1.5 font-semibold text-emerald-600 dark:text-emerald-400 flex items-center gap-1">
|
|
<CheckCircle2 className="h-3.5 w-3.5" /> A new verification link has been sent to your email.
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center justify-between pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
|
<Button
|
|
type="submit"
|
|
disabled={processing}
|
|
className="bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-semibold h-9 px-4 shadow-2xs transition-colors"
|
|
>
|
|
Save Changes
|
|
</Button>
|
|
|
|
<Transition
|
|
show={recentlySuccessful}
|
|
enter="transition ease-in-out duration-300"
|
|
enterFrom="opacity-0 translate-x-2"
|
|
enterTo="opacity-100 translate-x-0"
|
|
leave="transition ease-in-out duration-300"
|
|
leaveFrom="opacity-100"
|
|
leaveTo="opacity-0"
|
|
>
|
|
<div className="flex items-center gap-1.5 text-emerald-600 dark:text-emerald-400 text-xs font-semibold">
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
<span>Profile updated successfully.</span>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|