Skip to main content

Managing Personal Account Settings

To manage personal account settings in this project, users interact with the UserSettings components located in frontend/src/components/UserSettings. These components utilize the UsersService to perform authenticated API requests for updating profile details, changing passwords, and deleting accounts.

Updating Profile Information

Users can update their full name and email address through the UserInformation component. This component implements a toggleable edit mode and ensures that only modified fields are sent to the backend to optimize the update process.

// From frontend/src/components/UserSettings/UserInformation.tsx

const onSubmit = (data: FormData) => {
const updateData: UserUpdateMe = {}

// only include fields that have changed
if (data.full_name !== currentUser?.full_name) {
updateData.full_name = data.full_name
}
if (data.email !== currentUser?.email) {
updateData.email = data.email
}

mutation.mutate(updateData)
}

const mutation = useMutation({
mutationFn: (data: UserUpdateMe) =>
UsersService.updateUserMe({ requestBody: data }),
onSuccess: () => {
showSuccessToast("User updated successfully")
toggleEditMode()
},
onError: handleError.bind(showErrorToast),
onSettled: () => {
queryClient.invalidateQueries()
},
})

Key Implementation Details

  • Form Management: Uses react-hook-form with a zod schema for validation.
  • Partial Updates: The onSubmit handler compares current values with form data to build a partial UserUpdateMe object.
  • API Integration: Calls UsersService.updateUserMe which targets the PATCH /api/v1/users/me endpoint.
  • State Sync: On success, queryClient.invalidateQueries() is called to refresh the user data across the application.

Changing Passwords

The ChangePassword component provides a secure form for users to update their credentials. It requires the current password for verification and enforces strict validation for the new password.

// From frontend/src/components/UserSettings/ChangePassword.tsx

const formSchema = z
.object({
current_password: z
.string()
.min(1, { message: "Password is required" })
.min(8, { message: "Password must be at least 8 characters" }),
new_password: z
.string()
.min(1, { message: "Password is required" })
.min(8, { message: "Password must be at least 8 characters" }),
confirm_password: z
.string()
.min(1, { message: "Password confirmation is required" }),
})
.refine((data) => data.new_password === data.confirm_password, {
message: "The passwords don't match",
path: ["confirm_password"],
})

const mutation = useMutation({
mutationFn: (data: UpdatePassword) =>
UsersService.updatePasswordMe({ requestBody: data }),
onSuccess: () => {
showSuccessToast("Password updated successfully")
form.reset()
},
onError: handleError.bind(showErrorToast),
})

Validation Rules

  • Minimum Length: Both current and new passwords must be at least 8 characters long.
  • Confirmation: The confirm_password field must match new_password, enforced via a Zod .refine() check.
  • API Call: Uses UsersService.updatePasswordMe which sends the UpdatePassword payload to PATCH /api/v1/users/me/password.

Deleting an Account

The "Danger Zone" in the settings page includes the DeleteConfirmation component, which allows users to permanently remove their account. This action is irreversible and requires explicit confirmation via a dialog.

// From frontend/src/components/UserSettings/DeleteConfirmation.tsx

const mutation = useMutation({
mutationFn: () => UsersService.deleteUserMe(),
onSuccess: () => {
showSuccessToast("Your account has been successfully deleted")
logout()
},
onError: handleError.bind(showErrorToast),
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["currentUser"] })
},
})

Deletion Workflow

  1. Confirmation Dialog: A Dialog component from @/components/ui/dialog warns the user about permanent data loss.
  2. API Request: UsersService.deleteUserMe is called to trigger the DELETE /api/v1/users/me endpoint.
  3. Cleanup: Upon success, the logout() function from the useAuth hook is called to clear local session data, and the currentUser query is invalidated.

Troubleshooting

Validation Errors

If the API returns a 422 Validation Error, the handleError utility (bound to showErrorToast) will display the specific field errors. This typically occurs if the email is already taken or the password does not meet complexity requirements.

Form State Issues

The "Save" button in UserInformation is disabled unless the form is "dirty" (i.e., values have changed). If you cannot click save, ensure you have modified at least one field.

<LoadingButton
type="submit"
loading={mutation.isPending}
disabled={!form.formState.isDirty}
>
Save
</LoadingButton>

Authentication Timeouts

If a user's session expires while they are on the settings page, UsersService methods will fail with a 401 Unauthorized. The application's global error handling or the useAuth hook typically redirects the user to the login page in these scenarios.