Skip to content

Commit 24b06c1

Browse files
committed
Keep tooltip open if password field is in focus
1 parent 05c177d commit 24b06c1

File tree

5 files changed

+54
-31
lines changed

5 files changed

+54
-31
lines changed

frontend/src/components/ChangePasswordModal/index.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,9 @@ const ChangePasswordModal: React.FC<ChangePasswordModalProps> = (props) => {
108108
{...register("confirmPassword", {
109109
setValueAs: (value: string) => value.trim(),
110110
validate: {
111-
matchPassword: (value) => {
112-
return (
113-
watch("newPassword") === value ||
114-
PASSWORD_MISMATCH_ERROR_MESSAGE
115-
);
116-
},
111+
matchPassword: (value) =>
112+
watch("newPassword") === value ||
113+
PASSWORD_MISMATCH_ERROR_MESSAGE,
117114
},
118115
})}
119116
error={!!errors.confirmPassword}

frontend/src/components/PasswordTextField/index.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ const TooltipMessage: React.FC<{
2929
<ListItem
3030
key={index}
3131
sx={(theme) => ({
32-
paddingLeft: theme.spacing(0.2),
33-
paddingRight: theme.spacing(0.2),
34-
paddingTop: 0,
35-
paddingBottom: 0,
32+
padding: theme.spacing(0, 0.2),
3633
alignItems: "flex-start",
3734
})}
3835
>
@@ -63,7 +60,7 @@ const TooltipMessage: React.FC<{
6360
<Clear
6461
sx={(theme) => ({
6562
fontSize: theme.spacing(2.5),
66-
color: "#9A2A2A",
63+
color: "error.main",
6764
})}
6865
/>
6966
)}
@@ -79,11 +76,31 @@ const PasswordTextField = forwardRef<
7976
HTMLInputElement,
8077
TextFieldProps & { displayTooltip?: boolean; input?: string }
8178
>((props, ref) => {
82-
const [showPassword, setShowPassword] = useState<boolean>(false);
8379
const { displayTooltip = false, input = "", ...rest } = props;
80+
const [showPassword, setShowPassword] = useState<boolean>(false);
81+
const [openTooltip, setOpenTooltip] = useState<boolean>(false);
82+
const [isFocused, setIsFocused] = useState<boolean>(false);
83+
84+
const handleMouseEnter = () => {
85+
setOpenTooltip(true);
86+
};
87+
const handleMouseLeave = () => {
88+
if (!isFocused) {
89+
setOpenTooltip(false);
90+
}
91+
};
92+
const handleFocus = () => {
93+
setIsFocused(true);
94+
setOpenTooltip(true);
95+
};
96+
const handleBlur = () => {
97+
setIsFocused(false);
98+
setOpenTooltip(false);
99+
};
84100

85101
return (
86102
<Tooltip
103+
open={openTooltip}
87104
title={displayTooltip && <TooltipMessage input={input} />}
88105
arrow
89106
placement="right"
@@ -116,6 +133,10 @@ const PasswordTextField = forwardRef<
116133
),
117134
},
118135
}}
136+
onMouseEnter={handleMouseEnter}
137+
onMouseLeave={handleMouseLeave}
138+
onFocus={handleFocus}
139+
onBlur={handleBlur}
119140
/>
120141
</Tooltip>
121142
);

