Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user registration UI #738

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
Draft

Add user registration UI #738

wants to merge 20 commits into from

Conversation

paulcretu
Copy link
Member

@paulcretu paulcretu commented Dec 12, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a multi-step user onboarding process with components for account creation, profile completion, preferences management, and success confirmation.
    • Added a "Join" button in both mobile and desktop navigation.
    • Implemented form handling and validation for user account registration and preferences using react-hook-form and zod.
  • Bug Fixes

    • Updated the registerWithPassword mutation to allow the username to be optional.
  • Documentation

    • Enhanced user interface with improved layout and styling for navigation and forms.
  • Chores

    • Updated project dependencies for improved functionality and performance.

Copy link

coderabbitai bot commented Dec 12, 2024

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request introduces several updates to the orcasite project, including new dependencies in package.json for form handling and validation. Key components for user registration and preferences management are added, utilizing react-hook-form and zod for validation. The Header component is enhanced with a "Join" button for account creation. Additionally, multiple new components are created to manage user input across various steps of the onboarding process, culminating in a structured flow for user registration and preferences.

Changes

File Change Summary
ui/package.json Added dependencies: @hookform/resolvers (^3.9.1), react-hook-form (^7.54.0), zod (^3.24.1).
ui/src/components/Header.tsx Added "Join" button with Person icon in both mobile and desktop navigation.
ui/src/graphql/mutations/registerWithPassword.graphql Changed $username parameter from required to optional in registerWithPassword mutation.
ui/src/pages/join/components/AccountStep.tsx Introduced AccountStep component for user registration with form validation.
ui/src/pages/join/components/FormActions.tsx Added FormActions component for rendering action buttons in forms.
ui/src/pages/join/components/PreferencesStep.tsx Introduced PreferencesStep component for managing user preferences.
ui/src/pages/join/components/ProfileStep.tsx Introduced ProfileStep component for user profile input.
ui/src/pages/join/components/StepLayout.tsx Added StepLayout component for structured page layout.
ui/src/pages/join/components/SuccessStep.tsx Introduced SuccessStep component for completion confirmation.
ui/src/pages/join/hooks/useSteps.ts Added useSteps hook for managing multi-step process.
ui/src/pages/join/index.tsx Created JoinPage component for onboarding process with step management.
ui/src/pages/join/utils.tsx Introduced utility functions for form handling and error management.

Assessment against linked issues

Objective Addressed Explanation
Allow listeners to sign up for notifications (333)
Create an account on the site so listener-submitted detections are credited to them (333)
Request survey information for the UX team to make improvements (333)
Accept the minimally necessary information in steps to avoid information overload (333)

Possibly related PRs

  • Bouts index UI #694: This PR adds new dependencies like react-hook-form and zod, relevant for the user interface enhancements in the "Bouts index UI" PR, which focuses on monitoring recent detections.
  • Upgrade elixir 1.17 #713: This PR updates frontend sign-in authentication error handling, relating to overall user experience improvements, particularly in form and user interaction management.

"In a garden of forms, we sprout and we grow,
With buttons for joining, and preferences to show.
Each step is a journey, from account to success,
A hop and a skip, we aim to impress! 🐇✨
So come join our dance, let your voice be heard,
In the world of Orcasound, spread the word!"


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@paulcretu
Copy link
Member Author

@coderabbitai review

Copy link

coderabbitai bot commented Dec 12, 2024

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🧹 Outside diff range and nitpick comments (9)
ui/src/pages/join/components/SuccessStep.tsx (1)

8-17: Consider enhancing user feedback and accessibility

While the implementation is functional, consider these improvements for better user experience:

  1. Add a success message/icon to confirm registration completion
  2. Include aria-label for screen readers
  3. Add loading state handling during navigation
 <Box sx={{ textAlign: "center" }}>
