refactor(legacy-account): move personal_data form state to provider (no setState)

This commit is contained in:
2026-04-22 00:16:48 +02:00
parent 41b22ad457
commit 5925a97b01
3 changed files with 171 additions and 11 deletions

View File

@@ -1,4 +1,5 @@
import 'package:account/src/features/personal_data/presentation/providers/personal_data_controller.dart';
import 'package:account/src/features/personal_data/presentation/providers/personal_data_form_state_provider.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -42,8 +43,6 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
late final TextEditingController _firstNameController;
late final TextEditingController _lastNameController;
late final TextEditingController _phoneController;
late String _isoCode;
String? _localError;
@override
void initState() {
@@ -54,7 +53,6 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
_phoneController = TextEditingController(
text: parsed?.nationalNumber ?? widget.user.phone,
);
_isoCode = parsed?.isoCode ?? SfPhoneNumber.defaultIsoCode;
}
@override
@@ -77,20 +75,24 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
void _onSubmit() {
if (!_hasChanges) return;
final formProvider = personalDataFormProvider(widget.user.phone);
final formNotifier = ref.read(formProvider.notifier);
final isoCode = ref.read(formProvider).isoCode;
final phoneText = _phoneController.text.trim();
String? fullPhone;
if (phoneText.isNotEmpty) {
final parsed = SfPhoneNumber.tryParse(
_phoneController.text,
defaultIsoCode: _isoCode,
defaultIsoCode: isoCode,
);
if (parsed == null) {
setState(() => _localError = I18n.errorMessagePhoneIsInvalid);
formNotifier.setLocalError(I18n.errorMessagePhoneIsInvalid);
return;
}
fullPhone = parsed.e164;
}
setState(() => _localError = null);
formNotifier.setLocalError(null);
final first = _firstNameController.text.trim().isNotEmpty
? _firstNameController.text.trim()
@@ -122,6 +124,9 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
final isLoading = ref.watch(
personalDataControllerProvider.select((s) => s.isLoading),
);
final formState = ref.watch(
personalDataFormProvider(widget.user.phone),
);
return LegacyPageLayout(
title: context.translate(I18n.personalData),
@@ -155,11 +160,17 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
children: [
CountryPrefixPicker(
headerText: context.translate(I18n.selectYourCountry),
initialSelection: _isoCode,
initialSelection: formState.isoCode,
onChanged: (country) {
final code = country.code;
if (code != null && code != _isoCode) {
setState(() => _isoCode = code);
if (code != null) {
ref
.read(
personalDataFormProvider(
widget.user.phone,
).notifier,
)
.setIsoCode(code);
}
},
width: 80,
@@ -175,11 +186,11 @@ class _PersonalDataFormState extends ConsumerState<_PersonalDataForm> {
),
],
),
if (_localError != null)
if (formState.localError != null)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
context.translate(_localError!),
context.translate(formState.localError!),
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.error,

View File

@@ -0,0 +1,38 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sf_shared/sf_shared.dart';
part 'personal_data_form_state_provider.g.dart';
class PersonalDataFormState {
const PersonalDataFormState({required this.isoCode, this.localError});
final String isoCode;
final String? localError;
PersonalDataFormState copyWith({String? isoCode, String? localError}) {
return PersonalDataFormState(
isoCode: isoCode ?? this.isoCode,
localError: localError,
);
}
}
@riverpod
class PersonalDataFormNotifier extends _$PersonalDataFormNotifier {
@override
PersonalDataFormState build(String initialPhone) {
final parsed = SfPhoneNumber.tryParse(initialPhone);
return PersonalDataFormState(
isoCode: parsed?.isoCode ?? SfPhoneNumber.defaultIsoCode,
);
}
void setIsoCode(String code) {
if (code == state.isoCode) return;
state = state.copyWith(isoCode: code);
}
void setLocalError(String? error) {
state = state.copyWith(localError: error);
}
}

View File

@@ -0,0 +1,111 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'personal_data_form_state_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
@ProviderFor(PersonalDataFormNotifier)
const personalDataFormProvider = PersonalDataFormNotifierFamily._();
final class PersonalDataFormNotifierProvider
extends $NotifierProvider<PersonalDataFormNotifier, PersonalDataFormState> {
const PersonalDataFormNotifierProvider._({
required PersonalDataFormNotifierFamily super.from,
required String super.argument,
}) : super(
retry: null,
name: r'personalDataFormProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$personalDataFormNotifierHash();
@override
String toString() {
return r'personalDataFormProvider'
''
'($argument)';
}
@$internal
@override
PersonalDataFormNotifier create() => PersonalDataFormNotifier();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(PersonalDataFormState value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<PersonalDataFormState>(value),
);
}
@override
bool operator ==(Object other) {
return other is PersonalDataFormNotifierProvider &&
other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$personalDataFormNotifierHash() =>
r'566d8314bb56d0eff43c6998195bd72820ef11e8';
final class PersonalDataFormNotifierFamily extends $Family
with
$ClassFamilyOverride<
PersonalDataFormNotifier,
PersonalDataFormState,
PersonalDataFormState,
PersonalDataFormState,
String
> {
const PersonalDataFormNotifierFamily._()
: super(
retry: null,
name: r'personalDataFormProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
PersonalDataFormNotifierProvider call(String initialPhone) =>
PersonalDataFormNotifierProvider._(argument: initialPhone, from: this);
@override
String toString() => r'personalDataFormProvider';
}
abstract class _$PersonalDataFormNotifier
extends $Notifier<PersonalDataFormState> {
late final _$args = ref.$arg as String;
String get initialPhone => _$args;
PersonalDataFormState build(String initialPhone);
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<PersonalDataFormState, PersonalDataFormState>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<PersonalDataFormState, PersonalDataFormState>,
PersonalDataFormState,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}