frontend/src/contexts/AuthContext.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,25 @@ const AuthContext = createContext<AuthContextType | null>(null);
3737
const AuthProvider: React.FC<{ children?: React.ReactNode }> = (props) => {
3838
const { children } = props;
3939
const [user, setUser] = useState<User | null>(null);
40-
const [loading, setLoading] = useState<boolean>(true);
40+
const [loading, setLoading] = useState<boolean>(false);
4141
const navigate = useNavigate();
4242

4343
useEffect(() => {
4444
const accessToken = localStorage.getItem("token");
45-
userClient
46-
.get("/auth/verify-token", {
47-
headers: { Authorization: `Bearer ${accessToken}` },
48-
})
49-
.then((res) => setUser(res.data.data))
50-
.catch(() => setUser(null))
51-
.finally(() => {
52-
setTimeout(() => setLoading(false), 500);
53-
});
45+
if (accessToken) {
46+
setLoading(true);
47+
userClient
48+
.get("/auth/verify-token", {
49+
headers: { Authorization: `Bearer ${accessToken}` },
50+
})
51+
.then((res) => setUser(res.data.data))
52+
.catch(() => setUser(null))
53+
.finally(() => {
54+
setTimeout(() => setLoading(false), 500);
55+
});
56+
} else {
57+
setUser(null);
58+
}
5459
}, []);
5560

5661
const signup = (
@@ -71,7 +76,7 @@ const AuthProvider: React.FC<{ children?: React.ReactNode }> = (props) => {
7176
.then(() => login(email, password))
7277
.catch((err) => {
7378
setUser(null);
74-
toast.error(err.response.data.message);
79+
toast.error(err.response?.data.message || err.message);
7580
});
7681
};
7782

@@ -89,7 +94,7 @@ const AuthProvider: React.FC<{ children?: React.ReactNode }> = (props) => {
8994
})
9095
.catch((err) => {
9196
setUser(null);
92-
toast.error(err.response.data.message);
97+
toast.error(err.response?.data.message || err.message);
9398
});
9499
};
95100

frontend/src/contexts/ProfileContext.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const ProfileContextProvider: React.FC<{ children: React.ReactNode }> = ({
6868
})
6969
.catch((err) => {
7070
const message =
71-
err.response.data.message || FAILED_PROFILE_UPDATE_MESSAGE;
71+
err.response?.data.message || FAILED_PROFILE_UPDATE_MESSAGE;
7272
toast.error(message);
7373
});
7474
};
@@ -89,7 +89,7 @@ const ProfileContextProvider: React.FC<{ children: React.ReactNode }> = ({
8989
)
9090
.then(() => toast.success(SUCCESS_PW_UPDATE_MESSAGE))
9191
.catch((err) => {
92-
const message = err.response.data.message || FAILED_PW_UPDATE_MESSAGE;
92+
const message = err.response?.data.message || FAILED_PW_UPDATE_MESSAGE;
9393
toast.error(message);
9494
});
9595
};

frontend/src/reducers/questionReducer.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const createQuestion = async (
112112
.catch((err) => {
113113
dispatch({
114114
type: QuestionActionTypes.ERROR_CREATING_QUESTION,
115-
payload: err.response.data.message,
115+
payload: err.response?.data.message || err.message,
116116
});
117117
return false;
118118
});
@@ -130,7 +130,7 @@ export const getQuestionCategories = (dispatch: Dispatch<QuestionActions>) => {
130130
.catch((err) =>
131131
dispatch({
132132
type: QuestionActionTypes.ERROR_FETCHING_QUESTION_CATEGORIES,
133-
payload: err.response.data.message,
133+
payload: err.response?.data.message || err.message,
134134
})
135135
);
136136
};
@@ -162,7 +162,7 @@ export const getQuestionList = (
162162
.catch((err) =>
163163
dispatch({
164164
type: QuestionActionTypes.ERROR_FETCHING_QUESTION_LIST,
165-
payload: err.response.data.message,
165+
payload: err.response?.data.message || err.message,
166166
})
167167
);
168168
};
@@ -182,7 +182,7 @@ export const getQuestionById = (
182182
.catch((err) =>
183183
dispatch({
184184
type: QuestionActionTypes.ERROR_FETCHING_SELECTED_QN,
185-
payload: err.response.data.message,
185+
payload: err.response?.data.message || err.message,
186186
})
187187
);
188188
};
@@ -218,7 +218,7 @@ export const updateQuestionById = async (
218218
.catch((err) => {
219219
dispatch({
220220
type: QuestionActionTypes.ERROR_UPDATING_QUESTION,
221-
payload: err.response.data.message,
221+
payload: err.response?.data.message || err.message,
222222
});
223223
return false;
224224
});

0 commit comments

Comments
 (0)