Files
GSB-Construction/Modules/UserManagement/resources/js/Pages/Users/ChangePassword.tsx

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>
);
}