Shuffle/app/lib/features/auth/presentation/check_email/resend_controller.dart
cschlaefke 3805c71225
Some checks failed
CI / flutter (pull_request) Failing after 44s
CI / web-build (pull_request) Successful in 51s
CI / supabase (pull_request) Successful in 3s
CI / supabase-tests (pull_request) Successful in 29s
CI / e2e (pull_request) Successful in 2m44s
fix(auth): address review findings for smtp-neutral handling
Refs #37

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 12:24:25 +01:00

67 lines
2.2 KiB
Dart

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shuffle/features/auth/domain/auth_failure.dart';
import 'package:shuffle/features/auth/domain/resend_origin.dart';
import 'package:shuffle/features/auth/domain/validation/email_format.dart';
import 'package:shuffle/features/auth/presentation/providers/auth_providers.dart';
part 'resend_controller.freezed.dart';
part 'resend_controller.g.dart';
@freezed
abstract class ResendState with _$ResendState {
const factory ResendState({
@Default(false) bool isSending,
/// The last request counts as sent (also for `emailSendLimited` and server
/// failures from the check-email screen, F12/F13).
@Default(false) bool sent,
AuthFailure? failure,
/// Only for an address typed in by the user.
EmailError? emailError,
}) = _ResendState;
}
/// "Resend email" for the confirmation (KTO-01 Kriterium 6, F12).
///
/// The caller states where the request comes from: only there the controller
/// decides (`resendFailureFor`): `emailSendLimited` is shown at login and
/// treated as success on the check-email screen; `unexpected` (e.g. SMTP
/// outage) is shown at login (account proven) and neutral on check-email.
@riverpod
class ResendController extends _$ResendController {
@override
ResendState build() => const ResendState();
void clearEmailError() {
if (state.emailError != null) {
state = state.copyWith(emailError: null);
}
}
Future<void> resend(String email, {required ResendOrigin origin}) async {
if (state.isSending) {
return;
}
final normalized = EmailFormat.normalize(email);
final emailError = EmailFormat.validate(normalized);
if (emailError != null) {
state = ResendState(emailError: emailError);
return;
}
state = const ResendState(isSending: true);
final result = await ref
.read(authRepositoryProvider)
.resendConfirmation(normalized);
if (!ref.mounted) {
return;
}
final raw = result.errorOrNull;
final failure = raw == null ? null : resendFailureFor(raw, origin);
state = failure == null
? const ResendState(sent: true)
: ResendState(failure: failure);
}
}