1
0
forked from baron/baron-sso

userfront gateway 분리.

This commit is contained in:
Lectom C Han
2026-01-30 16:14:20 +09:00
parent 35552943d7
commit 1db7ce8f10
8 changed files with 302 additions and 99 deletions

View File

@@ -31,6 +31,11 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
final FocusNode _departmentFocus = FocusNode();
final FocusNode _phoneFocus = FocusNode();
final FocusNode _phoneCodeFocus = FocusNode();
bool _nameTouched = false;
bool _departmentTouched = false;
bool _phoneTouched = false;
bool _phoneCodeTouched = false;
bool _isSavingField = false;
String _initialPhone = '';
bool _isPhoneChanged = false;
@@ -102,6 +107,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_isCodeSent = false;
_isVerifying = false;
_codeController?.clear();
_phoneTouched = false;
_phoneCodeTouched = false;
}
void _startEditing(String field, UserProfile profile) {
@@ -117,6 +124,16 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_resetPhoneState();
}
});
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
if (field == 'name') {
FocusScope.of(context).requestFocus(_nameFocus);
} else if (field == 'department') {
FocusScope.of(context).requestFocus(_departmentFocus);
} else if (field == 'phone') {
FocusScope.of(context).requestFocus(_phoneFocus);
}
});
}
void _cancelEditing(UserProfile profile) {
@@ -131,6 +148,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_resetPhoneState();
}
_editingField = null;
_nameTouched = false;
_departmentTouched = false;
});
}
@@ -193,18 +212,55 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
void _autoSaveIfEditing(UserProfile profile, String field) {
if (_editingField != field) return;
if (_isVerifying) return;
if (_isSavingField) return;
if (!_hasFieldChanged(profile, field)) {
setState(() {
if (field == 'phone') {
_resetPhoneState();
}
_editingField = null;
if (field == 'name') {
_nameTouched = false;
} else if (field == 'department') {
_departmentTouched = false;
}
});
return;
}
_saveField(profile);
}
void _handlePhoneFocusChange(UserProfile profile) {
if (_editingField != 'phone') return;
if (_isVerifying) return;
if (_isSavingField) return;
if (_phoneFocus.hasFocus || _phoneCodeFocus.hasFocus) return;
if (!_hasFieldChanged(profile, 'phone')) {
setState(() {
_resetPhoneState();
_editingField = null;
});
return;
}
_saveField(profile);
}
bool _hasFieldChanged(UserProfile profile, String field) {
if (field == 'name') {
return (_nameController?.text.trim() ?? '') != profile.name;
}
if (field == 'department') {
return (_departmentController?.text.trim() ?? '') != profile.department;
}
if (field == 'phone') {
return (_phoneController?.text.trim() ?? '') != profile.phone;
}
return false;
}
Future<void> _saveField(UserProfile profile) async {
if (_editingField == null) return;
if (_isSavingField) return;
final nextName = _editingField == 'name'
? _nameController!.text.trim()
@@ -243,6 +299,20 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
}
}
if (!_hasFieldChanged(profile, _editingField!)) {
setState(() {
if (_editingField == 'phone') {
_resetPhoneState();
}
_editingField = null;
_nameTouched = false;
_departmentTouched = false;
});
return;
}
_isSavingField = true;
try {
await ref.read(profileProvider.notifier).updateProfile(
name: nextName,
@@ -256,6 +326,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_resetPhoneState();
}
_editingField = null;
_nameTouched = false;
_departmentTouched = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('정보가 수정되었습니다.')),
@@ -267,6 +339,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
SnackBar(content: Text('수정 실패: $e')),
);
}
} finally {
_isSavingField = false;
}
}
@@ -454,23 +528,53 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.w600)),
const SizedBox(height: 8),
Focus(
focusNode: field == 'name' ? _nameFocus : _departmentFocus,
onFocusChange: (hasFocus) {
if (!hasFocus) {
_autoSaveIfEditing(profile, field);
}
},
child: TextField(
controller: controller,
focusNode: field == 'name' ? _nameFocus : _departmentFocus,
textInputAction: TextInputAction.done,
onSubmitted: (_) => _autoSaveIfEditing(profile, field),
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: label,
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Focus(
focusNode: field == 'name' ? _nameFocus : _departmentFocus,
onFocusChange: (hasFocus) {
if (field == 'name') {
if (hasFocus) {
_nameTouched = true;
return;
}
if (!_nameTouched) {
return;
}
}
if (field == 'department') {
if (hasFocus) {
_departmentTouched = true;
return;
}
if (!_departmentTouched) {
return;
}
}
if (!hasFocus) {
_autoSaveIfEditing(profile, field);
}
},
child: TextField(
controller: controller,
focusNode: field == 'name' ? _nameFocus : _departmentFocus,
textInputAction: TextInputAction.done,
onSubmitted: (_) => _autoSaveIfEditing(profile, field),
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: label,
),
),
),
),
),
const SizedBox(width: 12),
OutlinedButton(
onPressed: isUpdating ? null : () => _cancelEditing(profile),
child: const Text('취소'),
),
],
),
],
);
@@ -504,6 +608,13 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
child: Focus(
focusNode: _phoneFocus,
onFocusChange: (hasFocus) {
if (hasFocus) {
_phoneTouched = true;
return;
}
if (!_phoneTouched) {
return;
}
if (!hasFocus) {
_handlePhoneFocusChange(profile);
}
@@ -531,6 +642,11 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
onPressed: _isVerifying ? null : _sendCode,
child: Text(_isCodeSent ? '재전송' : '인증요청'),
),
const SizedBox(width: 8),
OutlinedButton(
onPressed: isUpdating ? null : () => _cancelEditing(profile),
child: const Text('취소'),
),
],
),
if (_isCodeSent && !_isPhoneVerified) ...[
@@ -542,6 +658,13 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
child: Focus(
focusNode: _phoneCodeFocus,
onFocusChange: (hasFocus) {
if (hasFocus) {
_phoneCodeTouched = true;
return;
}
if (!_phoneCodeTouched) {
return;
}
if (!hasFocus) {
_handlePhoneFocusChange(profile);
}