From 4645bde0250d4a9cb476c01757d9f119a4cf6a35 Mon Sep 17 00:00:00 2001
From: llpingll <94099281+llpingll@users.noreply.github.com>
Date: Sun, 25 Jan 2026 15:19:21 +0000
Subject: [PATCH 1/9] Allow all users to change password and handle expired
sessions
---
client/package-lock.json | 2 +-
.../Pages/Account/components/PasswordPanel.jsx | 16 ++++++++++++++--
client/src/Pages/Account/index.jsx | 2 +-
client/src/locales/en.json | 2 +-
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/client/package-lock.json b/client/package-lock.json
index 7f5397b7f..282ab2611 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -38,7 +38,7 @@
"react-toastify": "^10.0.5",
"recharts": "2.15.2",
"redux-persist": "6.0.0",
- "swr": "2.3.6",
+ "swr": "^2.3.6",
"vite-plugin-svgr": "^4.2.0",
"zod": "4.1.11"
},
diff --git a/client/src/Pages/Account/components/PasswordPanel.jsx b/client/src/Pages/Account/components/PasswordPanel.jsx
index f54c61a16..f06555dcd 100644
--- a/client/src/Pages/Account/components/PasswordPanel.jsx
+++ b/client/src/Pages/Account/components/PasswordPanel.jsx
@@ -11,6 +11,8 @@ import { useDispatch, useSelector } from "react-redux";
import { createToast } from "../../../Utils/toastUtils.jsx";
import { getTouchedFieldErrors } from "../../../Validation/error.js";
import { useTranslation } from "react-i18next";
+import { useNavigate } from "react-router-dom";
+import { clearAuthState } from "../../../Features/Auth/authSlice.js";
const defaultPasswordsState = {
password: "",
@@ -28,11 +30,12 @@ const PasswordPanel = () => {
const theme = useTheme();
const dispatch = useDispatch();
const { t } = useTranslation();
+ const navigate = useNavigate();
const SPACING_GAP = theme.spacing(12);
//redux state
- const { isLoading } = useSelector((state) => state.auth);
+ const { isLoading, authToken } = useSelector((state) => state.auth);
const idToName = {
"edit-current-password": "password",
@@ -79,6 +82,16 @@ const PasswordPanel = () => {
const handleSubmit = async (event) => {
event.preventDefault();
+ // Check for expired/invalid token before submitting
+ if (!authToken) {
+ createToast({
+ body: t("passwordPanel.sessionExpired", "Your session has expired. Please log in again."),
+ });
+ dispatch(clearAuthState());
+ navigate("/login");
+ return;
+ }
+
const { error } = newOrChangedCredentials.validate(localData, {
abortEarly: false,
context: { password: localData.newPassword },
@@ -105,7 +118,6 @@ const PasswordPanel = () => {
confirm: "",
});
} else {
- // TODO: Check for other errors?
createToast({
body: t(
"passwordPanel.passwordInputIncorrect",
diff --git a/client/src/Pages/Account/index.jsx b/client/src/Pages/Account/index.jsx
index ae16ff9d7..3bf480336 100644
--- a/client/src/Pages/Account/index.jsx
+++ b/client/src/Pages/Account/index.jsx
@@ -85,7 +85,7 @@ const Account = ({ open = "profile" }) => {
))}
- {user.role.includes("superadmin") && }
+
{!hideTeams && }
diff --git a/client/src/locales/en.json b/client/src/locales/en.json
index de02815b1..7e5eb7092 100644
--- a/client/src/locales/en.json
+++ b/client/src/locales/en.json
@@ -555,7 +555,7 @@
"enterNewPassword": "Enter your new password",
"confirmNewPassword": "Confirm new password",
"passwordRequirements": "New password must contain at least 8 characters and must have at least one uppercase letter, one lowercase letter, one number and one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`).",
- "saving": "Saving..."
+ "sessionExpired": "Your session has expired, please log in again to continue."
},
"emailSent": "Email sent successfully",
"failedToSendEmail": "Failed to send email",
From 14a08a303be5bb8142df51d382c2d523663dd10f Mon Sep 17 00:00:00 2001
From: llpingll <94099281+llpingll@users.noreply.github.com>
Date: Sun, 25 Jan 2026 15:45:34 +0000
Subject: [PATCH 2/9] Fix helper text to correctly use translation to display
message not key
---
client/src/Pages/Account/components/PasswordPanel.jsx | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/client/src/Pages/Account/components/PasswordPanel.jsx b/client/src/Pages/Account/components/PasswordPanel.jsx
index f06555dcd..427c263ea 100644
--- a/client/src/Pages/Account/components/PasswordPanel.jsx
+++ b/client/src/Pages/Account/components/PasswordPanel.jsx
@@ -85,7 +85,10 @@ const PasswordPanel = () => {
// Check for expired/invalid token before submitting
if (!authToken) {
createToast({
- body: t("passwordPanel.sessionExpired", "Your session has expired. Please log in again."),
+ body: t(
+ "passwordPanel.sessionExpired",
+ "Your session has expired. Please log in again."
+ ),
});
dispatch(clearAuthState());
navigate("/login");
@@ -179,7 +182,7 @@ const PasswordPanel = () => {
value={localData.password}
onChange={handleChange}
error={errors[idToName["edit-current-password"]] ? true : false}
- helperText={errors[idToName["edit-current-password"]]}
+ helperText={t(errors[idToName["edit-current-password"]])}
endAdornment={}
flex={1}
/>
@@ -205,7 +208,7 @@ const PasswordPanel = () => {
value={localData.newPassword}
onChange={handleChange}
error={errors[idToName["edit-new-password"]] ? true : false}
- helperText={errors[idToName["edit-new-password"]]}
+ helperText={t(errors[idToName["edit-new-password"]])}
endAdornment={}
flex={1}
/>
@@ -231,7 +234,7 @@ const PasswordPanel = () => {
value={localData.confirm}
onChange={handleChange}
error={errors[idToName["edit-confirm-password"]] ? true : false}
- helperText={errors[idToName["edit-confirm-password"]]}
+ helperText={t(errors[idToName["edit-confirm-password"]])}
endAdornment={}
flex={1}
/>
From f564636cb435e6076f50f58fbf16c59c2adaa92c Mon Sep 17 00:00:00 2001
From: llpingll <94099281+llpingll@users.noreply.github.com>
Date: Sun, 25 Jan 2026 19:11:25 +0000
Subject: [PATCH 3/9] Fix missingKey warning with helper text
---
.../Account/components/PasswordPanel.jsx | 21 ++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/client/src/Pages/Account/components/PasswordPanel.jsx b/client/src/Pages/Account/components/PasswordPanel.jsx
index 427c263ea..1c365804f 100644
--- a/client/src/Pages/Account/components/PasswordPanel.jsx
+++ b/client/src/Pages/Account/components/PasswordPanel.jsx
@@ -182,7 +182,12 @@ const PasswordPanel = () => {
value={localData.password}
onChange={handleChange}
error={errors[idToName["edit-current-password"]] ? true : false}
- helperText={t(errors[idToName["edit-current-password"]])}
+ helperText={
+ //Only call t() if there is an error to prevent unnecessary localization calls
+ errors[idToName["edit-current-password"]]
+ ? t(errors[idToName["edit-current-password"]])
+ : ""
+ }
endAdornment={}
flex={1}
/>
@@ -208,7 +213,12 @@ const PasswordPanel = () => {
value={localData.newPassword}
onChange={handleChange}
error={errors[idToName["edit-new-password"]] ? true : false}
- helperText={t(errors[idToName["edit-new-password"]])}
+ helperText={
+ //Only call t() if there is an error to prevent unnecessary localization calls
+ errors[idToName["edit-new-password"]]
+ ? t(errors[idToName["edit-new-password"]])
+ : ""
+ }
endAdornment={}
flex={1}
/>
@@ -234,7 +244,12 @@ const PasswordPanel = () => {
value={localData.confirm}
onChange={handleChange}
error={errors[idToName["edit-confirm-password"]] ? true : false}
- helperText={t(errors[idToName["edit-confirm-password"]])}
+ helperText={
+ //Only call t() if there is an error to prevent unnecessary localization calls
+ errors[idToName["edit-confirm-password"]]
+ ? t(errors[idToName["edit-confirm-password"]])
+ : ""
+ }
endAdornment={}
flex={1}
/>
From 4ce4a124d640bf5809577dc9e44ee20817d4c1ec Mon Sep 17 00:00:00 2001
From: llpingll <94099281+llpingll@users.noreply.github.com>
Date: Sun, 25 Jan 2026 22:57:36 +0000
Subject: [PATCH 4/9] Refactor PasswordPanel to pass navigation context via
state to ForgotPassword using TextLink | Update ForgotPassword and CheckEmail
to handle navigation context for Back links, ensuring users return to the
correct page after password reset | Fix TextLink prop usage to avoid warnings
by passing state and href correctly | Ensure error messages and navigation
links use translation keys for localization
---
client/src/Components/v1/TextLink/index.jsx | 4 +++-
.../Account/components/PasswordPanel.jsx | 13 +++++++++++--
client/src/Pages/Auth/CheckEmail.jsx | 13 ++++++++++---
client/src/Pages/Auth/ForgotPassword.jsx | 19 ++++++++++++++-----
client/src/locales/en.json | 3 +++
5 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/client/src/Components/v1/TextLink/index.jsx b/client/src/Components/v1/TextLink/index.jsx
index 83ae251a5..e226250a6 100644
--- a/client/src/Components/v1/TextLink/index.jsx
+++ b/client/src/Components/v1/TextLink/index.jsx
@@ -5,7 +5,7 @@ import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { Link as RouterLink } from "react-router-dom";
-const TextLink = ({ text, linkText, href, target = "_self" }) => {
+const TextLink = ({ text, linkText, href, state, target = "_self" }) => {
const theme = useTheme();
return (
@@ -19,6 +19,7 @@ const TextLink = ({ text, linkText, href, target = "_self" }) => {
to={href}
component={RouterLink}
target={target}
+ state={state}
>
{linkText}
@@ -30,6 +31,7 @@ TextLink.propTypes = {
text: PropTypes.string,
linkText: PropTypes.string,
href: PropTypes.string,
+ state: PropTypes.object,
target: PropTypes.string,
};
diff --git a/client/src/Pages/Account/components/PasswordPanel.jsx b/client/src/Pages/Account/components/PasswordPanel.jsx
index 1c365804f..7deb6dc8c 100644
--- a/client/src/Pages/Account/components/PasswordPanel.jsx
+++ b/client/src/Pages/Account/components/PasswordPanel.jsx
@@ -13,6 +13,8 @@ import { getTouchedFieldErrors } from "../../../Validation/error.js";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { clearAuthState } from "../../../Features/Auth/authSlice.js";
+import TextLink from "@/Components/v1/TextLink/index.jsx";
+import { useLocation } from "react-router-dom";
const defaultPasswordsState = {
password: "",
@@ -31,6 +33,7 @@ const PasswordPanel = () => {
const dispatch = useDispatch();
const { t } = useTranslation();
const navigate = useNavigate();
+ const location = useLocation();
const SPACING_GAP = theme.spacing(12);
@@ -267,8 +270,15 @@ const PasswordPanel = () => {
)}
+