+  <Box sx={{ mb: 3 }}>
+    <Typography variant="h5" component="h1">
+      Registration Complete!
+    </Typography>
+    <Typography color="text.secondary" sx={{ mt: 1 }}>
+      Your account has been successfully created.
+    </Typography>
+  </Box>
   <Button
     variant="contained"
     color="primary"
     onClick={() => router.push("/")}
     size="large"
+    aria-label="Start listening to orca sounds"
   >
     Start listening
   </Button>
 </Box>
ui/src/graphql/mutations/registerWithPassword.graphql (1)

Line range hint 18-29: Consider enhancing error response structure

The error response structure looks good but consider adding:

  1. Field-specific validation rules in the error response
  2. Localization keys for error messages
    errors {
      message
      code
      fields
      shortMessage
      vars
+     validationRules
+     i18nKey
    }
ui/src/pages/join/components/FormActions.tsx (1)

3-7: Consider extending props interface

The type definition could be enhanced to:

  1. Support disabled states
  2. Allow custom button styling
  3. Include loading states
 type FormActionsProps = {
   onSkip?: () => void;
   submitText?: string;
   skipText?: string;
+  isSubmitting?: boolean;
+  isDisabled?: boolean;
+  buttonProps?: Partial<ButtonProps>;
 };
ui/src/pages/join/components/StepLayout.tsx (1)

15-36: Enhance accessibility and semantic structure.

While the layout is clean, it could benefit from improved accessibility.

Consider these enhancements:

 return (
   <>
     <Head>
       <title>{pageTitle} | Orcasound</title>
     </Head>
 
-    <Container maxWidth="sm">
+    <Container maxWidth="sm" component="main">
       <Box sx={{ mt: 4, mb: 6 }}>
-        <Typography variant="h4" gutterBottom>
+        <Typography variant="h4" component="h1" gutterBottom>
           {title}
         </Typography>
         {description && (
-          <Typography variant="body1" color="text.secondary">
+          <Typography 
+            variant="body1" 
+            color="text.secondary"
+            component="p"
+            role="doc-subtitle">
             {description}
           </Typography>
         )}
       </Box>
-      {children}
+      <div role="main">
+        {children}
+      </div>
     </Container>
   </>
 );
ui/src/pages/join/utils.tsx (1)

20-36: Consider enhancing type safety for field names.

The getFieldErrorProps function accepts any string as a field name, which could lead to runtime errors if mistyped.

Consider making the field parameter type-safe:

 export const getFieldErrorProps = <
+  T extends object,
+  K extends keyof T
 >(
-  field: string,
+  field: K,
   formError?: FieldError,
   mutationErrors?: MutationError[],
 ) => {
   const hasError =
     !!formError || mutationErrors?.some((e) => e.fields?.includes(field as string));
   const errorMessage =
     formError?.message ||
     mutationErrors?.find((e) => e.fields?.includes(field as string))?.message ||
     "";
 
   return {
     error: hasError,
     helperText: errorMessage || "",
   };
 };
ui/src/pages/join/components/PreferencesStep.tsx (1)

9-14: Consider adding constraints to the preference schema

While the boolean defaults are good, consider adding .describe() to each field to document their purpose in the schema itself. This would improve self-documentation and could be used to generate API documentation.

 const preferencesSchema = z.object({
-  liveNotifications: z.boolean().default(false),
+  liveNotifications: z.boolean().default(false).describe('Receive notifications for live orca detections'),
-  volunteering: z.boolean().default(false),
+  volunteering: z.boolean().default(false).describe('Interest in Orcasound volunteering opportunities'),
-  userTesting: z.boolean().default(false),
+  userTesting: z.boolean().default(false).describe('Willingness to participate in website testing'),
-  newsletter: z.boolean().default(false),
+  newsletter: z.boolean().default(false).describe('Opt-in for Orcasound newsletter'),
 });
ui/src/pages/join/components/ProfileStep.tsx (1)

61-68: Add loading state for organization field

The conditional rendering of the organization field should handle loading state to prevent flicker.

