feat(auth): transition from email to phone-based OTP authentication

- Replace Email+Password login with Phone+OTP flow
- Remove RegisterCubit and registration screens (email verification)
- Remove ResetPasswordCubit and reset password screens
- Add phone normalization and international dial code support
- Update LoginCubit with sendCode/resend cooldown logic
- Add new widgets: phone prefix selector, confirm sheet
- Update all auth API endpoints: /otp/send, /phone-session
- Update form inputs: Email -> Phone with E.164 validation
- Update tests for new auth flow
This commit is contained in:
qzl
2026-03-19 18:42:05 +08:00
parent 636b37ee5a
commit 0661016827
29 changed files with 615 additions and 2030 deletions
@@ -1,41 +1,48 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../../../core/theme/design_tokens.dart';
class AuthField extends StatelessWidget {
const AuthField({
super.key,
required this.label,
this.label,
required this.hint,
required this.controller,
this.keyboardType,
this.obscureText = false,
this.suffixIcon,
this.onChanged,
this.prefix,
this.inputFormatters,
});
final String label;
final String? label;
final String hint;
final TextEditingController controller;
final TextInputType? keyboardType;
final bool obscureText;
final Widget? suffixIcon;
final ValueChanged<String>? onChanged;
final Widget? prefix;
final List<TextInputFormatter>? inputFormatters;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w700,
color: AppColors.slate700,
if (label != null) ...[
Text(
label!,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w700,
color: AppColors.slate700,
),
),
),
SizedBox(height: AppSpacing.sm),
SizedBox(height: AppSpacing.sm),
],
Semantics(
label: label,
textField: true,
@@ -44,6 +51,7 @@ class AuthField extends StatelessWidget {
keyboardType: keyboardType,
obscureText: obscureText,
onChanged: onChanged,
inputFormatters: inputFormatters,
style: const TextStyle(fontSize: 16, color: AppColors.slate900),
decoration: InputDecoration(
hintText: hint,
@@ -57,6 +65,7 @@ class AuthField extends StatelessWidget {
horizontal: AppSpacing.lg,
vertical: AppSpacing.lg,
),
prefixIcon: prefix,
suffixIcon: suffixIcon,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),