diff options
| -rw-r--r-- | components/login/reset-password.tsx | 55 | ||||
| -rw-r--r-- | db/schema/vendorData.ts | 5 | ||||
| -rw-r--r-- | i18n/locales/en/login.json | 25 | ||||
| -rw-r--r-- | i18n/locales/ko/login.json | 25 |
4 files changed, 76 insertions, 34 deletions
diff --git a/components/login/reset-password.tsx b/components/login/reset-password.tsx index f68018d9..cc09f4fb 100644 --- a/components/login/reset-password.tsx +++ b/components/login/reset-password.tsx @@ -1,7 +1,6 @@ 'use client'; import { useState, useEffect } from 'react'; -import { useRouter } from 'next/navigation'; import { useFormState } from 'react-dom'; import { useToast } from '@/hooks/use-toast'; import { Button } from '@/components/ui/button'; @@ -12,6 +11,7 @@ import Link from 'next/link'; import SuccessPage from './SuccessPage'; import { PasswordPolicy } from '@/lib/users/auth/passwordUtil'; import { PasswordValidationResult, resetPasswordAction, validatePasswordAction } from '@/lib/users/auth/partners-auth'; +import { useTranslation } from '@/i18n/client'; interface PasswordRequirement { text: string; @@ -23,11 +23,12 @@ interface Props { token: string; userId: number; passwordPolicy: PasswordPolicy; + lng?: string; } -export default function ResetPasswordForm({ token, userId, passwordPolicy }: Props) { - const router = useRouter(); +export default function ResetPasswordForm({ token, userId, passwordPolicy, lng = 'ko' }: Props) { const { toast } = useToast(); + const { t } = useTranslation(lng, 'login'); // 상태 관리 const [showPassword, setShowPassword] = useState(false); @@ -75,12 +76,12 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro useEffect(() => { if (resetState.error) { toast({ - title: '오류', + title: t('error'), description: resetState.error, variant: 'destructive', }); } - }, [resetState, toast]); + }, [resetState, toast, t]); // 패스워드 요구사항 생성 const getPasswordRequirements = (): PasswordRequirement[] => { @@ -89,7 +90,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro const { strength } = passwordValidation; const requirements: PasswordRequirement[] = [ { - text: `${passwordPolicy.minLength}자 이상`, + text: `${passwordPolicy.minLength}${t('passwordRequirementLength')}`, met: strength.length >= passwordPolicy.minLength, type: 'length' } @@ -97,7 +98,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro if (passwordPolicy.requireUppercase) { requirements.push({ - text: '대문자 포함', + text: t('passwordRequirementUppercase'), met: strength.hasUppercase, type: 'uppercase' }); @@ -105,7 +106,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro if (passwordPolicy.requireLowercase) { requirements.push({ - text: '소문자 포함', + text: t('passwordRequirementLowercase'), met: strength.hasLowercase, type: 'lowercase' }); @@ -113,7 +114,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro if (passwordPolicy.requireNumbers) { requirements.push({ - text: '숫자 포함', + text: t('passwordRequirementNumbers'), met: strength.hasNumbers, type: 'number' }); @@ -121,7 +122,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro if (passwordPolicy.requireSymbols) { requirements.push({ - text: '특수문자 포함', + text: t('passwordRequirementSymbols'), met: strength.hasSymbols, type: 'symbol' }); @@ -144,11 +145,11 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro const getStrengthText = (score: number) => { switch (score) { - case 1: return '매우 약함'; - case 2: return '약함'; - case 3: return '보통'; - case 4: return '강함'; - case 5: return '매우 강함'; + case 1: return t('passwordStrengthVeryWeak'); + case 2: return t('passwordStrengthWeak'); + case 3: return t('passwordStrengthMedium'); + case 4: return t('passwordStrengthStrong'); + case 5: return t('passwordStrengthVeryStrong'); default: return ''; } }; @@ -170,9 +171,9 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro <Ship className="w-6 h-6 text-blue-600" /> <span className="text-xl font-bold">eVCP</span> </div> - <CardTitle className="text-2xl">새 비밀번호 설정</CardTitle> + <CardTitle className="text-2xl">{t('resetPasswordTitle')}</CardTitle> <CardDescription> - 계정 보안을 위해 강력한 비밀번호를 설정해주세요. + {t('resetPasswordDescription')} </CardDescription> </CardHeader> @@ -183,7 +184,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro {/* 새 비밀번호 */} <div className="space-y-2"> <label htmlFor="newPassword" className="text-sm font-medium text-gray-700"> - 새 비밀번호 + {t('newPassword')} </label> <div className="relative"> <Input @@ -192,7 +193,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro type={showPassword ? "text" : "password"} value={newPassword} onChange={(e) => setNewPassword(e.target.value)} - placeholder="새 비밀번호를 입력하세요" + placeholder={t('newPasswordPlaceholder')} required /> <button @@ -209,7 +210,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro <div className="mt-2 space-y-2"> <div className="flex items-center space-x-2"> <Shield className="h-4 w-4 text-gray-500" /> - <span className="text-xs text-gray-600">강도:</span> + <span className="text-xs text-gray-600">{t('passwordStrength')}:</span> <span className={`text-xs font-medium ${getStrengthColor(passwordValidation.strength.score)}`}> {getStrengthText(passwordValidation.strength.score)} </span> @@ -258,7 +259,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro <div className="flex items-center space-x-2 text-xs"> <XCircle className="h-3 w-3 text-red-500" /> <span className="text-red-700"> - 최근 {passwordPolicy.historyCount}개 비밀번호와 달라야 합니다 + {t('passwordHistoryError', { count: passwordPolicy.historyCount })} </span> </div> </div> @@ -292,7 +293,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro {/* 비밀번호 확인 */} <div className="space-y-2"> <label htmlFor="confirmPassword" className="text-sm font-medium text-gray-700"> - 비밀번호 확인 + {t('confirmPassword')} </label> <div className="relative"> <Input @@ -301,7 +302,7 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro type={showConfirmPassword ? "text" : "password"} value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} - placeholder="비밀번호를 다시 입력하세요" + placeholder={t('confirmPasswordPlaceholder')} required /> <button @@ -319,12 +320,12 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro {passwordsMatch ? ( <> <CheckCircle className="h-3 w-3 text-green-500" /> - <span className="text-green-700">비밀번호가 일치합니다</span> + <span className="text-green-700">{t('passwordsMatch')}</span> </> ) : ( <> <XCircle className="h-3 w-3 text-red-500" /> - <span className="text-red-700">비밀번호가 일치하지 않습니다</span> + <span className="text-red-700">{t('passwordsNotMatch')}</span> </> )} </div> @@ -336,13 +337,13 @@ export default function ResetPasswordForm({ token, userId, passwordPolicy }: Pro className="w-full" disabled={!canSubmit} > - {isValidatingPassword ? '검증 중...' : '비밀번호 변경하기'} + {isValidatingPassword ? t('validating') : t('changePassword')} </Button> </form> <div className="mt-6 text-center"> <Link href="/partners" className="text-sm text-blue-600 hover:text-blue-500"> - 로그인 페이지로 돌아가기 + {t('backToLogin')} </Link> </div> </CardContent> diff --git a/db/schema/vendorData.ts b/db/schema/vendorData.ts index 20348c55..c3df6b53 100644 --- a/db/schema/vendorData.ts +++ b/db/schema/vendorData.ts @@ -146,11 +146,6 @@ export const tagSubfields = pgTable("tag_subfields", { table.tagTypeCode, table.attributesId ), - // attributesId와 projectId 조합 내에서 유니크(0429 db push 관련 수정) - uniqAttributeIdProject: unique("uniq_attribute_id_project").on( - table.attributesId, - table.projectId - ), // tagTypes 참조를 위한 복합 FK (tagTypeCode, projectId) // tagTypeRef: foreignKey({ // columns: [table.tagTypeCode, table.projectId], diff --git a/i18n/locales/en/login.json b/i18n/locales/en/login.json index 2abdf036..674279f2 100644 --- a/i18n/locales/en/login.json +++ b/i18n/locales/en/login.json @@ -93,5 +93,28 @@ "authCodeExpired": "The verification code is incorrect or has expired.", "accessDenied": "Access denied.", "mfaAuthFailed": "MFA authentication failed.", - "mfaAuthError": "An error occurred during MFA authentication." + "mfaAuthError": "An error occurred during MFA authentication.", + "resetPasswordTitle": "Set New Password", + "resetPasswordDescription": "Please set a strong password for your account security.", + "newPassword": "New Password", + "newPasswordPlaceholder": "Enter your new password", + "confirmPassword": "Confirm Password", + "confirmPasswordPlaceholder": "Re-enter your password", + "error": "Error", + "passwordStrength": "Strength", + "passwordStrengthVeryWeak": "Very Weak", + "passwordStrengthWeak": "Weak", + "passwordStrengthMedium": "Medium", + "passwordStrengthStrong": "Strong", + "passwordStrengthVeryStrong": "Very Strong", + "passwordRequirementLength": " characters or more", + "passwordRequirementUppercase": "Include uppercase letters", + "passwordRequirementLowercase": "Include lowercase letters", + "passwordRequirementNumbers": "Include numbers", + "passwordRequirementSymbols": "Include special characters", + "passwordHistoryError": "Must be different from the last {{count}} passwords", + "passwordsMatch": "Passwords match", + "passwordsNotMatch": "Passwords do not match", + "validating": "Validating...", + "changePassword": "Change Password" }
\ No newline at end of file diff --git a/i18n/locales/ko/login.json b/i18n/locales/ko/login.json index eaa73a43..9dec5c56 100644 --- a/i18n/locales/ko/login.json +++ b/i18n/locales/ko/login.json @@ -93,5 +93,28 @@ "authCodeExpired": "인증번호가 올바르지 않거나 만료되었습니다.", "accessDenied": "접근이 거부되었습니다.", "mfaAuthFailed": "MFA 인증에 실패했습니다.", - "mfaAuthError": "MFA 인증 중 오류가 발생했습니다." + "mfaAuthError": "MFA 인증 중 오류가 발생했습니다.", + "resetPasswordTitle": "새 비밀번호 설정", + "resetPasswordDescription": "계정 보안을 위해 강력한 비밀번호를 설정해주세요.", + "newPassword": "새 비밀번호", + "newPasswordPlaceholder": "새 비밀번호를 입력하세요", + "confirmPassword": "비밀번호 확인", + "confirmPasswordPlaceholder": "비밀번호를 다시 입력하세요", + "error": "오류", + "passwordStrength": "강도", + "passwordStrengthVeryWeak": "매우 약함", + "passwordStrengthWeak": "약함", + "passwordStrengthMedium": "보통", + "passwordStrengthStrong": "강함", + "passwordStrengthVeryStrong": "매우 강함", + "passwordRequirementLength": "자 이상", + "passwordRequirementUppercase": "대문자 포함", + "passwordRequirementLowercase": "소문자 포함", + "passwordRequirementNumbers": "숫자 포함", + "passwordRequirementSymbols": "특수문자 포함", + "passwordHistoryError": "최근 {{count}}개 비밀번호와 달라야 합니다", + "passwordsMatch": "비밀번호가 일치합니다", + "passwordsNotMatch": "비밀번호가 일치하지 않습니다", + "validating": "검증 중...", + "changePassword": "비밀번호 변경하기" }
\ No newline at end of file |
