feat: #339 Add email notification toggle setting and update tests (#387)

This commit is contained in:
lenhanphung
2025-12-08 16:54:24 +07:00
committed by GitHub
parent 1056220719
commit bd33a93040
8 changed files with 316 additions and 17 deletions
+64 -5
View File
@@ -13,8 +13,8 @@ import {
MenuItem,
Typography,
Snackbar,
FormControlLabel,
Switch,
FormControlLabel,
} from "@mui/material";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import SettingsIcon from "@mui/icons-material/Settings";
@@ -30,6 +30,7 @@ import {
updateUserConfigurationsAsync,
setLanguage as setUserLanguage,
setTimezone as setUserTimeZone,
setAlarmEmails,
} from "../User/userSlice";
import { AVAILABLE_LANGUAGES } from "./constants";
import { useI18n } from "cozy-ui/transpiled/react/providers/I18n";
@@ -64,13 +65,16 @@ export default function SettingsPage() {
const isBrowserDefault = useAppSelector(
(state) => state.settings.isBrowserDefaultTimeZone
);
const alarmEmailsEnabled = useAppSelector(
(state) => state.user?.alarmEmailsEnabled ?? true
);
const [activeNavItem, setActiveNavItem] =
useState<SidebarNavItem>("settings");
const [activeSettingsSubTab, setActiveSettingsSubTab] =
useState<SettingsSubTab>("settings");
const [languageErrorOpen, setLanguageErrorOpen] = useState(false);
const [timeZoneErrorOpen, setTimeZoneErrorOpen] = useState(false);
const [alarmEmailsErrorOpen, setAlarmEmailsErrorOpen] = useState(false);
const handleBackClick = () => {
dispatch(setView("calendar"));
@@ -164,6 +168,30 @@ export default function SettingsPage() {
setTimeZoneErrorOpen(false);
};
const handleAlarmEmailsToggle = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const newValue = event.target.checked;
const previousValue = alarmEmailsEnabled;
// Optimistic update - update UI immediately
dispatch(setAlarmEmails(newValue));
// Call API in background, don't wait for it
dispatch(updateUserConfigurationsAsync({ alarmEmails: newValue }))
.unwrap()
.catch((error) => {
console.error("Failed to update alarm emails:", error);
// Rollback on error
dispatch(setAlarmEmails(previousValue));
setAlarmEmailsErrorOpen(true);
});
};
const handleAlarmEmailsErrorClose = () => {
setAlarmEmailsErrorOpen(false);
};
return (
<main className="main-layout settings-layout">
<Box className="settings-sidebar">
@@ -291,10 +319,32 @@ export default function SettingsPage() {
)}
{activeSettingsSubTab === "notifications" && (
<Box className="settings-tab-content">
<Typography variant="body1" color="text.secondary">
{t("settings.notifications.empty") ||
"Notifications settings coming soon"}
<Typography
variant="body2"
color="text.secondary"
sx={{ mb: 3 }}
>
{t("settings.notifications.deliveryMethod") ||
"Delivery method"}
</Typography>
<FormControlLabel
control={
<Switch
checked={alarmEmailsEnabled}
onChange={handleAlarmEmailsToggle}
aria-label={
t("settings.notifications.email") || "Email"
}
/>
}
label={t("settings.notifications.email") || "Email"}
labelPlacement="start"
sx={{
minWidth: 400,
justifyContent: "space-between",
marginLeft: 0,
}}
/>
</Box>
)}
</>
@@ -322,6 +372,15 @@ export default function SettingsPage() {
onClose={handleTimeZoneErrorClose}
message={t("settings.timeZoneUpdateError")}
/>
<Snackbar
open={alarmEmailsErrorOpen}
autoHideDuration={4000}
onClose={handleAlarmEmailsErrorClose}
message={
t("settings.alarmEmailsUpdateError") ||
"Failed to update email notifications setting"
}
/>
</main>
);
}