geraete/app/(app)/users/ChangePasswordModal.tsx
2025-11-26 15:00:05 +01:00

193 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import Modal from '@/components/ui/Modal';
import { CheckIcon } from '@heroicons/react/24/outline';
import type { UserWithAvatar } from './types';
import type { PasswordChecks } from './passwordUtils';
type ChangePasswordModalProps = {
open: boolean;
user: UserWithAvatar;
newPassword: string;
newPasswordConfirm: string;
pwChecks: PasswordChecks;
pwError: string | null;
saving: boolean;
canSubmitPw: boolean;
onNewPasswordChange: (value: string) => void;
onNewPasswordConfirmChange: (value: string) => void;
onClose: () => void;
onSubmit: () => void;
};
export default function ChangePasswordModal({
open,
user,
newPassword,
newPasswordConfirm,
pwChecks,
pwError,
saving,
canSubmitPw,
onNewPasswordChange,
onNewPasswordConfirmChange,
onClose,
onSubmit,
}: ChangePasswordModalProps) {
if (!open) return null;
return (
<Modal
open={open}
onClose={onClose}
title="Passwort ändern"
tone="warning"
variant="centered"
size="md"
primaryAction={{
label: saving ? 'Speichere …' : 'Passwort setzen',
onClick: onSubmit,
variant: 'primary',
disabled: !canSubmitPw,
}}
secondaryAction={{
label: 'Abbrechen',
onClick: onClose,
variant: 'secondary',
}}
>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmit();
}}
className="space-y-3 text-sm"
>
<p className="text-xs text-gray-600 dark:text-gray-400">
Das neue Passwort gilt sofort für den Benutzer{' '}
<strong>{user.arbeitsname || user.nwkennung}</strong>.
</p>
<div>
<label className="block text-xs font-medium text-gray-700 dark:text-gray-300">
Neues Passwort *
</label>
<input
type="password"
required
minLength={12}
className="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2.5 py-1.5 text-sm text-gray-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
value={newPassword}
onChange={(e) => onNewPasswordChange(e.target.value)}
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 dark:text-gray-300">
Passwort bestätigen *
</label>
<input
type="password"
required
minLength={12}
className="mt-1 block w-full rounded-md border border-gray-300 bg-white px-2.5 py-1.5 text-sm text-gray-900 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
value={newPasswordConfirm}
onChange={(e) => onNewPasswordConfirmChange(e.target.value)}
/>
</div>
<div className="mt-2 rounded-md bg-gray-50 p-2 text-xs text-gray-700 dark:bg-gray-800 dark:text-gray-300">
<p className="font-medium mb-1">Sicherheitskriterien:</p>
<ul className="space-y-0.5">
<li
className={
(pwChecks.lengthOk
? 'text-green-700 dark:text-green-500'
: 'text-gray-500 dark:text-gray-400') +
' flex items-center gap-1.5'
}
>
{pwChecks.lengthOk ? (
<CheckIcon className="h-4 w-4 shrink-0" />
) : (
<span className="inline-block w-4 text-center"></span>
)}
<span>Mindestens 12 Zeichen</span>
</li>
<li
className={
(pwChecks.lowerOk
? 'text-green-700 dark:text-green-500'
: 'text-gray-500 dark:text-gray-400') +
' flex items-center gap-1.5'
}
>
{pwChecks.lowerOk ? (
<CheckIcon className="h-4 w-4 shrink-0" />
) : (
<span className="inline-block w-4 text-center"></span>
)}
<span>Mindestens ein Kleinbuchstabe (az)</span>
</li>
<li
className={
(pwChecks.upperOk
? 'text-green-700 dark:text-green-500'
: 'text-gray-500 dark:text-gray-400') +
' flex items-center gap-1.5'
}
>
{pwChecks.upperOk ? (
<CheckIcon className="h-4 w-4 shrink-0" />
) : (
<span className="inline-block w-4 text-center"></span>
)}
<span>Mindestens ein Großbuchstabe (AZ)</span>
</li>
<li
className={
(pwChecks.digitOk
? 'text-green-700 dark:text-green-500'
: 'text-gray-500 dark:text-gray-400') +
' flex items-center gap-1.5'
}
>
{pwChecks.digitOk ? (
<CheckIcon className="h-4 w-4 shrink-0" />
) : (
<span className="inline-block w-4 text-center"></span>
)}
<span>Mindestens eine Ziffer (09)</span>
</li>
<li
className={
(pwChecks.specialOk
? 'text-green-700 dark:text-green-500'
: 'text-gray-500 dark:text-gray-400') +
' flex items-center gap-1.5'
}
>
{pwChecks.specialOk ? (
<CheckIcon className="h-4 w-4 shrink-0" />
) : (
<span className="inline-block w-4 text-center"></span>
)}
<span>Mindestens ein Sonderzeichen (!, ?, #, )</span>
</li>
</ul>
</div>
{pwError && (
<p className="text-xs text-red-600 dark:text-red-400">
{pwError}
</p>
)}
</form>
</Modal>
);
}