-{isMarineScientist && (
+{isMarineScientist && (
   <TextField
     {...register("organization")}
     label="Organization"
     fullWidth
     helperText="Your professional affiliation"
+    error={!!errors.organization}
+    helperText={errors.organization?.message || "Your professional affiliation"}
+    inputProps={{
+      'aria-label': 'Organization',
+    }}
   />
 )}
ui/src/pages/join/index.tsx (1)

17-41: Consider extracting step configurations

The step configurations object is quite large and could be moved to a separate file for better maintainability.

Consider creating a new file stepConfigs.ts to house these configurations.

ui/src/components/Header.tsx (1)

110-128: Consider adding aria-label for accessibility

The Join button could benefit from improved accessibility attributes.

Add aria-label to both mobile and desktop Join buttons:

 <Button
   variant="contained"
   startIcon={<Person />}
   color="primary"
+  aria-label="Create an account"
   sx={{
     borderRadius: 8,
   }}
 >
   Join
 </Button>

Also applies to: 266-287

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf6205f and fb58e19.

⛔ Files ignored due to path filters (2)
  • ui/package-lock.json is excluded by !**/package-lock.json
  • ui/src/graphql/generated/index.ts is excluded by !**/generated/**
📒 Files selected for processing (12)
  • ui/package.json (2 hunks)
  • ui/src/components/Header.tsx (5 hunks)
  • ui/src/graphql/mutations/registerWithPassword.graphql (1 hunks)
  • ui/src/pages/join/components/AccountStep.tsx (1 hunks)
  • ui/src/pages/join/components/FormActions.tsx (1 hunks)
  • ui/src/pages/join/components/PreferencesStep.tsx (1 hunks)
  • ui/src/pages/join/components/ProfileStep.tsx (1 hunks)
  • ui/src/pages/join/components/StepLayout.tsx (1 hunks)
  • ui/src/pages/join/components/SuccessStep.tsx (1 hunks)
  • ui/src/pages/join/hooks/useSteps.ts (1 hunks)
  • ui/src/pages/join/index.tsx (1 hunks)
  • ui/src/pages/join/utils.tsx (1 hunks)
🔇 Additional comments (5)
ui/src/pages/join/components/SuccessStep.tsx (1)

12-12: Consider handling navigation errors

The navigation callback should handle potential errors to ensure users aren't left in a broken state.

ui/src/graphql/mutations/registerWithPassword.graphql (1)

5-5: Verify impact of optional username

Making username optional is a significant change that could affect existing code paths. Please ensure:

  1. Client-side validation is updated accordingly
  2. Database constraints are aligned
  3. Username generation logic is in place if none provided
✅ Verification successful

Let me gather more information about the recent database migrations and related tests to understand the username changes better.


Let me check the GraphQL schema and related code to understand how username handling is implemented.


Based on the gathered information, I can now provide a final response:

Optional username change is properly implemented

The codebase shows proper handling of optional usernames:

  • Database migration 20240327003711_allow_username_nil.exs explicitly allows null usernames
  • User schema in accounts/user.ex has allow_nil?: true with appropriate constraints
  • Username uniqueness is still enforced through identity :unique_username when present
  • Tests demonstrate the registration flow remains functional
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for username validation patterns in the codebase
rg "username.*required|required.*username" --type typescript

# Look for username-related database migrations
fd -e exs -e sql | xargs rg -l "username"

Length of output: 580


Script:

#!/bin/bash
# Check the content of the recent username-related migrations
cat server/priv/repo/migrations/20240327003711_allow_username_nil.exs
cat server/priv/repo/migrations/20240122204313_make_username_non_null.exs

# Check username-related test cases
cat server/test/orcasite_web/graphql/accounts_test.exs

Length of output: 3507


Script:

#!/bin/bash
# Check GraphQL schema definitions and resolvers
fd -e ex | xargs rg -l "username"

# Look for username-related validation or generation logic
rg -A 5 "username" server/lib/

Length of output: 3877

ui/src/pages/join/hooks/useSteps.ts (1)

3-10: LGTM! Well-structured step definition using const assertions.

The use of const assertions provides excellent type safety for the step values.

ui/src/pages/join/components/StepLayout.tsx (1)

4-14: LGTM! Well-structured props interface.

The props are well-typed and provide good flexibility for different step content.

ui/package.json (1)

25-25: Verify version compatibility and check for security vulnerabilities

The new dependencies use caret ranges which could lead to compatibility issues:

  • @hookform/resolvers: ^3.9.1
  • react-hook-form: ^7.54.0
  • zod: ^3.24.1

Consider pinning these versions for better stability.

Also applies to: 41-41, 48-48

Comment on lines 14 to 23
<Box sx={{ display: "flex", gap: 2, mt: 2 }}>
{onSkip && (
<Button variant="outlined" onClick={onSkip} fullWidth>
{skipText}
</Button>
)}
<Button type="submit" variant="contained" color="primary" fullWidth>
{submitText}
</Button>
</Box>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance accessibility and user feedback

The implementation could be improved with:

  1. Loading states during form submission
  2. Disabled states to prevent double submission
  3. ARIA attributes for better screen reader support
 <Box sx={{ display: "flex", gap: 2, mt: 2 }}>
   {onSkip && (
     <Button
       variant="outlined"
       onClick={onSkip}
       fullWidth
+      disabled={isSubmitting}
+      aria-label={skipText}
     >
       {skipText}
     </Button>
   )}
   <Button
     type="submit"
     variant="contained"
     color="primary"
     fullWidth
+    disabled={isSubmitting || isDisabled}
+    aria-label={submitText}
   >
-    {submitText}
+    {isSubmitting ? <CircularProgress size={24} /> : submitText}
   </Button>
 </Box>

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 12 to 30
export const useSteps = () => {
const [currentStep, setCurrentStep] = useState<Step>(steps.account);

const goToNextStep = () => {
setCurrentStep((prev) =>
prev < steps.success ? ((prev + 1) as Step) : prev,
);
};

const skipToNextStep = () => {
goToNextStep();
};

return {
currentStep,
goToNextStep,
skipToNextStep,
};
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing step navigation capabilities.

The current implementation has a few limitations:

  1. skipToNextStep is identical to goToNextStep, making it redundant
  2. No ability to navigate to previous steps
  3. Missing step validation before progression

Consider this enhanced implementation:

 export const useSteps = () => {
   const [currentStep, setCurrentStep] = useState<Step>(steps.account);
 
   const goToNextStep = () => {
     setCurrentStep((prev) =>
       prev < steps.success ? ((prev + 1) as Step) : prev,
     );
   };
 
-  const skipToNextStep = () => {
-    goToNextStep();
-  };
+  const goToPreviousStep = () => {
+    setCurrentStep((prev) =>
+      prev > steps.account ? ((prev - 1) as Step) : prev,
+    );
+  };
+
+  const skipToNextStep = () => {
+    setCurrentStep((prev) =>
+      prev < steps.success ? ((prev + 2) as Step) : prev,
+    );
+  };
 
   return {
     currentStep,
     goToNextStep,
+    goToPreviousStep,
     skipToNextStep,
   };
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const useSteps = () => {
const [currentStep, setCurrentStep] = useState<Step>(steps.account);
const goToNextStep = () => {
setCurrentStep((prev) =>
prev < steps.success ? ((prev + 1) as Step) : prev,
);
};
const skipToNextStep = () => {
goToNextStep();
};
return {
currentStep,
goToNextStep,
skipToNextStep,
};
};
export const useSteps = () => {
const [currentStep, setCurrentStep] = useState<Step>(steps.account);
const goToNextStep = () => {
setCurrentStep((prev) =>
prev < steps.success ? ((prev + 1) as Step) : prev,
);
};
const goToPreviousStep = () => {
setCurrentStep((prev) =>
prev > steps.account ? ((prev - 1) as Step) : prev,
);
};
const skipToNextStep = () => {
setCurrentStep((prev) =>
prev < steps.success ? ((prev + 2) as Step) : prev,
);
};
return {
currentStep,
goToNextStep,
goToPreviousStep,
skipToNextStep,
};
};

Comment on lines 10 to 18
export const createFormSubmitHandler = <T extends object>(
form: UseFormReturn<T>,
onSubmit: (data: T) => void,
) => {
return form.handleSubmit((data) => {
console.log("Form data:", data);
onSubmit(data);
});
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove console.log from production code.

The form submission handler includes a console.log statement that should not be in production code.

Apply this change:

 export const createFormSubmitHandler = <T extends object>(
   form: UseFormReturn<T>,
   onSubmit: (data: T) => void,
 ) => {
   return form.handleSubmit((data) => {
-    console.log("Form data:", data);
     onSubmit(data);
   });
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const createFormSubmitHandler = <T extends object>(
form: UseFormReturn<T>,
onSubmit: (data: T) => void,
) => {
return form.handleSubmit((data) => {
console.log("Form data:", data);
onSubmit(data);
});
};
export const createFormSubmitHandler = <T extends object>(
form: UseFormReturn<T>,
onSubmit: (data: T) => void,
) => {
return form.handleSubmit((data) => {
onSubmit(data);
});
};

Comment on lines 29 to 32
const onSubmit = (data: PreferencesFormInputs) => {
// TODO: Implement preferences update mutation
onSuccess();
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement the TODO for preferences update mutation

The preferences update mutation needs to be implemented. This is a critical piece for persisting user preferences.

Would you like me to help generate the GraphQL mutation implementation for updating user preferences?

Comment on lines 41 to 67
return (
<form onSubmit={createFormSubmitHandler(form, onSubmit)} name="preferences">
<Box sx={{ display: "flex", flexDirection: "column", gap: 3 }}>
<FormControlLabel
control={<Switch {...register("liveNotifications")} />}
label="Notify me when orcas are detected live"
/>

<FormControlLabel
control={<Switch {...register("volunteering")} />}
label="I'm interested in volunteering with Orcasound"
/>

<FormControlLabel
control={<Switch {...register("userTesting")} />}
label="I'd like to participate in website user testing"
/>

<FormControlLabel
control={<Switch {...register("newsletter")} />}
label="Subscribe to the Orcasound newsletter"
/>

<FormActions onSkip={onSkip} submitText="Complete setup" />
</Box>
</form>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding loading state and error handling

The form submission lacks loading state and error handling. This could lead to a poor user experience if the mutation fails.

 export const PreferencesStep = ({ onSuccess, onSkip }: StepFormProps) => {
-  const { form, onSubmit } = usePreferencesForm(onSuccess);
-  const { register } = form;
+  const { form, onSubmit } = usePreferencesForm(onSuccess);
+  const { register, formState: { isSubmitting, errors } } = form;

   return (
     <form onSubmit={createFormSubmitHandler(form, onSubmit)} name="preferences">
       <Box sx={{ display: "flex", flexDirection: "column", gap: 3 }}>
         {/* ... existing form controls ... */}

-        <FormActions onSkip={onSkip} submitText="Complete setup" />
+        <FormActions 
+          onSkip={onSkip} 
+          submitText="Complete setup" 
+          disabled={isSubmitting}
+        />
+        {errors.root && (
+          <Typography color="error">
+            {errors.root.message}
+          </Typography>
+        )}
       </Box>
     </form>
   );
 };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 56 to 66
{currentStep === steps.account && (
<AccountStep onSuccess={goToNextStep} />
)}
{currentStep === steps.profile && (
<ProfileStep onSuccess={goToNextStep} onSkip={skipToNextStep} />
)}
{currentStep === steps.preferences && (
<PreferencesStep onSuccess={goToNextStep} onSkip={skipToNextStep} />
)}
{currentStep === steps.success && <SuccessStep />}
</StepLayout>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider handling invalid step states

