[#341] added show week number toggle (#399)

* [#341] added show week number toggle
This commit is contained in:
Camille Moussu
2025-12-11 11:41:38 +01:00
committed by GitHub
parent 3cb445ea79
commit e8b1b72901
8 changed files with 114 additions and 32 deletions
+8 -3
View File
@@ -82,6 +82,9 @@ export default function CalendarApp({
(state) => state.settings.hideDeclinedEvents (state) => state.settings.hideDeclinedEvents
); );
const calendars = useAppSelector((state) => state.calendars.list); const calendars = useAppSelector((state) => state.calendars.list);
const displayWeekNumbers = useAppSelector(
(state) => state.settings.displayWeekNumbers
);
const tempcalendars = useAppSelector((state) => state.calendars.templist); const tempcalendars = useAppSelector((state) => state.calendars.templist);
const [selectedCalendars, setSelectedCalendars] = useState<string[]>([]); const [selectedCalendars, setSelectedCalendars] = useState<string[]>([]);
@@ -689,9 +692,11 @@ export default function CalendarApp({
weekNumberContent={(arg) => { weekNumberContent={(arg) => {
return ( return (
<div className="weekSelector"> <div className="weekSelector">
<div> {displayWeekNumbers && (
{t("menubar.views.week")} {arg.num} <div>
</div> {t("menubar.views.week")} {arg.num}
</div>
)}
<TimezoneSelector <TimezoneSelector
value={timezone} value={timezone}
referenceDate={calendarRef.current?.getDate() ?? new Date()} referenceDate={calendarRef.current?.getDate() ?? new Date()}
+73 -29
View File
@@ -26,6 +26,7 @@ import {
setTimeZone as setSettingsTimeZone, setTimeZone as setSettingsTimeZone,
setIsBrowserDefaultTimeZone, setIsBrowserDefaultTimeZone,
setHideDeclinedEvents, setHideDeclinedEvents,
setDisplayWeekNumbers,
} from "./SettingsSlice"; } from "./SettingsSlice";
import { import {
updateUserConfigurationsAsync, updateUserConfigurationsAsync,
@@ -74,6 +75,10 @@ export default function SettingsPage() {
(state) => state.settings?.hideDeclinedEvents (state) => state.settings?.hideDeclinedEvents
); );
const displayWeekNumbers = useAppSelector(
(state) => state.settings?.displayWeekNumbers
);
const [activeNavItem, setActiveNavItem] = const [activeNavItem, setActiveNavItem] =
useState<SidebarNavItem>("settings"); useState<SidebarNavItem>("settings");
const [activeSettingsSubTab, setActiveSettingsSubTab] = const [activeSettingsSubTab, setActiveSettingsSubTab] =
@@ -83,7 +88,8 @@ export default function SettingsPage() {
const [alarmEmailsErrorOpen, setAlarmEmailsErrorOpen] = useState(false); const [alarmEmailsErrorOpen, setAlarmEmailsErrorOpen] = useState(false);
const [hideDeclinedEventsErrorOpen, setHideDeclinedEventsErrorOpen] = const [hideDeclinedEventsErrorOpen, setHideDeclinedEventsErrorOpen] =
useState(false); useState(false);
const [displayWeekNumbersErrorOpen, setDisplayWeekNumbersErrorOpen] =
useState(false);
const handleBackClick = () => { const handleBackClick = () => {
dispatch(setView("calendar")); dispatch(setView("calendar"));
}; };
@@ -221,6 +227,27 @@ export default function SettingsPage() {
setAlarmEmailsErrorOpen(false); setAlarmEmailsErrorOpen(false);
}; };
const handleDisplayWeekNumbers = (doDisplayWeekNumbers: boolean) => {
// Optimistic update - update UI immediately
dispatch(setDisplayWeekNumbers(doDisplayWeekNumbers));
// Call API in background, don't wait for it
dispatch(
updateUserConfigurationsAsync({
displayWeekNumbers: doDisplayWeekNumbers,
})
)
.unwrap()
.catch((error) => {
console.error("Failed to update the week number setting:", error);
dispatch(setDisplayWeekNumbers(!doDisplayWeekNumbers));
setDisplayWeekNumbersErrorOpen(true);
});
};
const handleDisplayWeekNumbersErrorClose = () => {
setDisplayWeekNumbersErrorOpen(false);
};
return ( return (
<main className="main-layout settings-layout"> <main className="main-layout settings-layout">
<Box className="settings-sidebar"> <Box className="settings-sidebar">
@@ -344,37 +371,48 @@ export default function SettingsPage() {
</FormControl> </FormControl>
</Box> </Box>
</Box> </Box>
<Box> <Box sx={{ mb: 6 }}>
<Typography variant="h6" sx={{ mb: 1 }}> <Typography variant="h6" sx={{ mb: 1 }}>
{t("settings.calAndEvent")} {t("settings.calAndEvent")}
</Typography> </Typography>
<Box <FormControl size="small" sx={{ minWidth: 500 }}>
sx={{ <FormControlLabel
mb: 6, control={
}} <Switch
> checked={Boolean(!hideDeclinedEvents)}
<FormControl size="small" sx={{ minWidth: 500 }}> onChange={() =>
<FormControlLabel handleHideDeclinedEvents(!hideDeclinedEvents)
control={ }
<Switch aria-label={t("settings.showDeclinedEvent")}
checked={Boolean(!hideDeclinedEvents)} />
onChange={() => }
handleHideDeclinedEvents(!hideDeclinedEvents) label={t("settings.showDeclinedEvent")}
} labelPlacement="start"
aria-label={t("settings.showDeclinedEvent")} sx={{
/> minWidth: 400,
} justifyContent: "space-between",
label={t("settings.showDeclinedEvent")} marginLeft: 0,
labelPlacement="start" }}
sx={{ />
minWidth: 400, <FormControlLabel
justifyContent: "space-between", control={
marginLeft: 0, <Switch
mb: 2, checked={Boolean(displayWeekNumbers)}
}} onChange={() =>
/> handleDisplayWeekNumbers(!displayWeekNumbers)
</FormControl> }
</Box> aria-label={t("settings.displayWeekNumbers")}
/>
}
label={t("settings.displayWeekNumbers")}
labelPlacement="start"
sx={{
minWidth: 400,
justifyContent: "space-between",
marginLeft: 0,
}}
/>
</FormControl>
</Box> </Box>
</Box> </Box>
)} )}
@@ -449,6 +487,12 @@ export default function SettingsPage() {
onClose={handleHideDeclinedEventsErrorClose} onClose={handleHideDeclinedEventsErrorClose}
message={t("settings.hideDeclinedEventsUpdateError")} message={t("settings.hideDeclinedEventsUpdateError")}
/> />
<Snackbar
open={displayWeekNumbersErrorOpen}
autoHideDuration={4000}
onClose={handleDisplayWeekNumbersErrorClose}
message={t("settings.displayWeekNumbersUpdateError")}
/>
</main> </main>
); );
} }
+18
View File
@@ -7,6 +7,7 @@ export interface SettingsState {
timeZone: string | null; // Allow null to represent browser default timeZone: string | null; // Allow null to represent browser default
isBrowserDefaultTimeZone: boolean; isBrowserDefaultTimeZone: boolean;
hideDeclinedEvents: boolean | null; hideDeclinedEvents: boolean | null;
displayWeekNumbers: boolean;
view: "calendar" | "settings" | "search"; view: "calendar" | "settings" | "search";
} }
@@ -23,6 +24,7 @@ const initialState: SettingsState = {
timeZone: defaultTimeZone, timeZone: defaultTimeZone,
isBrowserDefaultTimeZone: defaultTimeZone === null, isBrowserDefaultTimeZone: defaultTimeZone === null,
hideDeclinedEvents: null, hideDeclinedEvents: null,
displayWeekNumbers: true,
view: "calendar", view: "calendar",
}; };
@@ -44,6 +46,9 @@ export const settingsSlice = createSlice({
setHideDeclinedEvents: (state, action: PayloadAction<boolean | null>) => { setHideDeclinedEvents: (state, action: PayloadAction<boolean | null>) => {
state.hideDeclinedEvents = action.payload; state.hideDeclinedEvents = action.payload;
}, },
setDisplayWeekNumbers: (state, action: PayloadAction<boolean>) => {
state.displayWeekNumbers = action.payload;
},
setView: ( setView: (
state, state,
action: PayloadAction<"calendar" | "settings" | "search"> action: PayloadAction<"calendar" | "settings" | "search">
@@ -80,6 +85,18 @@ export const settingsSlice = createSlice({
typeof hideDeclinedEventsConfig?.value === "boolean" typeof hideDeclinedEventsConfig?.value === "boolean"
? hideDeclinedEventsConfig.value ? hideDeclinedEventsConfig.value
: null; : null;
const calendarModule = action.payload.configurations.modules.find(
(module: any) => module.name === "calendar"
);
if (calendarModule?.configurations) {
const alarmEmailsConfig = calendarModule.configurations.find(
(config: any) => config.name === "displayWeekNumbers"
);
if (alarmEmailsConfig) {
state.displayWeekNumbers = alarmEmailsConfig.value === true;
}
}
}); });
}, },
}); });
@@ -90,5 +107,6 @@ export const {
setView, setView,
setIsBrowserDefaultTimeZone, setIsBrowserDefaultTimeZone,
setHideDeclinedEvents, setHideDeclinedEvents,
setDisplayWeekNumbers,
} = settingsSlice.actions; } = settingsSlice.actions;
export default settingsSlice.reducer; export default settingsSlice.reducer;
+7
View File
@@ -38,6 +38,7 @@ export interface UserConfigurationUpdates {
language?: string; language?: string;
notifications?: Record<string, unknown>; notifications?: Record<string, unknown>;
timezone?: string | null; timezone?: string | null;
displayWeekNumbers?: boolean;
previousConfig?: Record<string, any>; previousConfig?: Record<string, any>;
alarmEmails?: boolean; alarmEmails?: boolean;
hideDeclinedEvents?: boolean; hideDeclinedEvents?: boolean;
@@ -77,6 +78,12 @@ export async function updateUserConfigurations(
value: updates.hideDeclinedEvents, value: updates.hideDeclinedEvents,
}); });
} }
if (updates.displayWeekNumbers !== undefined) {
calendarConfigs.push({
name: "displayWeekNumbers",
value: updates.displayWeekNumbers,
});
}
const modules: Array<{ const modules: Array<{
name: string; name: string;
+2
View File
@@ -220,6 +220,8 @@
"notifications.email": "Email", "notifications.email": "Email",
"notifications.deliveryMethod": "Delivery method", "notifications.deliveryMethod": "Delivery method",
"alarmEmailsUpdateError": "Failed to update email notifications setting", "alarmEmailsUpdateError": "Failed to update email notifications setting",
"displayWeekNumbers": "Show week number",
"displayWeekNumbersUpdateError": "Failed to update show week number",
"sync.empty": "Sync settings coming soon", "sync.empty": "Sync settings coming soon",
"calAndEvent": "Calendar and events", "calAndEvent": "Calendar and events",
"showDeclinedEvent": "Show declined events", "showDeclinedEvent": "Show declined events",
+2
View File
@@ -220,6 +220,8 @@
"notifications.email": "Email", "notifications.email": "Email",
"notifications.deliveryMethod": "Mode de réception", "notifications.deliveryMethod": "Mode de réception",
"alarmEmailsUpdateError": "Échec de la mise à jour du mode de notification par e-mail", "alarmEmailsUpdateError": "Échec de la mise à jour du mode de notification par e-mail",
"displayWeekNumbers": "Afficher le numéro de la semaine",
"displayWeekNumbersUpdateError": "Échec de la mise à jour de l'affichage du numéro de la semaine",
"sync.empty": "Paramètres de synchronisation à venir", "sync.empty": "Paramètres de synchronisation à venir",
"calAndEvent": "Calendrier et événements", "calAndEvent": "Calendrier et événements",
"showDeclinedEvent": "Afficher les événements déclinés", "showDeclinedEvent": "Afficher les événements déclinés",
+2
View File
@@ -220,6 +220,8 @@
"notifications.email": "Email", "notifications.email": "Email",
"notifications.deliveryMethod": "Способ доставки", "notifications.deliveryMethod": "Способ доставки",
"alarmEmailsUpdateError": "Не удалось обновить настройки уведомлений по email", "alarmEmailsUpdateError": "Не удалось обновить настройки уведомлений по email",
"displayWeekNumbers": "Показать номер недели",
"displayWeekNumbersUpdateError": "Не удалось обновить отображение номера недели",
"sync.empty": "Настройки синхронизации скоро появятся", "sync.empty": "Настройки синхронизации скоро появятся",
"calAndEvent": "Календарь и мероприятия", "calAndEvent": "Календарь и мероприятия",
"showDeclinedEvent": "Показать отклонённые мероприятия", "showDeclinedEvent": "Показать отклонённые мероприятия",
+2
View File
@@ -220,6 +220,8 @@
"notifications.email": "Email", "notifications.email": "Email",
"notifications.deliveryMethod": "Phương thức gửi", "notifications.deliveryMethod": "Phương thức gửi",
"alarmEmailsUpdateError": "Cập nhật cài đặt thông báo email thất bại", "alarmEmailsUpdateError": "Cập nhật cài đặt thông báo email thất bại",
"displayWeekNumbers": "Hiển thị số tuần",
"displayWeekNumbersUpdateError": "Không cập nhật được cách hiển thị số tuần",
"sync.empty": "Cài đặt đồng bộ sắp có", "sync.empty": "Cài đặt đồng bộ sắp có",
"calAndEvent": "Lịch và sự kiện", "calAndEvent": "Lịch và sự kiện",
"showDeclinedEvent": "Hiển thị các sự kiện đã từ chối", "showDeclinedEvent": "Hiển thị các sự kiện đã từ chối",