feat: persist sidebar toggle settings per-device via cookies
The sidebar eye-toggles (Someday, All-day, Checkboxes, Project Icons, Weather) and the sub-hour slots toggle now save to a device-local cookie instead of the DB, so phone and desktop can have independent display preferences. - DEVICE_SETTINGS_KEYS extended with showSubHourSlots - New DEVICE_VIEW_SETTINGS_KEYS for per-view sidebar toggles (showSomeday, showAllDayEvents, showTaskCheckboxes, showProjectIcons, weatherEnabled) - saveViewSetting writes cookie-only for device keys; DB untouched - getEffective checks device cookie before DB per-view overrides - Cookie restores applied after DB load in both fetchProfile and fetchUserInfo so device preference always wins v1.94.0
This commit is contained in:
parent
36744d0e09
commit
0b40974b88
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.93.1",
|
||||
"version": "1.94.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -110,7 +110,12 @@ const RichTextEditor = dynamic(() => import("./RichTextEditor"), { ssr: false })
|
||||
const PriorityView = dynamic(() => import("./PriorityView"), { ssr: false });
|
||||
|
||||
// Cookie helpers for per-device settings
|
||||
const DEVICE_SETTINGS_KEYS = ["viewDays", "cellDuration", "startHour", "endHour", "fontSize"];
|
||||
// Keys here bypass the DB and save/load from cookie only — each device keeps its own value
|
||||
const DEVICE_SETTINGS_KEYS = ["viewDays", "cellDuration", "startHour", "endHour", "fontSize", "showSubHourSlots"];
|
||||
|
||||
// Per-view toggle keys that are also device-specific (sidebar eye toggles)
|
||||
const DEVICE_VIEW_SETTINGS_KEYS = ["showSomeday", "showAllDayEvents", "showTaskCheckboxes", "showProjectIcons", "weatherEnabled"] as const;
|
||||
type DeviceViewSettingKey = typeof DEVICE_VIEW_SETTINGS_KEYS[number];
|
||||
|
||||
function getCookie(name: string): string | null {
|
||||
if (typeof document === "undefined") return null;
|
||||
@ -124,6 +129,16 @@ function setCookie(name: string, value: string, days: number = 365) {
|
||||
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/; SameSite=Lax`;
|
||||
}
|
||||
|
||||
function readDeviceViewCookie(): Record<string, Record<string, any>> {
|
||||
const raw = getCookie("device_view_settings");
|
||||
if (!raw) return {};
|
||||
try { return JSON.parse(raw); } catch { return {}; }
|
||||
}
|
||||
|
||||
function writeDeviceViewCookie(settings: Record<string, Record<string, any>>) {
|
||||
setCookie("device_view_settings", JSON.stringify(settings));
|
||||
}
|
||||
|
||||
export type ViewStyle = "simple" | "calendar" | "list" | "grid" | "kanban" | "priority";
|
||||
|
||||
export interface KanbanStage {
|
||||
@ -611,7 +626,10 @@ export default function WeeklyView() {
|
||||
const [timeFormat, setTimeFormat] = useState("24h");
|
||||
const [dateFormat, setDateFormat] = useState("yyyy-MM-dd");
|
||||
const [hourLabelFormat, setHourLabelFormat] = useState<"short" | "full">("short");
|
||||
const [showSubHourSlots, setShowSubHourSlots] = useState(true);
|
||||
const [showSubHourSlots, setShowSubHourSlots] = useState<boolean>(() => {
|
||||
const c = getCookie("setting_showSubHourSlots");
|
||||
return c !== null ? c === "true" : true;
|
||||
});
|
||||
const [allDayPosition, setAllDayPosition] = useState<"above" | "below">("below");
|
||||
|
||||
const [somedayExpanded, setSomedayExpanded] = useState(true);
|
||||
@ -1023,7 +1041,17 @@ export default function WeeklyView() {
|
||||
const viewSettingsRef = useRef<Record<string, PerViewOverrides>>({});
|
||||
viewSettingsRef.current = viewSettings;
|
||||
|
||||
// Device-local per-view overrides (cookie-based, not synced to DB)
|
||||
const [deviceViewSettings, setDeviceViewSettings] = useState<Record<string, Record<string, any>>>(() => readDeviceViewCookie());
|
||||
const deviceViewSettingsRef = useRef<Record<string, Record<string, any>>>({});
|
||||
deviceViewSettingsRef.current = deviceViewSettings;
|
||||
|
||||
const getEffective = <K extends keyof PerViewOverrides>(key: K, globalVal: PerViewOverrides[K]): PerViewOverrides[K] => {
|
||||
// Device-specific settings take priority (cookie-based, not synced across devices)
|
||||
if ((DEVICE_VIEW_SETTINGS_KEYS as readonly string[]).includes(key)) {
|
||||
const dvs = deviceViewSettingsRef.current[profile.viewStyle];
|
||||
if (dvs && dvs[key] !== undefined) return dvs[key] as PerViewOverrides[K];
|
||||
}
|
||||
const vs = viewSettingsRef.current[profile.viewStyle];
|
||||
if (vs && vs[key] !== undefined) return vs[key] as PerViewOverrides[K];
|
||||
return globalVal;
|
||||
@ -1033,6 +1061,15 @@ export default function WeeklyView() {
|
||||
return !!(vs && vs[key] !== undefined);
|
||||
};
|
||||
const saveViewSetting = async <K extends keyof PerViewOverrides>(key: K, value: PerViewOverrides[K], perView: boolean) => {
|
||||
// Device-specific keys: save to cookie only, not DB
|
||||
if ((DEVICE_VIEW_SETTINGS_KEYS as readonly string[]).includes(key) && perView) {
|
||||
const dvs = { ...deviceViewSettingsRef.current };
|
||||
dvs[profile.viewStyle] = { ...(dvs[profile.viewStyle] || {}), [key]: value };
|
||||
deviceViewSettingsRef.current = dvs;
|
||||
setDeviceViewSettings(dvs);
|
||||
writeDeviceViewCookie(dvs);
|
||||
return;
|
||||
}
|
||||
const updated = { ...viewSettingsRef.current };
|
||||
if (perView) {
|
||||
updated[profile.viewStyle] = { ...(updated[profile.viewStyle] || {}), [key]: value };
|
||||
@ -1359,6 +1396,18 @@ export default function WeeklyView() {
|
||||
}
|
||||
}
|
||||
|
||||
// Re-apply per-device cookie overrides — these always win over DB values
|
||||
const _cFS = getCookie("setting_fontSize");
|
||||
if (_cFS) setFontSize(_cFS as "S" | "M" | "L");
|
||||
const _cSH = getCookie("setting_showSubHourSlots");
|
||||
if (_cSH !== null) setShowSubHourSlots(_cSH === "true");
|
||||
const _cCD = getCookie("setting_cellDuration");
|
||||
if (_cCD) setCellDuration(Number(_cCD) as CellDuration);
|
||||
const _cStart = getCookie("setting_startHour");
|
||||
if (_cStart) setStartHour(Number(_cStart));
|
||||
const _cEnd = getCookie("setting_endHour");
|
||||
if (_cEnd) setEndHour(Number(_cEnd));
|
||||
|
||||
// Show onboarding wizard for new users
|
||||
if (profileData.hasCompletedOnboarding === false) {
|
||||
setShowOnboarding(true);
|
||||
@ -2349,12 +2398,13 @@ export default function WeeklyView() {
|
||||
if (cookieStartHour) setStartHour(Number(cookieStartHour));
|
||||
const cookieEndHour = getCookie("setting_endHour");
|
||||
if (cookieEndHour) setEndHour(Number(cookieEndHour));
|
||||
const cookieFontSize = getCookie("setting_fontSize");
|
||||
if (cookieFontSize) setFontSize(cookieFontSize as "S" | "M" | "L");
|
||||
setShowNextTask(data.user.showNextTask || false);
|
||||
setCalendarEditMode(data.user.calendarEditMode || false);
|
||||
if (data.user.fontSize)
|
||||
setFontSize(data.user.fontSize as "S" | "M" | "L");
|
||||
// Cookie wins over DB for per-device settings
|
||||
const cookieFontSize2 = getCookie("setting_fontSize");
|
||||
if (cookieFontSize2) setFontSize(cookieFontSize2 as "S" | "M" | "L");
|
||||
|
||||
if (data.user.showSomeday !== undefined)
|
||||
setShowSomeday(data.user.showSomeday);
|
||||
@ -2372,6 +2422,9 @@ export default function WeeklyView() {
|
||||
setHourLabelFormat(data.user.hourLabelFormat as "short" | "full");
|
||||
if (data.user.showSubHourSlots !== undefined)
|
||||
setShowSubHourSlots(data.user.showSubHourSlots);
|
||||
// Cookie wins over DB for showSubHourSlots (per-device)
|
||||
const _cSH2 = getCookie("setting_showSubHourSlots");
|
||||
if (_cSH2 !== null) setShowSubHourSlots(_cSH2 === "true");
|
||||
if (data.user.allDayPosition)
|
||||
setAllDayPosition(data.user.allDayPosition as "above" | "below");
|
||||
if (data.user.viewSettings) setViewSettings(data.user.viewSettings);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user