* [#340] show declined event in settings Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -77,6 +77,10 @@ export default function CalendarApp({
|
|||||||
}
|
}
|
||||||
}, [dispatch, tokens, userId]);
|
}, [dispatch, tokens, userId]);
|
||||||
const view = useAppSelector((state) => state.settings.view);
|
const view = useAppSelector((state) => state.settings.view);
|
||||||
|
const userData = useAppSelector((state) => state.user.userData);
|
||||||
|
const hideDeclinedEvents = useAppSelector(
|
||||||
|
(state) => state.settings.hideDeclinedEvents
|
||||||
|
);
|
||||||
const calendars = useAppSelector((state) => state.calendars.list);
|
const calendars = useAppSelector((state) => state.calendars.list);
|
||||||
const tempcalendars = useAppSelector((state) => state.calendars.templist);
|
const tempcalendars = useAppSelector((state) => state.calendars.templist);
|
||||||
const [selectedCalendars, setSelectedCalendars] = useState<string[]>([]);
|
const [selectedCalendars, setSelectedCalendars] = useState<string[]>([]);
|
||||||
@@ -221,7 +225,9 @@ export default function CalendarApp({
|
|||||||
|
|
||||||
let filteredEvents: CalendarEvent[] = extractEvents(
|
let filteredEvents: CalendarEvent[] = extractEvents(
|
||||||
selectedCalendars,
|
selectedCalendars,
|
||||||
calendars || {}
|
calendars || {},
|
||||||
|
userData?.email,
|
||||||
|
hideDeclinedEvents
|
||||||
);
|
);
|
||||||
|
|
||||||
const tempCalendarIds = useMemo(
|
const tempCalendarIds = useMemo(
|
||||||
@@ -231,7 +237,9 @@ export default function CalendarApp({
|
|||||||
|
|
||||||
let filteredTempEvents: CalendarEvent[] = extractEvents(
|
let filteredTempEvents: CalendarEvent[] = extractEvents(
|
||||||
tempCalendarIds,
|
tempCalendarIds,
|
||||||
tempcalendars || {}
|
tempcalendars || {},
|
||||||
|
userData?.email,
|
||||||
|
hideDeclinedEvents
|
||||||
);
|
);
|
||||||
|
|
||||||
const sortedSelectedCalendars = useMemo(
|
const sortedSelectedCalendars = useMemo(
|
||||||
|
|||||||
@@ -138,21 +138,30 @@ export const eventToFullCalendarFormat = (
|
|||||||
|
|
||||||
export const extractEvents = (
|
export const extractEvents = (
|
||||||
selectedCalendars: string[],
|
selectedCalendars: string[],
|
||||||
calendars: Record<string, Calendars>
|
calendars: Record<string, Calendars>,
|
||||||
|
userAddress?: string,
|
||||||
|
hideDeclinedEvents?: boolean | null
|
||||||
) => {
|
) => {
|
||||||
let filteredEvents: CalendarEvent[] = [];
|
const allEvents: CalendarEvent[] = [];
|
||||||
|
|
||||||
selectedCalendars.forEach((id) => {
|
selectedCalendars.forEach((id) => {
|
||||||
if (calendars[id] && calendars[id].events) {
|
const calendar = calendars[id];
|
||||||
filteredEvents = filteredEvents
|
if (calendar?.events) {
|
||||||
.concat(
|
allEvents.push(...Object.values(calendar.events));
|
||||||
Object.keys(calendars[id].events).map(
|
|
||||||
(eventid) => calendars[id].events[eventid]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.filter((event) => !(event.status === "CANCELLED"));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return filteredEvents;
|
|
||||||
|
return allEvents
|
||||||
|
.filter((event) => event.status !== "CANCELLED")
|
||||||
|
.filter(
|
||||||
|
(event) =>
|
||||||
|
!(
|
||||||
|
hideDeclinedEvents &&
|
||||||
|
event.attendee?.some(
|
||||||
|
(a) => a.cal_address === userAddress && a.partstat === "DECLINED"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateCalsDetails = (
|
export const updateCalsDetails = (
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
setLanguage as setSettingsLanguage,
|
setLanguage as setSettingsLanguage,
|
||||||
setTimeZone as setSettingsTimeZone,
|
setTimeZone as setSettingsTimeZone,
|
||||||
setIsBrowserDefaultTimeZone,
|
setIsBrowserDefaultTimeZone,
|
||||||
|
setHideDeclinedEvents,
|
||||||
} from "./SettingsSlice";
|
} from "./SettingsSlice";
|
||||||
import {
|
import {
|
||||||
updateUserConfigurationsAsync,
|
updateUserConfigurationsAsync,
|
||||||
@@ -68,6 +69,11 @@ export default function SettingsPage() {
|
|||||||
const alarmEmailsEnabled = useAppSelector(
|
const alarmEmailsEnabled = useAppSelector(
|
||||||
(state) => state.user?.alarmEmailsEnabled ?? true
|
(state) => state.user?.alarmEmailsEnabled ?? true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hideDeclinedEvents = useAppSelector(
|
||||||
|
(state) => state.settings?.hideDeclinedEvents
|
||||||
|
);
|
||||||
|
|
||||||
const [activeNavItem, setActiveNavItem] =
|
const [activeNavItem, setActiveNavItem] =
|
||||||
useState<SidebarNavItem>("settings");
|
useState<SidebarNavItem>("settings");
|
||||||
const [activeSettingsSubTab, setActiveSettingsSubTab] =
|
const [activeSettingsSubTab, setActiveSettingsSubTab] =
|
||||||
@@ -75,6 +81,8 @@ export default function SettingsPage() {
|
|||||||
const [languageErrorOpen, setLanguageErrorOpen] = useState(false);
|
const [languageErrorOpen, setLanguageErrorOpen] = useState(false);
|
||||||
const [timeZoneErrorOpen, setTimeZoneErrorOpen] = useState(false);
|
const [timeZoneErrorOpen, setTimeZoneErrorOpen] = useState(false);
|
||||||
const [alarmEmailsErrorOpen, setAlarmEmailsErrorOpen] = useState(false);
|
const [alarmEmailsErrorOpen, setAlarmEmailsErrorOpen] = useState(false);
|
||||||
|
const [hideDeclinedEventsErrorOpen, setHideDeclinedEventsErrorOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
const handleBackClick = () => {
|
const handleBackClick = () => {
|
||||||
dispatch(setView("calendar"));
|
dispatch(setView("calendar"));
|
||||||
@@ -168,6 +176,27 @@ export default function SettingsPage() {
|
|||||||
setTimeZoneErrorOpen(false);
|
setTimeZoneErrorOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleHideDeclinedEvents = (doHideDeclinedEvents: boolean) => {
|
||||||
|
// Optimistic update - update UI immediately
|
||||||
|
dispatch(setHideDeclinedEvents(doHideDeclinedEvents));
|
||||||
|
|
||||||
|
// Call API in background, don't wait for it
|
||||||
|
dispatch(
|
||||||
|
updateUserConfigurationsAsync({
|
||||||
|
hideDeclinedEvents: doHideDeclinedEvents,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Failed to update hide declined event:", error);
|
||||||
|
dispatch(setHideDeclinedEvents(!doHideDeclinedEvents));
|
||||||
|
setHideDeclinedEventsErrorOpen(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleHideDeclinedEventsErrorClose = () => {
|
||||||
|
setHideDeclinedEventsErrorOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleAlarmEmailsToggle = (
|
const handleAlarmEmailsToggle = (
|
||||||
event: React.ChangeEvent<HTMLInputElement>
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
) => {
|
) => {
|
||||||
@@ -315,6 +344,38 @@ export default function SettingsPage() {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h6" sx={{ mb: 1 }}>
|
||||||
|
{t("settings.calAndEvent")}
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
mb: 6,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormControl size="small" sx={{ minWidth: 500 }}>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={Boolean(!hideDeclinedEvents)}
|
||||||
|
onChange={() =>
|
||||||
|
handleHideDeclinedEvents(!hideDeclinedEvents)
|
||||||
|
}
|
||||||
|
aria-label={t("settings.showDeclinedEvent")}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={t("settings.showDeclinedEvent")}
|
||||||
|
labelPlacement="start"
|
||||||
|
sx={{
|
||||||
|
minWidth: 400,
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginLeft: 0,
|
||||||
|
mb: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{activeSettingsSubTab === "notifications" && (
|
{activeSettingsSubTab === "notifications" && (
|
||||||
@@ -381,6 +442,13 @@ export default function SettingsPage() {
|
|||||||
"Failed to update email notifications setting"
|
"Failed to update email notifications setting"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Snackbar
|
||||||
|
open={hideDeclinedEventsErrorOpen}
|
||||||
|
autoHideDuration={4000}
|
||||||
|
onClose={handleHideDeclinedEventsErrorClose}
|
||||||
|
message={t("settings.hideDeclinedEventsUpdateError")}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface SettingsState {
|
|||||||
language: string;
|
language: string;
|
||||||
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;
|
||||||
view: "calendar" | "settings" | "search";
|
view: "calendar" | "settings" | "search";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ const initialState: SettingsState = {
|
|||||||
language: defaultLang,
|
language: defaultLang,
|
||||||
timeZone: defaultTimeZone,
|
timeZone: defaultTimeZone,
|
||||||
isBrowserDefaultTimeZone: defaultTimeZone === null,
|
isBrowserDefaultTimeZone: defaultTimeZone === null,
|
||||||
|
hideDeclinedEvents: null,
|
||||||
view: "calendar",
|
view: "calendar",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,6 +41,9 @@ export const settingsSlice = createSlice({
|
|||||||
setIsBrowserDefaultTimeZone: (state, action: PayloadAction<boolean>) => {
|
setIsBrowserDefaultTimeZone: (state, action: PayloadAction<boolean>) => {
|
||||||
state.isBrowserDefaultTimeZone = action.payload;
|
state.isBrowserDefaultTimeZone = action.payload;
|
||||||
},
|
},
|
||||||
|
setHideDeclinedEvents: (state, action: PayloadAction<boolean | null>) => {
|
||||||
|
state.hideDeclinedEvents = action.payload;
|
||||||
|
},
|
||||||
setView: (
|
setView: (
|
||||||
state,
|
state,
|
||||||
action: PayloadAction<"calendar" | "settings" | "search">
|
action: PayloadAction<"calendar" | "settings" | "search">
|
||||||
@@ -65,6 +70,16 @@ export const settingsSlice = createSlice({
|
|||||||
state.isBrowserDefaultTimeZone = true;
|
state.isBrowserDefaultTimeZone = true;
|
||||||
localStorage.setItem("timeZone", browserDefaultTimeZone);
|
localStorage.setItem("timeZone", browserDefaultTimeZone);
|
||||||
}
|
}
|
||||||
|
const esnCalendarModule = action.payload.configurations?.modules?.find(
|
||||||
|
(module: any) => module.name === "linagora.esn.calendar"
|
||||||
|
);
|
||||||
|
const hideDeclinedEventsConfig = esnCalendarModule?.configurations?.find(
|
||||||
|
(config: any) => config.name === "hideDeclinedEvents"
|
||||||
|
);
|
||||||
|
state.hideDeclinedEvents =
|
||||||
|
typeof hideDeclinedEventsConfig?.value === "boolean"
|
||||||
|
? hideDeclinedEventsConfig.value
|
||||||
|
: null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -74,5 +89,6 @@ export const {
|
|||||||
setTimeZone,
|
setTimeZone,
|
||||||
setView,
|
setView,
|
||||||
setIsBrowserDefaultTimeZone,
|
setIsBrowserDefaultTimeZone,
|
||||||
|
setHideDeclinedEvents,
|
||||||
} = settingsSlice.actions;
|
} = settingsSlice.actions;
|
||||||
export default settingsSlice.reducer;
|
export default settingsSlice.reducer;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export interface UserConfigurationUpdates {
|
|||||||
timezone?: string | null;
|
timezone?: string | null;
|
||||||
previousConfig?: Record<string, any>;
|
previousConfig?: Record<string, any>;
|
||||||
alarmEmails?: boolean;
|
alarmEmails?: boolean;
|
||||||
|
hideDeclinedEvents?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateUserConfigurations(
|
export async function updateUserConfigurations(
|
||||||
@@ -47,6 +48,7 @@ export async function updateUserConfigurations(
|
|||||||
): Promise<Response | { status: number }> {
|
): Promise<Response | { status: number }> {
|
||||||
const coreConfigs: Array<{ name: string; value: any }> = [];
|
const coreConfigs: Array<{ name: string; value: any }> = [];
|
||||||
const calendarConfigs: Array<{ name: string; value: any }> = [];
|
const calendarConfigs: Array<{ name: string; value: any }> = [];
|
||||||
|
const esnCalendarConfigs: Array<{ name: string; value: any }> = [];
|
||||||
|
|
||||||
if (updates.language !== undefined) {
|
if (updates.language !== undefined) {
|
||||||
coreConfigs.push({ name: "language", value: updates.language });
|
coreConfigs.push({ name: "language", value: updates.language });
|
||||||
@@ -69,6 +71,12 @@ export async function updateUserConfigurations(
|
|||||||
value: updates.alarmEmails,
|
value: updates.alarmEmails,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (updates.hideDeclinedEvents !== undefined) {
|
||||||
|
esnCalendarConfigs.push({
|
||||||
|
name: "hideDeclinedEvents",
|
||||||
|
value: updates.hideDeclinedEvents,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const modules: Array<{
|
const modules: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
@@ -88,6 +96,12 @@ export async function updateUserConfigurations(
|
|||||||
configurations: calendarConfigs,
|
configurations: calendarConfigs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (esnCalendarConfigs.length > 0) {
|
||||||
|
modules.push({
|
||||||
|
name: "linagora.esn.calendar",
|
||||||
|
configurations: esnCalendarConfigs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (modules.length === 0) {
|
if (modules.length === 0) {
|
||||||
return Promise.resolve({ status: 204 });
|
return Promise.resolve({ status: 204 });
|
||||||
|
|||||||
@@ -221,6 +221,9 @@
|
|||||||
"notifications.deliveryMethod": "Delivery method",
|
"notifications.deliveryMethod": "Delivery method",
|
||||||
"alarmEmailsUpdateError": "Failed to update email notifications setting",
|
"alarmEmailsUpdateError": "Failed to update email notifications setting",
|
||||||
"sync.empty": "Sync settings coming soon",
|
"sync.empty": "Sync settings coming soon",
|
||||||
|
"calAndEvent": "Calendar and events",
|
||||||
|
"showDeclinedEvent": "Show declined events",
|
||||||
|
"hideDeclinedEventsUpdateError": "Failed to update hide declined event.",
|
||||||
"back": "Back to calendar"
|
"back": "Back to calendar"
|
||||||
},
|
},
|
||||||
"eventPreview": {
|
"eventPreview": {
|
||||||
|
|||||||
@@ -221,6 +221,9 @@
|
|||||||
"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",
|
||||||
"sync.empty": "Paramètres de synchronisation à venir",
|
"sync.empty": "Paramètres de synchronisation à venir",
|
||||||
|
"calAndEvent": "Calendrier et événements",
|
||||||
|
"showDeclinedEvent": "Afficher les événements déclinés",
|
||||||
|
"hideDeclinedEventsUpdateError": "Échec de la mise à jour du masquage des événements déclinés.",
|
||||||
"back": "Retour au calendrier"
|
"back": "Retour au calendrier"
|
||||||
},
|
},
|
||||||
"eventPreview": {
|
"eventPreview": {
|
||||||
|
|||||||
@@ -221,6 +221,9 @@
|
|||||||
"notifications.deliveryMethod": "Способ доставки",
|
"notifications.deliveryMethod": "Способ доставки",
|
||||||
"alarmEmailsUpdateError": "Не удалось обновить настройки уведомлений по email",
|
"alarmEmailsUpdateError": "Не удалось обновить настройки уведомлений по email",
|
||||||
"sync.empty": "Настройки синхронизации скоро появятся",
|
"sync.empty": "Настройки синхронизации скоро появятся",
|
||||||
|
"calAndEvent": "Календарь и мероприятия",
|
||||||
|
"showDeclinedEvent": "Показать отклонённые мероприятия",
|
||||||
|
"hideDeclinedEventsUpdateError": "Не удалось обновить скрытие отклонённых событий.",
|
||||||
"back": "Вернуться к календарю"
|
"back": "Вернуться к календарю"
|
||||||
},
|
},
|
||||||
"eventPreview": {
|
"eventPreview": {
|
||||||
|
|||||||
@@ -221,6 +221,9 @@
|
|||||||
"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",
|
||||||
"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",
|
||||||
|
"showDeclinedEvent": "Hiển thị các sự kiện đã từ chối",
|
||||||
|
"hideDeclinedEventsUpdateError": "Không cập nhật được các sự kiện ẩn bị từ chối.",
|
||||||
"back": "Quay lại lịch"
|
"back": "Quay lại lịch"
|
||||||
},
|
},
|
||||||
"eventPreview": {
|
"eventPreview": {
|
||||||
|
|||||||
Reference in New Issue
Block a user