diff --git a/frontend/src/components/admin/PasswordResetModal.tsx b/frontend/src/components/admin/PasswordResetModal.tsx index 208ed564..f9236f38 100644 --- a/frontend/src/components/admin/PasswordResetModal.tsx +++ b/frontend/src/components/admin/PasswordResetModal.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { X, Key, Copy, CheckCircle, Mail, Lock, Eye, EyeOff } from 'lucide-react'; import { toast } from 'react-toastify'; +import { useTranslation } from 'react-i18next'; import { Button, Card, Input, PasswordGenerator } from '../common'; interface PasswordResetModalProps { @@ -18,6 +19,7 @@ export const PasswordResetModal: React.FC = ({ onConfirm, onClose }) => { + const { t } = useTranslation(); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); @@ -33,10 +35,10 @@ export const PasswordResetModal: React.FC = ({ // Empty is allowed → server auto-generates. Only validate when typed. if (password) { if (password.length < 6) { - next.password = 'Password must be at least 6 characters'; + next.password = t('events.passwordReset.errorMinLength'); } if (password !== confirmPassword) { - next.confirmPassword = 'Passwords do not match'; + next.confirmPassword = t('events.passwordReset.errorMismatch'); } } setErrors(next); @@ -52,14 +54,14 @@ export const PasswordResetModal: React.FC = ({ setResultPassword(result.newPassword); setResultWasGenerated(!supplied); if (supplied) { - toast.success('Password reset successfully'); + toast.success(t('events.passwordReset.toastSuccess')); } } catch (error: any) { const serverError = error?.response?.data; if (serverError?.error === 'Password does not meet security requirements') { - setErrors({ password: serverError.feedback?.join?.(' ') || 'Password does not meet security requirements' }); + setErrors({ password: serverError.feedback?.join?.(' ') || t('events.passwordReset.errorMinLength') }); } else { - toast.error(serverError?.error || 'Failed to reset password'); + toast.error(serverError?.error || t('events.passwordReset.toastError')); } } finally { setIsResetting(false); @@ -70,7 +72,7 @@ export const PasswordResetModal: React.FC = ({ if (resultPassword) { await navigator.clipboard.writeText(resultPassword); setCopied(true); - toast.success('Password copied to clipboard'); + toast.success(t('events.passwordReset.toastCopied')); setTimeout(() => setCopied(false), 2000); } }; @@ -86,7 +88,7 @@ export const PasswordResetModal: React.FC = ({

- {resultPassword ? 'New Password' : 'Reset Gallery Password'} + {resultPassword ? t('events.passwordReset.newTitle') : t('events.passwordReset.title')}

@@ -179,8 +181,7 @@ export const PasswordResetModal: React.FC = ({

- Note: The old password will no longer work. - Make sure to share the new password with the host. + {t('events.passwordReset.warning')}

@@ -191,7 +192,7 @@ export const PasswordResetModal: React.FC = ({ disabled={isResetting} className="flex-1" > - Cancel + {t('common.cancel')} @@ -210,11 +211,11 @@ export const PasswordResetModal: React.FC = ({
-

Password reset successfully!

+

{t('events.passwordReset.successHeading')}

{sendEmail && (

- An email notification has been sent to the host. + {t('events.passwordReset.emailSentNote')}

)}
@@ -223,7 +224,7 @@ export const PasswordResetModal: React.FC = ({ <>
= ({ onClick={handleCopy} leftIcon={copied ? : } > - {copied ? 'Copied!' : 'Copy'} + {copied ? t('events.copied') : t('events.copy')}

- Important: Save this password securely. It cannot be recovered once you close this window. + {t('events.passwordReset.saveSecurelyNote')}

@@ -255,7 +256,7 @@ export const PasswordResetModal: React.FC = ({ onClick={onClose} className="w-full" > - Done + {t('events.passwordReset.done')} )} diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 2456c406..f0cc2ded 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -904,6 +904,29 @@ "confirmPassword": "Passwort bestätigen", "showPasswords": "Passwörter anzeigen", "newPasswordLabel": "Neues Galerie-Passwort", + "passwordReset": { + "title": "Galerie-Passwort zurücksetzen", + "newTitle": "Neues Passwort", + "description": "Lege ein neues Passwort für {{eventName}} fest oder lasse beide Felder leer, um eines automatisch zu erzeugen.", + "newPasswordLabel": "Neues Passwort", + "placeholder": "Leer lassen für automatische Erzeugung", + "helperText": "Mindestens 6 Zeichen verwenden oder leer lassen für automatische Erzeugung", + "confirmLabel": "Passwort bestätigen", + "sendEmail": "E-Mail-Benachrichtigung senden", + "sendEmailHelp": "Den Host über die Passwortänderung informieren", + "warning": "Hinweis: Das alte Passwort funktioniert nicht mehr. Stelle sicher, dass du das neue Passwort an den Host weitergibst.", + "submit": "Passwort zurücksetzen", + "successHeading": "Passwort erfolgreich zurückgesetzt!", + "emailSentNote": "Eine E-Mail-Benachrichtigung wurde an den Host gesendet.", + "generatedLabel": "Automatisch generiertes Galerie-Passwort", + "saveSecurelyNote": "Wichtig: Speichere dieses Passwort sicher. Es kann nicht wiederhergestellt werden, sobald du dieses Fenster schließt.", + "done": "Fertig", + "toastSuccess": "Passwort erfolgreich zurückgesetzt", + "toastError": "Passwort zurücksetzen fehlgeschlagen", + "toastCopied": "Passwort in Zwischenablage kopiert", + "errorMinLength": "Das Passwort muss mindestens 6 Zeichen lang sein", + "errorMismatch": "Passwörter stimmen nicht überein" + }, "gallerySettings": "Galerie-Einstellungen", "colorTheme": "Farbthema", "galleryExpiration": "Galerie-Ablauf", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 0c571243..e03fe273 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -454,6 +454,29 @@ "confirmPassword": "Confirm Password", "showPasswords": "Show passwords", "newPasswordLabel": "New Gallery Password", + "passwordReset": { + "title": "Reset Gallery Password", + "newTitle": "New Password", + "description": "Set a new password for {{eventName}}, or leave both fields empty to have one auto-generated.", + "newPasswordLabel": "New password", + "placeholder": "Leave empty to auto-generate", + "helperText": "Use 6+ characters, or leave blank to auto-generate", + "confirmLabel": "Confirm password", + "sendEmail": "Send email notification", + "sendEmailHelp": "Notify the host about the password change", + "warning": "Note: The old password will no longer work. Make sure to share the new password with the host.", + "submit": "Reset Password", + "successHeading": "Password reset successfully!", + "emailSentNote": "An email notification has been sent to the host.", + "generatedLabel": "Auto-generated gallery password", + "saveSecurelyNote": "Important: Save this password securely. It cannot be recovered once you close this window.", + "done": "Done", + "toastSuccess": "Password reset successfully", + "toastError": "Failed to reset password", + "toastCopied": "Password copied to clipboard", + "errorMinLength": "Password must be at least 6 characters", + "errorMismatch": "Passwords do not match" + }, "gallerySettings": "Gallery Settings", "themeAndStyle": "Theme & Style", "colorTheme": "Color Theme", diff --git a/frontend/src/i18n/locales/nl.json b/frontend/src/i18n/locales/nl.json index ad5d64d4..e959c0b6 100644 --- a/frontend/src/i18n/locales/nl.json +++ b/frontend/src/i18n/locales/nl.json @@ -448,6 +448,29 @@ "confirmPassword": "Bevestig wachtwoord", "showPasswords": "Wachtwoorden tonen", "newPasswordLabel": "Nieuw galerijwachtwoord", + "passwordReset": { + "title": "Galerijwachtwoord opnieuw instellen", + "newTitle": "Nieuw wachtwoord", + "description": "Stel een nieuw wachtwoord in voor {{eventName}}, of laat beide velden leeg om er automatisch een te laten genereren.", + "newPasswordLabel": "Nieuw wachtwoord", + "placeholder": "Leeg laten voor automatische generatie", + "helperText": "Gebruik 6+ tekens, of laat leeg voor automatische generatie", + "confirmLabel": "Wachtwoord bevestigen", + "sendEmail": "E-mailmelding versturen", + "sendEmailHelp": "Stel de host op de hoogte van de wachtwoordwijziging", + "warning": "Let op: Het oude wachtwoord werkt niet meer. Zorg ervoor dat je het nieuwe wachtwoord deelt met de host.", + "submit": "Wachtwoord opnieuw instellen", + "successHeading": "Wachtwoord succesvol opnieuw ingesteld!", + "emailSentNote": "Een e-mailmelding is naar de host gestuurd.", + "generatedLabel": "Automatisch gegenereerd galerijwachtwoord", + "saveSecurelyNote": "Belangrijk: Sla dit wachtwoord veilig op. Het kan niet worden hersteld nadat je dit venster hebt gesloten.", + "done": "Klaar", + "toastSuccess": "Wachtwoord succesvol opnieuw ingesteld", + "toastError": "Wachtwoord opnieuw instellen mislukt", + "toastCopied": "Wachtwoord gekopieerd naar klembord", + "errorMinLength": "Wachtwoord moet minimaal 6 tekens bevatten", + "errorMismatch": "Wachtwoorden komen niet overeen" + }, "gallerySettings": "Galerijinstellingen", "themeAndStyle": "Thema & Stijl", "colorTheme": "Kleurthema", diff --git a/frontend/src/i18n/locales/pt.json b/frontend/src/i18n/locales/pt.json index 620fa972..248b7c90 100644 --- a/frontend/src/i18n/locales/pt.json +++ b/frontend/src/i18n/locales/pt.json @@ -448,6 +448,29 @@ "confirmPassword": "Confirmar Senha", "showPasswords": "Mostrar senhas", "newPasswordLabel": "Nova Senha da Galeria", + "passwordReset": { + "title": "Redefinir Senha da Galeria", + "newTitle": "Nova Senha", + "description": "Defina uma nova senha para {{eventName}} ou deixe ambos os campos vazios para gerar uma automaticamente.", + "newPasswordLabel": "Nova senha", + "placeholder": "Deixe em branco para gerar automaticamente", + "helperText": "Use 6+ caracteres, ou deixe em branco para gerar automaticamente", + "confirmLabel": "Confirmar senha", + "sendEmail": "Enviar notificação por e-mail", + "sendEmailHelp": "Notifique o anfitrião sobre a alteração de senha", + "warning": "Observação: A senha antiga não funcionará mais. Certifique-se de compartilhar a nova senha com o anfitrião.", + "submit": "Redefinir Senha", + "successHeading": "Senha redefinida com sucesso!", + "emailSentNote": "Uma notificação por e-mail foi enviada ao anfitrião.", + "generatedLabel": "Senha da galeria gerada automaticamente", + "saveSecurelyNote": "Importante: Salve esta senha com segurança. Ela não pode ser recuperada após fechar esta janela.", + "done": "Concluído", + "toastSuccess": "Senha redefinida com sucesso", + "toastError": "Falha ao redefinir senha", + "toastCopied": "Senha copiada para a área de transferência", + "errorMinLength": "A senha deve ter pelo menos 6 caracteres", + "errorMismatch": "As senhas não coincidem" + }, "gallerySettings": "Configurações da Galeria", "themeAndStyle": "Tema e Estilo", "colorTheme": "Tema de Cores", diff --git a/frontend/src/i18n/locales/ru.json b/frontend/src/i18n/locales/ru.json index 7e2a0897..5089e87e 100644 --- a/frontend/src/i18n/locales/ru.json +++ b/frontend/src/i18n/locales/ru.json @@ -448,6 +448,29 @@ "confirmPassword": "Подтвердить пароль", "showPasswords": "Показать пароли", "newPasswordLabel": "Новый пароль галереи", + "passwordReset": { + "title": "Сбросить пароль галереи", + "newTitle": "Новый пароль", + "description": "Установите новый пароль для {{eventName}} или оставьте оба поля пустыми, чтобы пароль был сгенерирован автоматически.", + "newPasswordLabel": "Новый пароль", + "placeholder": "Оставьте пустым для автоматической генерации", + "helperText": "Минимум 6 символов или оставьте пустым для автоматической генерации", + "confirmLabel": "Подтвердите пароль", + "sendEmail": "Отправить уведомление по электронной почте", + "sendEmailHelp": "Уведомить хоста об изменении пароля", + "warning": "Внимание: Старый пароль больше не будет работать. Обязательно передайте новый пароль хосту.", + "submit": "Сбросить пароль", + "successHeading": "Пароль успешно сброшен!", + "emailSentNote": "Уведомление по электронной почте отправлено хосту.", + "generatedLabel": "Автоматически сгенерированный пароль галереи", + "saveSecurelyNote": "Важно: Сохраните этот пароль в безопасном месте. Восстановить его после закрытия окна невозможно.", + "done": "Готово", + "toastSuccess": "Пароль успешно сброшен", + "toastError": "Не удалось сбросить пароль", + "toastCopied": "Пароль скопирован в буфер обмена", + "errorMinLength": "Пароль должен содержать не менее 6 символов", + "errorMismatch": "Пароли не совпадают" + }, "gallerySettings": "Настройки галереи", "themeAndStyle": "Тема и стиль", "colorTheme": "Цветовая тема",