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-formwith azodschema for validation. - Partial Updates: The
onSubmithandler compares current values with form data to build a partialUserUpdateMeobject. - API Integration: Calls
UsersService.updateUserMewhich targets thePATCH /api/v1/users/meendpoint. - 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_passwordfield must matchnew_password, enforced via a Zod.refine()check. - API Call: Uses
UsersService.updatePasswordMewhich sends theUpdatePasswordpayload toPATCH /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
- Confirmation Dialog: A
Dialogcomponent from@/components/ui/dialogwarns the user about permanent data loss. - API Request:
UsersService.deleteUserMeis called to trigger theDELETE /api/v1/users/meendpoint. - Cleanup: Upon success, the
logout()function from theuseAuthhook is called to clear local session data, and thecurrentUserquery 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.