mega-plant/components/auth/PasswordField.tsx
Dave 2594dead84 feat: add user access and improve plant dashboard
Add PocketBase login, first-sign-in password changes, account settings,
and user activation, reactivation and deletion with self-removal guards.
Protect application pages and APIs and keep private pages out of PWA
caches.

Resolve plant locations from site assignments and improve map controls,
profit chart views, navigation and mobile table layouts.

Validation: production build and TypeScript passed; 28 unit tests passed.
Backend access integration tests and mobile verification are documented.
2026-10-06 04:02:08 +02:00

26 lines
1.5 KiB
TypeScript

"use client";
import { useState } from "react";
import { Eye, EyeOff } from "lucide-react";
export const inputClass = "w-full min-h-12 rounded-xl border border-gray-200 bg-white px-3.5 text-base text-[#003D5B] outline-none transition focus:border-[#30638E] focus:ring-3 focus:ring-[#30638E]/10 dark:border-border dark:bg-surface-muted dark:text-white";
export function PasswordField({ name, label, autoComplete, minLength, hint }: {
name: string; label: string; autoComplete: string; minLength?: number; hint?: string;
}) {
const [visible, setVisible] = useState(false);
return (
<div>
<label htmlFor={name} className="mb-2 block text-sm font-medium">{label}</label>
<div className="relative">
<input id={name} name={name} type={visible ? "text" : "password"} autoComplete={autoComplete}
required minLength={minLength} className={`${inputClass} pr-14`} aria-describedby={hint ? `${name}-hint` : undefined} />
<button type="button" onClick={() => setVisible(!visible)} aria-label={`${visible ? "Hide" : "Show"} ${label.toLowerCase()}`}
className="absolute right-1 top-0.5 grid h-11 w-11 place-items-center rounded-lg text-gray-500 hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-[#30638E] dark:hover:bg-white/5">
{visible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</div>
{hint && <p id={`${name}-hint`} className="mt-2 text-xs leading-relaxed text-gray-500 dark:text-gray-400">{hint}</p>}
</div>
);
}