Shuffle/app/lib/features/auth/presentation/check_email/resend_controller.dart
cschlaefke e632da2344 feat(auth): add registration, check-email and email-link screens
Implements KTO-01 criteria 1-4, 10 and 11 (client part).

Refs #1

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

66 lines
2.1 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` from the
/// check-email screen, F12).
@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 whether `emailSendLimited` is shown (login) or treated as success
/// (check-email screen).
@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);
}
}