The component doesn't handle cases where currentStep might be invalid.

Add error boundaries or fallback UI for invalid states:

+ if (currentStep < 1 || currentStep > Object.keys(steps).length) {
+   return <div>Invalid step</div>;
+ }

  {currentStep === steps.account && (
    <AccountStep onSuccess={goToNextStep} />
  )}
  // ... rest of the steps

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 63 to 69
const onSubmit = (data: AccountFormInputs) => {
submitRegister.mutate({
email: data.email,
password: data.password,
passwordConfirmation: data.password,
});
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add loading state handling

The form submission doesn't handle loading states, which could lead to multiple submissions.

 const onSubmit = (data: AccountFormInputs) => {
+  if (submitRegister.isLoading) return;
   submitRegister.mutate({
     email: data.email,
     password: data.password,
     passwordConfirmation: data.password,
   });
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const onSubmit = (data: AccountFormInputs) => {
submitRegister.mutate({
email: data.email,
password: data.password,
passwordConfirmation: data.password,
});
};
const onSubmit = (data: AccountFormInputs) => {
if (submitRegister.isLoading) return;
submitRegister.mutate({
email: data.email,
password: data.password,
passwordConfirmation: data.password,
});
};

Comment on lines 58 to 61
onError: (error) => {
console.log("Register error", error);
},
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error logging

The error logging could be more informative for debugging purposes.

-    console.log("Register error", error);
+    console.error("Registration failed:", {
+      error,
+      timestamp: new Date().toISOString(),
+      context: "AccountStep registration"
+    });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onError: (error) => {
console.log("Register error", error);
},
});
onError: (error) => {
console.error("Registration failed:", {
error,
timestamp: new Date().toISOString(),
context: "AccountStep registration"
});
},
});

