Skip to content

Commit 7a60038

Browse files
authored
Merge pull request #48 from ruiqi7/feature/user-authentication
Implement dynamic tooltips for password fields
2 parents 163191e + 24b06c1 commit 7a60038

File tree

16 files changed

+292
-320
lines changed

16 files changed

+292
-320
lines changed

frontend/src/components/ChangePasswordModal/index.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import { useForm } from "react-hook-form";
1111
import { useProfile } from "../../contexts/ProfileContext";
1212
import { passwordValidator } from "../../utils/validators";
1313
import PasswordTextField from "../PasswordTextField";
14+
import {
15+
PASSWORD_MISMATCH_ERROR_MESSAGE,
16+
PASSWORD_REQUIRED_ERROR_MESSAGE,
17+
USE_PROFILE_ERROR_MESSAGE,
18+
} from "../../utils/constants";
1419

1520
interface ChangePasswordModalProps {
1621
open: boolean;
@@ -26,8 +31,9 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
2631
const {
2732
register,
2833
handleSubmit,
29-
formState: { errors, isDirty, isValid },
34+
formState: { errors, dirtyFields, isDirty, isValid },
3035
watch,
36+
trigger,
3137
} = useForm<{
3238
oldPassword: string;
3339
newPassword: string;
@@ -39,16 +45,18 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
3945
const profile = useProfile();
4046

4147
if (!profile) {
42-
throw new Error("useProfile() must be used within ProfileContextProvider");
48+
throw new Error(USE_PROFILE_ERROR_MESSAGE);
4349
}
4450

4551
const { updatePassword } = profile;
4652

4753
return (
4854
<Dialog fullWidth open={open} onClose={onClose}>
49-
<DialogTitle fontSize={24}>Change password</DialogTitle>
55+
<DialogTitle fontSize={24} sx={{ paddingBottom: 0 }}>
56+
Change password
57+
</DialogTitle>
5058
<DialogContent>
51-
<Container maxWidth="sm">
59+
<Container maxWidth="sm" disableGutters>
5260
<StyledForm
5361
onSubmit={handleSubmit((data) => {
5462
updatePassword({
@@ -63,8 +71,10 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
6371
required
6472
fullWidth
6573
margin="normal"
74+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
6675
{...register("oldPassword", {
67-
required: "Required field",
76+
setValueAs: (value: string) => value.trim(),
77+
required: PASSWORD_REQUIRED_ERROR_MESSAGE,
6878
})}
6979
error={!!errors.oldPassword}
7080
helperText={errors.oldPassword?.message}
@@ -75,8 +85,16 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
7585
required
7686
fullWidth
7787
margin="normal"
88+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
89+
input={watch("newPassword", "")}
7890
{...register("newPassword", {
91+
setValueAs: (value: string) => value.trim(),
7992
validate: { passwordValidator },
93+
onChange: () => {
94+
if (dirtyFields.confirmPassword) {
95+
trigger("confirmPassword");
96+
}
97+
},
8098
})}
8199
error={!!errors.newPassword}
82100
helperText={errors.newPassword?.message}
@@ -86,10 +104,13 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
86104
required
87105
fullWidth
88106
margin="normal"
107+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
89108
{...register("confirmPassword", {
109+
setValueAs: (value: string) => value.trim(),
90110
validate: {
91111
matchPassword: (value) =>
92-
watch("newPassword") === value || "Password does not match",
112+
watch("newPassword") === value ||
113+
PASSWORD_MISMATCH_ERROR_MESSAGE,
93114
},
94115
})}
95116
error={!!errors.confirmPassword}

frontend/src/components/CustomTextField/index.tsx

Lines changed: 0 additions & 105 deletions
This file was deleted.

frontend/src/components/EditProfileModal/index.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { useForm } from "react-hook-form";
1212
import { useProfile } from "../../contexts/ProfileContext";
1313
import { bioValidator, nameValidator } from "../../utils/validators";
14+
import { USE_PROFILE_ERROR_MESSAGE } from "../../utils/constants";
1415

1516
interface EditProfileModalProps {
1617
onClose: () => void;
@@ -47,16 +48,18 @@ const EditProfileModal: React.FC<EditProfileModalProps> = (props) => {
4748
const profile = useProfile();
4849

4950
if (!profile) {
50-
throw new Error("useProfile() must be used within ProfileContextProvider");
51+
throw new Error(USE_PROFILE_ERROR_MESSAGE);
5152
}
5253

5354
const { updateProfile } = profile;
5455

5556
return (
5657
<Dialog open={open} onClose={onClose}>
57-
<DialogTitle fontSize={24}>Edit profile</DialogTitle>
58+
<DialogTitle fontSize={24} sx={{ paddingBottom: 0 }}>
59+
Edit profile
60+
</DialogTitle>
5861
<DialogContent>
59-
<Container maxWidth="sm">
62+
<Container maxWidth="sm" disableGutters>
6063
<StyledForm
6164
onSubmit={handleSubmit((data) => {
6265
updateProfile(data);
@@ -68,7 +71,9 @@ const EditProfileModal: React.FC<EditProfileModalProps> = (props) => {
6871
required
6972
label="First name"
7073
margin="normal"
74+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
7175
{...register("firstName", {
76+
setValueAs: (value: string) => value.trim(),
7277
validate: { nameValidator },
7378
})}
7479
error={!!errors.firstName}
@@ -79,7 +84,9 @@ const EditProfileModal: React.FC<EditProfileModalProps> = (props) => {
7984
required
8085
label="Last name"
8186
margin="normal"
87+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
8288
{...register("lastName", {
89+
setValueAs: (value: string) => value.trim(),
8390
validate: { nameValidator },
8491
})}
8592
error={!!errors.lastName}
@@ -90,7 +97,9 @@ const EditProfileModal: React.FC<EditProfileModalProps> = (props) => {
9097
multiline
9198
label="Biography"
9299
margin="normal"
100+
sx={(theme) => ({ marginTop: theme.spacing(1) })}
93101
{...register("biography", {
102+
setValueAs: (value: string) => value.trim(),
94103
validate: { bioValidator },
95104
})}
96105
/>

frontend/src/components/Navbar/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import AppMargin from "../AppMargin";
1717
import { useNavigate } from "react-router-dom";
1818
import { useAuth } from "../../contexts/AuthContext";
1919
import { useState } from "react";
20+
import { USE_AUTH_ERROR_MESSAGE } from "../../utils/constants";
2021

2122
type NavbarItem = { label: string; link: string };
2223

@@ -29,7 +30,7 @@ const Navbar: React.FC<NavbarProps> = (props) => {
2930
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
3031

3132
if (!auth) {
32-
throw new Error("useAuth() must be used within AuthProvider");
33+
throw new Error(USE_AUTH_ERROR_MESSAGE);
3334
}
3435

3536
const { logout, user } = auth;

0 commit comments

Comments
 (0)