forked from baron/baron-sso
i18n 대대적 변경
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../core/services/auth_proxy_service.dart';
|
||||
import 'package:userfront/i18n.dart';
|
||||
|
||||
class ResetPasswordScreen extends StatefulWidget {
|
||||
final String? loginId; // Now receiving loginId
|
||||
@@ -66,7 +67,12 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
Future<void> _handlePasswordReset() async {
|
||||
if (_formKey.currentState?.validate() != true) return;
|
||||
if ((_loginId == null || _loginId!.isEmpty) && (_token == null || _token!.isEmpty)) {
|
||||
_showError("유효하지 않은 재설정 링크입니다. (loginId/token 누락)");
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.reset.invalid_link',
|
||||
fallback: '유효하지 않은 재설정 링크입니다. (loginId/token 누락)',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,8 +87,13 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요."),
|
||||
SnackBar(
|
||||
content: Text(
|
||||
tr(
|
||||
'msg.userfront.reset.success',
|
||||
fallback: '비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요.',
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
@@ -90,7 +101,13 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
_showError("비밀번호 변경에 실패했습니다: ${e.toString()}");
|
||||
_showError(
|
||||
tr(
|
||||
'msg.userfront.reset.error.generic',
|
||||
fallback: '비밀번호 변경에 실패했습니다: {{error}}',
|
||||
params: {'error': e.toString()},
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
@@ -107,7 +124,10 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
|
||||
String _buildPolicyDescription() {
|
||||
if (_isPolicyLoading) {
|
||||
return "비밀번호 정책을 불러오는 중입니다...";
|
||||
return tr(
|
||||
'msg.userfront.reset.policy_loading',
|
||||
fallback: '비밀번호 정책을 불러오는 중입니다...',
|
||||
);
|
||||
}
|
||||
final minLength = (_policy?['minLength'] as int?) ?? 12;
|
||||
final minTypes = (_policy?['minCharacterTypes'] as int?) ?? 0;
|
||||
@@ -116,14 +136,42 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
final requiresNumber = _policy?['number'] ?? true;
|
||||
final requiresSymbol = _policy?['nonAlphanumeric'] ?? true;
|
||||
|
||||
final parts = <String>["최소 ${minLength}자 이상"];
|
||||
final parts = <String>[
|
||||
tr(
|
||||
'msg.userfront.reset.policy.min_length',
|
||||
fallback: '최소 {{count}}자 이상',
|
||||
params: {'count': '$minLength'},
|
||||
),
|
||||
];
|
||||
if (minTypes > 0) {
|
||||
parts.add("영문 대/소문자/숫자/특수문자 중 ${minTypes}가지 이상");
|
||||
parts.add(
|
||||
tr(
|
||||
'msg.userfront.reset.policy.min_types',
|
||||
fallback: '영문 대/소문자/숫자/특수문자 중 {{count}}가지 이상',
|
||||
params: {'count': '$minTypes'},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (requiresLower) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.lowercase', fallback: '소문자 1개 이상'),
|
||||
);
|
||||
}
|
||||
if (requiresUpper) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.uppercase', fallback: '대문자 1개 이상'),
|
||||
);
|
||||
}
|
||||
if (requiresNumber) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.number', fallback: '숫자 1개 이상'),
|
||||
);
|
||||
}
|
||||
if (requiresSymbol) {
|
||||
parts.add(
|
||||
tr('msg.userfront.reset.policy.symbol', fallback: '특수문자 1개 이상'),
|
||||
);
|
||||
}
|
||||
if (requiresLower) parts.add("소문자 1개 이상");
|
||||
if (requiresUpper) parts.add("대문자 1개 이상");
|
||||
if (requiresNumber) parts.add("숫자 1개 이상");
|
||||
if (requiresSymbol) parts.add("특수문자 1개 이상");
|
||||
|
||||
return parts.join(", ");
|
||||
}
|
||||
@@ -132,7 +180,9 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("새 비밀번호 설정"),
|
||||
title: Text(
|
||||
tr('ui.userfront.reset.title', fallback: '새 비밀번호 설정'),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Center(
|
||||
@@ -148,7 +198,10 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"새로운 비밀번호 설정",
|
||||
tr(
|
||||
'ui.userfront.reset.subtitle',
|
||||
fallback: '새로운 비밀번호 설정',
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -166,7 +219,10 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
controller: _passwordController,
|
||||
obscureText: _isPasswordObscured,
|
||||
decoration: InputDecoration(
|
||||
labelText: "새 비밀번호",
|
||||
labelText: tr(
|
||||
'ui.userfront.reset.new_password',
|
||||
fallback: '새 비밀번호',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.lock_outline),
|
||||
suffixIcon: IconButton(
|
||||
@@ -183,11 +239,18 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
validator: (value) {
|
||||
final val = value ?? "";
|
||||
if (val.isEmpty) {
|
||||
return '비밀번호를 입력해주세요.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.empty_password',
|
||||
fallback: '비밀번호를 입력해주세요.',
|
||||
);
|
||||
}
|
||||
final minLength = (_policy?['minLength'] as int?) ?? 12;
|
||||
if (val.length < minLength) {
|
||||
return '비밀번호는 최소 $minLength자 이상이어야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.min_length',
|
||||
fallback: '비밀번호는 최소 {{count}}자 이상이어야 합니다.',
|
||||
params: {'count': '$minLength'},
|
||||
);
|
||||
}
|
||||
final hasLower = RegExp(r'[a-z]').hasMatch(val);
|
||||
final hasUpper = RegExp(r'[A-Z]').hasMatch(val);
|
||||
@@ -201,20 +264,37 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
|
||||
final minTypes = (_policy?['minCharacterTypes'] as int?) ?? 0;
|
||||
if (minTypes > 0 && typeCount < minTypes) {
|
||||
return '비밀번호는 영문 대/소문자/숫자/특수문자 중 $minTypes가지 이상 포함해야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.min_types',
|
||||
fallback:
|
||||
'비밀번호는 영문 대/소문자/숫자/특수문자 중 {{count}}가지 이상 포함해야 합니다.',
|
||||
params: {'count': '$minTypes'},
|
||||
);
|
||||
}
|
||||
|
||||
if ((_policy?['lowercase'] ?? true) && !hasLower) {
|
||||
return '최소 1개 이상의 소문자를 포함해야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.lowercase',
|
||||
fallback: '최소 1개 이상의 소문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['uppercase'] ?? false) && !hasUpper) {
|
||||
return '최소 1개 이상의 대문자를 포함해야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.uppercase',
|
||||
fallback: '최소 1개 이상의 대문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['number'] ?? true) && !hasNumber) {
|
||||
return '최소 1개 이상의 숫자를 포함해야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.number',
|
||||
fallback: '최소 1개 이상의 숫자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
if ((_policy?['nonAlphanumeric'] ?? true) && !hasSymbol) {
|
||||
return '최소 1개 이상의 특수문자를 포함해야 합니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.symbol',
|
||||
fallback: '최소 1개 이상의 특수문자를 포함해야 합니다.',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -224,7 +304,10 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
controller: _confirmPasswordController,
|
||||
obscureText: _isConfirmPasswordObscured,
|
||||
decoration: InputDecoration(
|
||||
labelText: "새 비밀번호 확인",
|
||||
labelText: tr(
|
||||
'ui.userfront.reset.confirm_password',
|
||||
fallback: '새 비밀번호 확인',
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
prefixIcon: const Icon(Icons.lock_outline),
|
||||
suffixIcon: IconButton(
|
||||
@@ -240,7 +323,10 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
),
|
||||
validator: (value) {
|
||||
if (value != _passwordController.text) {
|
||||
return '비밀번호가 일치하지 않습니다.';
|
||||
return tr(
|
||||
'msg.userfront.reset.error.mismatch',
|
||||
fallback: '비밀번호가 일치하지 않습니다.',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -255,9 +341,17 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: const Text("비밀번호 변경"),
|
||||
: Text(
|
||||
tr(
|
||||
'ui.userfront.reset.submit',
|
||||
fallback: '비밀번호 변경',
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -268,20 +362,24 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
|
||||
}
|
||||
|
||||
Widget _buildInvalidTokenView() {
|
||||
return const Center(
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.error_outline, color: Colors.red, size: 60),
|
||||
SizedBox(height: 16),
|
||||
const Icon(Icons.error_outline, color: Colors.red, size: 60),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"유효하지 않은 링크입니다.",
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
tr('msg.userfront.reset.invalid_title',
|
||||
fallback: '유효하지 않은 링크입니다.'),
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
"비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요.",
|
||||
tr(
|
||||
'msg.userfront.reset.invalid_body',
|
||||
fallback: '비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요.',
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user