feat(auth): add sign-up flow and reusable auth form widgets#14
feat(auth): add sign-up flow and reusable auth form widgets#14
Conversation
…h the /register contract
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughAdds a complete sign-up flow across layers: request/response DTOs (RegisterRequestDto, RegisterResponseDto), AuthApiClient.register, AuthRepository.signUp and AuthRepositoryImpl.signUp, SignUpCubit with SignUpState, SignUpPage and SignUpPageBuilder, shared UI widgets (AuthFlowShell, AuthTextField, AuthPasswordField, AuthSwitchSection), validators, router entry for /auth/sign-up, tests for repository and cubit, and makes UserDto.emailVerifiedAt nullable. Sequence Diagram(s)sequenceDiagram
participant User as User/UI
participant Page as SignUpPage
participant Cubit as SignUpCubit
participant Repo as AuthRepositoryImpl
participant API as AuthApiClient
participant Net as Network/Dio
User->>Page: Enter name, email, password
User->>Page: Tap "Sign Up"
Page->>Cubit: signUp(name, email, password)
Cubit->>Cubit: emit(inProgress)
Cubit->>Repo: signUp(name, email, password)
Repo->>Repo: build RegisterRequestDto
Repo->>API: register(request)
API->>Net: POST /register
Net-->>API: 200 RegisterResponseDto
API-->>Repo: RegisterResponseDto
Repo->>Repo: map to User entity
Repo-->>Cubit: Result<User, AuthFailure>
Cubit->>Cubit: emit(succeed(user)) / emit(failed(error))
Page->>User: show snackbar & navigate on success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (4)
CHANGELOG.md (1)
32-36: Consider grouping the new sign-up changelog bullets.Five consecutive entries start with
Added, which makes this subsection harder to scan. Collapsing them into one parent bullet with subitems would read cleaner.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@CHANGELOG.md` around lines 32 - 36, Combine the five consecutive "Added" bullets into a single parent bullet that summarizes "Added sign-up/auth changes" and list the specific artifacts as indented subitems; include subitems for the API and DTOs (RegisterRequestDto, RegisterResponseDto, AuthApiClient.register), data/domain changes (AuthRepository.signUp, AuthRepositoryImpl), presentation (SignUpCubit, SignUpPageBuilder, SignUpPage), tests (AuthRepositoryImpl.signUp tests, SignUpCubit tests), and shared UI widgets (AuthFlowShell, AuthTextField, AuthPasswordField, AuthSwitchSection) so the changelog reads as one coherent grouped entry with clear subentries.lib/features/auth/presentation/widgets/auth_flow_shell.dart (1)
34-39: Consider using theme colors for dark mode support.The hardcoded
Colors.whitebackground won't adapt to dark theme. If dark mode support is planned, consider using theme-aware colors.decoration: BoxDecoration( - color: Colors.white, + color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(24), ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/features/auth/presentation/widgets/auth_flow_shell.dart` around lines 34 - 39, The Container in AuthFlowShell uses a hardcoded Colors.white in its BoxDecoration which won't adapt to dark mode; replace that with a theme-aware color (e.g. Theme.of(context).colorScheme.surface or Theme.of(context).cardColor) so the background follows light/dark themes, e.g. update the BoxDecoration's color property to use Theme.of(context).colorScheme.surface (or cardColor) and ensure the enclosing build method has access to the BuildContext.lib/features/auth/presentation/widgets/auth_password_field.dart (1)
54-63: Consider adding semantic label for accessibility.The visibility toggle
IconButtonlacks a semantic label, which may impact screen reader users. Adding atooltipprovides both visual and accessibility benefits.suffixIcon: IconButton( + tooltip: _isPasswordVisible ? 'Hide password' : 'Show password', onPressed: widget.enabled ? () => setState(() { _isPasswordVisible = !_isPasswordVisible; }) : null, icon: Icon( _isPasswordVisible ? Icons.visibility_rounded : Icons.visibility_off_rounded, ), ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/features/auth/presentation/widgets/auth_password_field.dart` around lines 54 - 63, The IconButton used as the password visibility toggle (in the suffixIcon) is missing an accessibility label/tooltip; update the IconButton in auth_password_field.dart (the widget that toggles _isPasswordVisible and uses widget.enabled) to include a descriptive semantic label/tooltip (e.g., "Show password"/"Hide password" based on _isPasswordVisible) so screen readers and hover/tooltips provide context, ensuring the label changes when _isPasswordVisible toggles and remains null/disabled when widget.enabled is false.test/features/auth/support/auth_dto_fixtures.dart (1)
20-27: DefaultemailVerifiedAttonullin shared fixtures.The type is now nullable, but the common fixture still defaults to the old non-null shape. Making unverified the default broadens coverage for the new register contract and makes verified cases explicit.
🧪 Suggested change
- String? emailVerifiedAt = 'emailVerifiedAt', + String? emailVerifiedAt,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/features/auth/support/auth_dto_fixtures.dart` around lines 20 - 27, The shared fixture createUserDto currently defaults the nullable parameter emailVerifiedAt to the string 'emailVerifiedAt'; change the default to null so unverified users are the default in tests. Update the createUserDto signature (the emailVerifiedAt parameter) to use emailVerifiedAt = null (keeping its nullable type String?) and ensure any tests that relied on the old default explicitly pass a verified timestamp where needed (search for createUserDto calls to update those cases).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/features/auth/data/repositories/auth_repository_impl.dart`:
- Around line 47-51: In signUp (in auth_repository_impl.dart) don't assume
RegisterResponseDto is successful; check response.success and only return
Result.success(response.user.toEntity()) when true, otherwise return
Result.failure with an AuthFailure carrying response.message (map non-401
failures to a message-bearing AuthFailure and preserve UnauthorizedAuthFailure
behavior if applicable); update the signUp flow to convert
RegisterResponseDto.message -> user-facing AuthFailure and ensure Result.failure
is returned when response.success is false.
In `@lib/features/auth/presentation/pages/sign_up_page.dart`:
- Around line 39-45: Trim the incoming value before performing any validations
in _nameValidator: assign a local variable like trimmed = value?.trim() and use
that for the empty check and the length check (so surrounding whitespace doesn't
inflate length), and apply the same change to the other validator referenced at
lines 108-109 (e.g., _surnameValidator) to ensure consistency with _submit()
which trims input before sending.
- Around line 257-283: The RichText TextSpan children in SignUpPage are styled
like links but have no gesture recognizers or destinations; add
TapGestureRecognizer instances (importing/using TapGestureRecognizer from
gestures) for the two underlined TextSpans, wire them to Navigator.push to open
new routes, and manage their lifecycle by holding them as fields on the
SignUpPageState and disposing them in dispose(); also create simple target pages
(e.g., PrivacyPolicyPage and DataProcessingConsentPage classes/widgets) and
register/push them from the recognizers so tapping the underlined text navigates
to those pages.
- Around line 234-255: Replace the custom GestureDetector/Container checkbox
with Flutter's built-in Checkbox to restore keyboard and assistive-tech support:
in sign_up_page.dart remove the GestureDetector/Container block and use
Checkbox(value: isAgree, onChanged: enabled ? (v) => onTap?.call() /* or adapt
to accept ValueChanged<bool?> */ : null, activeColor:
Theme.of(context).colorScheme.primary, checkColor:
Theme.of(context).colorScheme.onPrimary) wrapped in a SizedBox(width: 48,
height: 48) (or Padding to ensure a 48×48 tap target) and add a semanticLabel
via Semantics(label: 'Agree to terms', child: ...) if needed; keep the existing
enabled/isAgree state usage and ensure the onTap callback signature is adapted
if necessary to accept the boolean from Checkbox.onChanged.
- Around line 137-141: The "Пропустить" TextButton is currently disabled in
non-debug builds due to the condition (!kDebugMode || isInProgress) which makes
the guest flow unreachable in production; update the topRightAction logic in
sign_up_page.dart to either remove the kDebugMode gate so the button is enabled
in production (i.e., use isInProgress alone to disable while loading and keep
onPressed calling context.read<AuthSessionCubit>().continueAsGuest()), or if
guest mode is truly dev-only, replace the disabling approach with visibility
logic so the TextButton is not rendered at all when !kDebugMode (wrap the widget
with a conditional or Visibility and keep isInProgress gating for enabled state)
and add a short comment explaining the chosen behavior.
- Around line 76-84: The sign-up validator (allowedCharsPattern, hasLetter,
hasDigit and max 64) in sign_up_page.dart is more restrictive than
sign_in_page.dart (which allows any character and max 128); confirm the backend
/register password policy and then update the sign_up_page.dart validators to
match it—either remove the allowedCharsPattern restriction to permit symbols (or
relax its regex), align the length limit to the backend (and to
sign_in_page.dart), and keep/adjust the hasLetter/hasDigit checks only if the
backend requires them so both sign-up and sign-in use the same rules.
---
Nitpick comments:
In `@CHANGELOG.md`:
- Around line 32-36: Combine the five consecutive "Added" bullets into a single
parent bullet that summarizes "Added sign-up/auth changes" and list the specific
artifacts as indented subitems; include subitems for the API and DTOs
(RegisterRequestDto, RegisterResponseDto, AuthApiClient.register), data/domain
changes (AuthRepository.signUp, AuthRepositoryImpl), presentation (SignUpCubit,
SignUpPageBuilder, SignUpPage), tests (AuthRepositoryImpl.signUp tests,
SignUpCubit tests), and shared UI widgets (AuthFlowShell, AuthTextField,
AuthPasswordField, AuthSwitchSection) so the changelog reads as one coherent
grouped entry with clear subentries.
In `@lib/features/auth/presentation/widgets/auth_flow_shell.dart`:
- Around line 34-39: The Container in AuthFlowShell uses a hardcoded
Colors.white in its BoxDecoration which won't adapt to dark mode; replace that
with a theme-aware color (e.g. Theme.of(context).colorScheme.surface or
Theme.of(context).cardColor) so the background follows light/dark themes, e.g.
update the BoxDecoration's color property to use
Theme.of(context).colorScheme.surface (or cardColor) and ensure the enclosing
build method has access to the BuildContext.
In `@lib/features/auth/presentation/widgets/auth_password_field.dart`:
- Around line 54-63: The IconButton used as the password visibility toggle (in
the suffixIcon) is missing an accessibility label/tooltip; update the IconButton
in auth_password_field.dart (the widget that toggles _isPasswordVisible and uses
widget.enabled) to include a descriptive semantic label/tooltip (e.g., "Show
password"/"Hide password" based on _isPasswordVisible) so screen readers and
hover/tooltips provide context, ensuring the label changes when
_isPasswordVisible toggles and remains null/disabled when widget.enabled is
false.
In `@test/features/auth/support/auth_dto_fixtures.dart`:
- Around line 20-27: The shared fixture createUserDto currently defaults the
nullable parameter emailVerifiedAt to the string 'emailVerifiedAt'; change the
default to null so unverified users are the default in tests. Update the
createUserDto signature (the emailVerifiedAt parameter) to use emailVerifiedAt =
null (keeping its nullable type String?) and ensure any tests that relied on the
old default explicitly pass a verified timestamp where needed (search for
createUserDto calls to update those cases).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 95394020-4e3f-49bb-8c86-f102aad5f330
📒 Files selected for processing (22)
CHANGELOG.mdlib/core/router/router.dartlib/core/router/router_paths.dartlib/features/auth/data/dto/register_request_dto.dartlib/features/auth/data/dto/register_response_dto.dartlib/features/auth/data/dto/user_dto.dartlib/features/auth/data/remote/auth_api_client.dartlib/features/auth/data/repositories/auth_repository_impl.dartlib/features/auth/domain/repositories/auth_repository.dartlib/features/auth/presentation/cubits/sign_up_cubit.dartlib/features/auth/presentation/cubits/sign_up_state.dartlib/features/auth/presentation/pages/sign_in_page.dartlib/features/auth/presentation/pages/sign_up_page.dartlib/features/auth/presentation/pages/sign_up_page_builder.dartlib/features/auth/presentation/widgets/.gitkeeplib/features/auth/presentation/widgets/auth_flow_shell.dartlib/features/auth/presentation/widgets/auth_password_field.dartlib/features/auth/presentation/widgets/auth_switch_section.dartlib/features/auth/presentation/widgets/auth_text_field.darttest/features/auth/data/repositories/auth_repository_impl_sign_up_test.darttest/features/auth/presentation/cubits/sign_up_cubit_test.darttest/features/auth/support/auth_dto_fixtures.dart
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| - | - | Generic Password | 7fe413a | test/features/auth/presentation/validators/auth_validators_test.dart | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/features/auth/presentation/pages/sign_in_page.dart`:
- Around line 104-109: The disabled "Забыли пароль?" TextButton (the
Align/TextButton block with onPressed: null and Text('Забыли пароль?')) should
be hidden until the feature exists; either remove that widget entirely or
conditionally render it. Fix by replacing the block with nothing (e.g., omit it
or return SizedBox.shrink()) or wrap it behind a feature flag/boolean (e.g.,
isForgotPasswordEnabled) and only render Align/TextButton when true, or
implement a real handler by setting onPressed to navigate to the
ForgotPasswordPage via Navigator.push (or call the existing forgot-password
handler) if the flow is ready. Ensure changes are made in the SignInPage where
Align/TextButton currently lives.
- Around line 95-101: The sign-in form currently uses the sign-up password
validator AuthValidators.password which can reject legacy or otherwise-valid
backend passwords; replace it with a simpler sign-in validator (e.g.,
AuthValidators.signInPassword) that only enforces presence. Add a new static
method signInPassword in AuthValidators returning a non-null error only when the
value is null/empty, then update the AuthPasswordField instance (the widget
using _passwordController, enabled: !isInProgress, textInputAction:
TextInputAction.done, onFieldSubmitted: _submit) to use
AuthValidators.signInPassword instead of AuthValidators.password so client-side
validation won’t incorrectly block login attempts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: bf93ead9-059d-45ab-b86a-f7f48bf3f32f
📒 Files selected for processing (4)
lib/features/auth/presentation/pages/sign_in_page.dartlib/features/auth/presentation/pages/sign_up_page.dartlib/features/auth/presentation/validators/auth_validators.darttest/features/auth/presentation/validators/auth_validators_test.dart
🚀 Summary
Implemented the
/registervertical slice end-to-end (API client → repository → cubit → UI → router), aligned register contract handling, and reduced auth UI duplication via shared widgets.✨ Changes
/registerintegration:RegisterRequestDto,RegisterResponseDto,AuthApiClient.register,AuthRepository.signUp,AuthRepositoryImpl.signUpAuthRepositoryImpl.signUpSignUpCubit+ unit testsSignUpPageandSignUpPageBuilder, wired route and navigation from sign-inAuthFlowShell,AuthTextField,AuthPasswordField,AuthSwitchSectionUserDto.emailVerifiedAtto nullable to match/registerpayloadConsentRowand improved consent validation message🧪 Verification
flutter analyzeflutter test