"use client"; import React from "react"; import { Check, Copy, Eye, EyeOff, KeyRound, Loader2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { adminResetUserPassword, ApiClientError, } from "@/lib/frontend/apiClient"; import { buildLoginUrl, LOGIN_REASONS } from "@/lib/frontend/authRedirect"; import { getDisplayedTemporaryPassword, hasTemporaryPassword, } from "@/lib/frontend/admin/users/userManagementUx"; import { notifySuccess, notifyError, notifyApiError, } from "@/lib/frontend/ui/toast"; function useCopySuccessTimeout(isActive, onReset) { React.useEffect(() => { if (!isActive) return undefined; const timer = window.setTimeout(() => onReset?.(), 1200); return () => window.clearTimeout(timer); }, [isActive, onReset]); } export default function UserTemporaryPasswordField({ user, temporaryPassword, onTemporaryPasswordChange, onPasswordReset, disabled = false, compact = false, }) { const [isVisible, setIsVisible] = React.useState(false); const [isResetting, setIsResetting] = React.useState(false); const [copySuccess, setCopySuccess] = React.useState(false); const hasTempPassword = hasTemporaryPassword(temporaryPassword); const isDisabled = Boolean(disabled || isResetting || !user?.id); useCopySuccessTimeout(copySuccess, () => setCopySuccess(false)); React.useEffect(() => { if (hasTempPassword) return; setIsVisible(false); setCopySuccess(false); }, [hasTempPassword]); const redirectToLoginExpired = React.useCallback(() => { const next = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}` : "/admin/users"; window.location.replace( buildLoginUrl({ reason: LOGIN_REASONS.EXPIRED, next }), ); }, []); const handleResetPassword = React.useCallback(async () => { if (!user?.id || isDisabled) return; setIsResetting(true); setCopySuccess(false); try { const result = await adminResetUserPassword(String(user.id)); const nextPassword = typeof result?.temporaryPassword === "string" ? result.temporaryPassword : ""; if (!nextPassword) { throw new Error("Missing temporaryPassword in reset response"); } onTemporaryPasswordChange?.(nextPassword); setIsVisible(false); notifySuccess({ title: "Temporäres Passwort gesetzt", description: `Für "${user.username}" wurde ein neues Startpasswort erstellt.`, }); onPasswordReset?.(); } catch (err) { if (err instanceof ApiClientError) { if (err.code === "AUTH_UNAUTHENTICATED") { notifyApiError(err); redirectToLoginExpired(); return; } if ( err.code === "VALIDATION_INVALID_FIELD" && err.details?.reason === "SELF_PASSWORD_RESET_FORBIDDEN" ) { notifyError({ title: "Nicht möglich", description: "Sie können Ihr eigenes Passwort hier nicht zurücksetzen.", }); return; } if (err.code === "USER_NOT_FOUND") { notifyError({ title: "Benutzer nicht gefunden.", description: "Der Benutzer existiert nicht (mehr). Bitte aktualisieren Sie die Liste.", }); return; } notifyApiError(err, { fallbackTitle: "Passwort konnte nicht zurückgesetzt werden.", fallbackDescription: "Bitte versuchen Sie es erneut.", }); return; } notifyError({ title: "Passwort konnte nicht zurückgesetzt werden.", description: "Bitte versuchen Sie es erneut.", }); } finally { setIsResetting(false); } }, [ user?.id, user?.username, isDisabled, onTemporaryPasswordChange, onPasswordReset, redirectToLoginExpired, ]); const handleToggleVisible = React.useCallback(() => { if (!hasTempPassword || isDisabled) return; setIsVisible((prev) => !prev); }, [hasTempPassword, isDisabled]); const handleCopyPassword = React.useCallback(async () => { if (!hasTempPassword || isDisabled) return; if (!navigator?.clipboard?.writeText) { notifyError({ title: "Kopieren nicht verfügbar", description: "Die Zwischenablage ist in diesem Browser nicht verfügbar.", }); return; } try { await navigator.clipboard.writeText(temporaryPassword); setCopySuccess(true); } catch { notifyError({ title: "Passwort konnte nicht kopiert werden.", description: "Bitte erneut versuchen.", }); } }, [hasTempPassword, isDisabled, temporaryPassword]); const displayValue = getDisplayedTemporaryPassword({ temporaryPassword, isVisible, }); const controls = (
); if (compact) { return (
{displayValue} {controls}
); } return (
{controls}

{hasTempPassword ? "Das temporäre Passwort ist nur in dieser Ansicht verfügbar." : "Noch kein temporäres Passwort gesetzt. Bitte zuerst zurücksetzen."}

); }