Comment on lines 19 to 29
const accountSchema = z.object({
email: z.string().min(1, "Email is required").email("Invalid email address"),
password: z
.string()
.min(1, "Password is required")
.min(8, "Password must be at least 8 characters")
.regex(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
"Password must contain at least one uppercase letter, one lowercase letter, and one number",
),
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance password validation requirements

The current password validation might not be sufficient for security best practices.

Consider strengthening the password requirements:

 .regex(
-  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
-  "Password must contain at least one uppercase letter, one lowercase letter, and one number",
+  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])/,
+  "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character",
 )
+.max(128, "Password must not exceed 128 characters")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const accountSchema = z.object({
email: z.string().min(1, "Email is required").email("Invalid email address"),
password: z
.string()
.min(1, "Password is required")
.min(8, "Password must be at least 8 characters")
.regex(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
"Password must contain at least one uppercase letter, one lowercase letter, and one number",
),
});
const accountSchema = z.object({
email: z.string().min(1, "Email is required").email("Invalid email address"),
password: z
.string()
.min(1, "Password is required")
.min(8, "Password must be at least 8 characters")
.regex(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])/,
"Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character",
)
.max(128, "Password must not exceed 128 characters"),
});

Comment on lines 274 to 275
// TODO(@paulcretu): Add analytics event
// onClick={() => analytics.nav.joinClicked()}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement analytics tracking

The TODO comment indicates missing analytics tracking for the Join button.

Implement the analytics tracking as indicated in the TODO comment:

-// TODO(@paulcretu): Add analytics event
-// onClick={() => analytics.nav.joinClicked()}
+onClick={() => analytics.nav.joinClicked()}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TODO(@paulcretu): Add analytics event
// onClick={() => analytics.nav.joinClicked()}
onClick={() => analytics.nav.joinClicked()}

@paulcretu paulcretu temporarily deployed to orcasite-pr-738 December 12, 2024 17:05 Inactive
@paulcretu paulcretu temporarily deployed to orcasite-pr-738 December 13, 2024 01:14 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Investigate new registration and notification subscription flow Add sign in button to nav
1 participant