132 lines
6.5 KiB
TypeScript
132 lines
6.5 KiB
TypeScript
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
|
|
import { Head, useForm, usePage } from '@inertiajs/react';
|
|
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 { KeyRound, ShieldCheck } from 'lucide-react';
|
|
import { FormEvent, useState } from 'react';
|
|
import { PageProps } from '@/types';
|
|
|
|
export default function ChangePassword() {
|
|
const { flash } = usePage<PageProps>().props;
|
|
const { data, setData, post, processing, errors } = useForm({
|
|
password: '',
|
|
password_confirmation: '',
|
|
});
|
|
|
|
const [strength, setStrength] = useState(0);
|
|
|
|
const handlePasswordChange = (val: string) => {
|
|
setData('password', val);
|
|
let score = 0;
|
|
if (val.length >= 8) score++;
|
|
if (/[A-Z]/.test(val)) score++;
|
|
if (/[0-9]/.test(val)) score++;
|
|
if (/[^A-Za-z0-9]/.test(val)) score++;
|
|
setStrength(score);
|
|
};
|
|
|
|
const strengthLabel = ['', 'Weak', 'Fair', 'Good', 'Strong'];
|
|
const strengthColor = ['', 'bg-red-500', 'bg-amber-400', 'bg-blue-500', 'bg-emerald-500'];
|
|
|
|
const handleSubmit = (e: FormEvent) => {
|
|
e.preventDefault();
|
|
post(route('password.change.update'));
|
|
};
|
|
|
|
return (
|
|
<AuthenticatedLayout
|
|
header={
|
|
<div className="flex items-center gap-3">
|
|
<KeyRound className="h-5 w-5 text-amber-500" />
|
|
<h2 className="text-xl font-semibold leading-tight text-gray-800">
|
|
Set Your New Password
|
|
</h2>
|
|
</div>
|
|
}
|
|
>
|
|
<Head title="Change Password" />
|
|
|
|
<div className="flex min-h-[60vh] items-center justify-center py-12">
|
|
<div className="w-full max-w-md px-4">
|
|
{/* Warning Banner */}
|
|
<div className="mb-6 flex items-start gap-3 rounded-lg border border-amber-200 bg-amber-50 p-4">
|
|
<ShieldCheck className="mt-0.5 h-5 w-5 shrink-0 text-amber-600" />
|
|
<div>
|
|
<p className="text-sm font-medium text-amber-800">Temporary Password Detected</p>
|
|
<p className="mt-1 text-xs text-amber-700">
|
|
Your account was set up with a temporary password. Please create a new secure password to continue.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg">Create New Password</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleSubmit} className="space-y-5">
|
|
<div>
|
|
<Label htmlFor="password">New Password</Label>
|
|
<Input
|
|
id="password"
|
|
type="password"
|
|
value={data.password}
|
|
onChange={(e) => handlePasswordChange(e.target.value)}
|
|
placeholder="Minimum 8 characters"
|
|
className="mt-1"
|
|
/>
|
|
{/* Strength bar */}
|
|
{data.password.length > 0 && (
|
|
<div className="mt-2 space-y-1">
|
|
<div className="flex gap-1">
|
|
{[1, 2, 3, 4].map((i) => (
|
|
<div
|
|
key={i}
|
|
className={`h-1.5 flex-1 rounded-full transition-all duration-300 ${
|
|
i <= strength ? strengthColor[strength] : 'bg-gray-200'
|
|
}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
<p className={`text-xs font-medium ${strength >= 3 ? 'text-emerald-600' : 'text-amber-600'}`}>
|
|
{strengthLabel[strength]} password
|
|
</p>
|
|
</div>
|
|
)}
|
|
{errors.password && <p className="mt-1 text-sm text-red-500">{errors.password}</p>}
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="password_confirmation">Confirm Password</Label>
|
|
<Input
|
|
id="password_confirmation"
|
|
type="password"
|
|
value={data.password_confirmation}
|
|
onChange={(e) => setData('password_confirmation', e.target.value)}
|
|
placeholder="Repeat your new password"
|
|
className="mt-1"
|
|
/>
|
|
{data.password_confirmation && data.password !== data.password_confirmation && (
|
|
<p className="mt-1 text-xs text-red-500">Passwords do not match</p>
|
|
)}
|
|
</div>
|
|
|
|
<Button
|
|
type="submit"
|
|
disabled={processing || strength < 2 || data.password !== data.password_confirmation}
|
|
className="w-full"
|
|
>
|
|
<KeyRound className="mr-2 h-4 w-4" />
|
|
{processing ? 'Saving...' : 'Set Password & Continue'}
|
|
</Button>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</AuthenticatedLayout>
|
|
);
|
|
}
|