mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
style(client): prettier on the files this branch touched
This commit is contained in:
@@ -1,19 +1,39 @@
|
||||
// FE-PLANNER-BKPARTS-001 to FE-PLANNER-BKPARTS-002
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { WhenFields } from './bookingParts';
|
||||
import type { BookingFacts } from './bookingFacts';
|
||||
import { WhenFields } from './bookingParts';
|
||||
|
||||
function facts(day: BookingFacts['day'], time: string | null = '15:35 → 09:55'): BookingFacts {
|
||||
return {
|
||||
day, time, startTime: null, endTime: null, startDate: null, endDate: null,
|
||||
cells: [], endpoints: [], legCodes: [], place: null, accommodation: null, linked: null, url: null, isHotel: false,
|
||||
day,
|
||||
time,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
cells: [],
|
||||
endpoints: [],
|
||||
legCodes: [],
|
||||
place: null,
|
||||
accommodation: null,
|
||||
linked: null,
|
||||
url: null,
|
||||
isHotel: false,
|
||||
};
|
||||
}
|
||||
|
||||
describe('WhenFields', () => {
|
||||
it('FE-PLANNER-BKPARTS-001: a long day title is cut, the date beside it never shrinks (#2590)', () => {
|
||||
render(<WhenFields facts={facts({ label: 'Germany Departure Flight with a much longer custom title → Korea Arrival', date: 'Oct 21 → Oct 22', range: true })} />);
|
||||
render(
|
||||
<WhenFields
|
||||
facts={facts({
|
||||
label: 'Germany Departure Flight with a much longer custom title → Korea Arrival',
|
||||
date: 'Oct 21 → Oct 22',
|
||||
range: true,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
||||
const title = screen.getByText('Germany Departure Flight with a much longer custom title → Korea Arrival');
|
||||
const date = screen.getByText('Oct 21 → Oct 22');
|
||||
|
||||
@@ -181,16 +181,24 @@ describe('reservation dates', () => {
|
||||
expect(endTimeBeforeStartTime(overnight)).toBe(true);
|
||||
// Time zones can make a booking end "before" it starts, so the save stays open.
|
||||
expect(isEndBeforeStart(overnight)).toBe(false);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_time: '2026-11-24T09:00', reservation_end_time: '18:00' }))).toBe(false);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_time: '2026-11-24T18:00', reservation_end_time: '18:00' }))).toBe(false);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_time: '2026-11-24T09:00', reservation_end_time: '18:00' }))).toBe(
|
||||
false
|
||||
);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_time: '2026-11-24T18:00', reservation_end_time: '18:00' }))).toBe(
|
||||
false
|
||||
);
|
||||
// With the next day as end date the times are fine, and an end date of its own is checked by isEndBeforeStart.
|
||||
expect(
|
||||
endTimeBeforeStartTime(form({ reservation_time: '2026-11-24T18:00', end_date: '2026-11-25', reservation_end_time: '09:00' }))
|
||||
endTimeBeforeStartTime(
|
||||
form({ reservation_time: '2026-11-24T18:00', end_date: '2026-11-25', reservation_end_time: '09:00' })
|
||||
)
|
||||
).toBe(false);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_time: '2026-11-24', reservation_end_time: '09:00' }))).toBe(false);
|
||||
expect(endTimeBeforeStartTime(form({ reservation_end_time: '09:00' }))).toBe(false);
|
||||
expect(
|
||||
endTimeBeforeStartTime(form({ type: 'hotel', reservation_time: '2026-11-24T18:00', reservation_end_time: '09:00' }))
|
||||
endTimeBeforeStartTime(
|
||||
form({ type: 'hotel', reservation_time: '2026-11-24T18:00', reservation_end_time: '09:00' })
|
||||
)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ describe('usePlanMapViewport', () => {
|
||||
});
|
||||
|
||||
it('raeumt ihn auch weg, sobald die Karte nicht mehr zu sehen ist, und nimmt dann nichts an', () => {
|
||||
const { result, rerender } = renderHook(({ shown }) => usePlanMapViewport(5, shown), { initialProps: { shown: true } });
|
||||
const { result, rerender } = renderHook(({ shown }) => usePlanMapViewport(5, shown), {
|
||||
initialProps: { shown: true },
|
||||
});
|
||||
act(() => result.current(KYOTO));
|
||||
rerender({ shown: false });
|
||||
expect(useTripStore.getState().planMapViewport).toBeNull();
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { useTripStore } from '../store/tripStore'
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useTripStore } from '../store/tripStore';
|
||||
|
||||
interface Bounds { south: number; west: number; north: number; east: number }
|
||||
interface Bounds {
|
||||
south: number;
|
||||
west: number;
|
||||
north: number;
|
||||
east: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hands the plan map's viewport to the trip store, where the place search reads
|
||||
@@ -11,16 +16,19 @@ interface Bounds { south: number; west: number; north: number; east: number }
|
||||
* to lean on, and falls back to the day and the trip.
|
||||
*/
|
||||
export function usePlanMapViewport(tripId: number, shown = true): (bounds: Bounds) => void {
|
||||
const setPlanMapViewport = useTripStore((s) => s.setPlanMapViewport)
|
||||
const setPlanMapViewport = useTripStore((s) => s.setPlanMapViewport);
|
||||
|
||||
useEffect(() => {
|
||||
if (!shown) setPlanMapViewport(null)
|
||||
return () => setPlanMapViewport(null)
|
||||
}, [shown, tripId, setPlanMapViewport])
|
||||
if (!shown) setPlanMapViewport(null);
|
||||
return () => setPlanMapViewport(null);
|
||||
}, [shown, tripId, setPlanMapViewport]);
|
||||
|
||||
return useCallback((bounds: Bounds) => {
|
||||
if (!shown || !Number.isFinite(tripId)) return
|
||||
const { south, west, north, east } = bounds
|
||||
setPlanMapViewport({ tripId, south, west, north, east })
|
||||
}, [shown, tripId, setPlanMapViewport])
|
||||
return useCallback(
|
||||
(bounds: Bounds) => {
|
||||
if (!shown || !Number.isFinite(tripId)) return;
|
||||
const { south, west, north, east } = bounds;
|
||||
setPlanMapViewport({ tripId, south, west, north, east });
|
||||
},
|
||||
[shown, tripId, setPlanMapViewport]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,9 @@ describe('MReservationCardParts', () => {
|
||||
});
|
||||
|
||||
it('FE-COMP-MRESCARD-009: a booking with a linked expense says the expense is deleted with it (#2604)', () => {
|
||||
render(<CardDeleteSheet title="LH 400" card={cardState({ confirmingDelete: true, deleteTakesExpense: true })} t={t} />);
|
||||
render(
|
||||
<CardDeleteSheet title="LH 400" card={cardState({ confirmingDelete: true, deleteTakesExpense: true })} t={t} />
|
||||
);
|
||||
|
||||
expect(screen.getByText('reservations.confirm.deleteBodyWithExpense:LH 400')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -106,7 +106,9 @@ export function CardWhenAndCode({
|
||||
<span className="min-w-0 truncate">{dayValue}</span>
|
||||
<span className="flex-none font-medium text-m-faint">{dayDate}</span>
|
||||
</span>
|
||||
) : dayValue}
|
||||
) : (
|
||||
dayValue
|
||||
)}
|
||||
</Field>
|
||||
<Field label={t('reservations.time')} className="flex-1" tabular>
|
||||
{timeValue}
|
||||
@@ -161,7 +163,10 @@ export function CardDeleteSheet({ title, card, t }: { title: string; card: CardS
|
||||
open={card.confirmingDelete}
|
||||
onClose={card.cancelDelete}
|
||||
title={t('reservations.confirm.deleteTitle')}
|
||||
message={t(card.deleteTakesExpense ? 'reservations.confirm.deleteBodyWithExpense' : 'reservations.confirm.deleteBody', { name: title })}
|
||||
message={t(
|
||||
card.deleteTakesExpense ? 'reservations.confirm.deleteBodyWithExpense' : 'reservations.confirm.deleteBody',
|
||||
{ name: title }
|
||||
)}
|
||||
confirmLabel={t('common.delete')}
|
||||
cancelLabel={t('common.cancel')}
|
||||
danger
|
||||
|
||||
@@ -3,111 +3,135 @@
|
||||
// The planner's view switches the account remembers per trip (#2639): road trip
|
||||
// mode, the Dawarich trail and the route overview. The tab keeps a copy that
|
||||
// answers before the settings arrive.
|
||||
import { act, renderHook, waitFor } from '@testing-library/react'
|
||||
import { http, HttpResponse } from 'msw'
|
||||
import { server } from '../../../tests/helpers/msw/server'
|
||||
import { resetAllStores, seedStore } from '../../../tests/helpers/store'
|
||||
import { buildSettings } from '../../../tests/helpers/factories'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { usePlannerTripView } from './usePlannerTripView'
|
||||
import { act, renderHook, waitFor } from '@testing-library/react';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { buildSettings } from '../../../tests/helpers/factories';
|
||||
import { server } from '../../../tests/helpers/msw/server';
|
||||
import { resetAllStores, seedStore } from '../../../tests/helpers/store';
|
||||
import { useSettingsStore } from '../../store/settingsStore';
|
||||
import { usePlannerTripView } from './usePlannerTripView';
|
||||
|
||||
function captureSettingWrites() {
|
||||
const writes: Array<{ key: string; value: unknown }> = []
|
||||
server.use(http.put('/api/settings', async ({ request }) => {
|
||||
const body = await request.json() as { key: string; value: unknown }
|
||||
writes.push(body)
|
||||
return HttpResponse.json({ success: true, key: body.key, value: body.value })
|
||||
}))
|
||||
return writes
|
||||
const writes: Array<{ key: string; value: unknown }> = [];
|
||||
server.use(
|
||||
http.put('/api/settings', async ({ request }) => {
|
||||
const body = (await request.json()) as { key: string; value: unknown };
|
||||
writes.push(body);
|
||||
return HttpResponse.json({ success: true, key: body.key, value: body.value });
|
||||
})
|
||||
);
|
||||
return writes;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
resetAllStores()
|
||||
})
|
||||
resetAllStores();
|
||||
});
|
||||
|
||||
describe('usePlannerTripView', () => {
|
||||
it('FE-TP-TRIPVIEW-001: a fresh browser opens the trip with the switches the account has on', () => {
|
||||
seedStore(useSettingsStore, {
|
||||
settings: buildSettings({ planner_trip_views: { '42': { roadtrip: true } } }),
|
||||
isLoaded: true,
|
||||
})
|
||||
expect(renderHook(() => usePlannerTripView(42, 'roadtrip')).result.current[0]).toBe(true)
|
||||
expect(renderHook(() => usePlannerTripView(42, 'dawarich')).result.current[0]).toBe(false)
|
||||
expect(renderHook(() => usePlannerTripView(43, 'roadtrip')).result.current[0]).toBe(false)
|
||||
})
|
||||
});
|
||||
expect(renderHook(() => usePlannerTripView(42, 'roadtrip')).result.current[0]).toBe(true);
|
||||
expect(renderHook(() => usePlannerTripView(42, 'dawarich')).result.current[0]).toBe(false);
|
||||
expect(renderHook(() => usePlannerTripView(43, 'roadtrip')).result.current[0]).toBe(false);
|
||||
});
|
||||
|
||||
it('FE-TP-TRIPVIEW-002: the tab copy answers until the settings are here, then the account decides', () => {
|
||||
sessionStorage.setItem('trip-roadtrip-42', '1')
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'))
|
||||
expect(result.current[0]).toBe(true)
|
||||
sessionStorage.setItem('trip-roadtrip-42', '1');
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'));
|
||||
expect(result.current[0]).toBe(true);
|
||||
|
||||
// Switched off on another device since this tab last looked.
|
||||
act(() => { seedStore(useSettingsStore, { settings: buildSettings(), isLoaded: true }) })
|
||||
expect(result.current[0]).toBe(false)
|
||||
})
|
||||
act(() => {
|
||||
seedStore(useSettingsStore, { settings: buildSettings(), isLoaded: true });
|
||||
});
|
||||
expect(result.current[0]).toBe(false);
|
||||
});
|
||||
|
||||
it('FE-TP-TRIPVIEW-003: a switch is saved on the account next to the other trips, and only what is on', async () => {
|
||||
const writes = captureSettingWrites()
|
||||
const writes = captureSettingWrites();
|
||||
seedStore(useSettingsStore, {
|
||||
settings: buildSettings({ planner_trip_views: { '7': { overview: true }, '42': { dawarich: true } } }),
|
||||
isLoaded: true,
|
||||
})
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'))
|
||||
});
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'));
|
||||
|
||||
act(() => { result.current[1]() })
|
||||
expect(result.current[0]).toBe(true)
|
||||
expect(sessionStorage.getItem('trip-roadtrip-42')).toBe('1')
|
||||
await waitFor(() => expect(writes).toHaveLength(1))
|
||||
act(() => {
|
||||
result.current[1]();
|
||||
});
|
||||
expect(result.current[0]).toBe(true);
|
||||
expect(sessionStorage.getItem('trip-roadtrip-42')).toBe('1');
|
||||
await waitFor(() => expect(writes).toHaveLength(1));
|
||||
expect(writes[0]).toEqual({
|
||||
key: 'planner_trip_views',
|
||||
value: { '7': { overview: true }, '42': { dawarich: true, roadtrip: true } },
|
||||
})
|
||||
});
|
||||
|
||||
act(() => { result.current[1]() })
|
||||
expect(result.current[0]).toBe(false)
|
||||
await waitFor(() => expect(writes).toHaveLength(2))
|
||||
expect(writes[1].value).toEqual({ '7': { overview: true }, '42': { dawarich: true } })
|
||||
})
|
||||
act(() => {
|
||||
result.current[1]();
|
||||
});
|
||||
expect(result.current[0]).toBe(false);
|
||||
await waitFor(() => expect(writes).toHaveLength(2));
|
||||
expect(writes[1].value).toEqual({ '7': { overview: true }, '42': { dawarich: true } });
|
||||
});
|
||||
|
||||
it('FE-TP-TRIPVIEW-004: a switch made before the settings arrived waits for them instead of erasing other trips', async () => {
|
||||
const writes = captureSettingWrites()
|
||||
server.use(http.get('/api/settings', () => HttpResponse.json({
|
||||
settings: buildSettings({ planner_trip_views: { '7': { overview: true } } }),
|
||||
})))
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'dawarich'))
|
||||
const writes = captureSettingWrites();
|
||||
server.use(
|
||||
http.get('/api/settings', () =>
|
||||
HttpResponse.json({
|
||||
settings: buildSettings({ planner_trip_views: { '7': { overview: true } } }),
|
||||
})
|
||||
)
|
||||
);
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'dawarich'));
|
||||
|
||||
act(() => { result.current[1]() })
|
||||
expect(result.current[0]).toBe(true)
|
||||
await waitFor(() => expect(writes).toHaveLength(1))
|
||||
expect(writes[0].value).toEqual({ '7': { overview: true }, '42': { dawarich: true } })
|
||||
expect(result.current[0]).toBe(true)
|
||||
})
|
||||
act(() => {
|
||||
result.current[1]();
|
||||
});
|
||||
expect(result.current[0]).toBe(true);
|
||||
await waitFor(() => expect(writes).toHaveLength(1));
|
||||
expect(writes[0].value).toEqual({ '7': { overview: true }, '42': { dawarich: true } });
|
||||
expect(result.current[0]).toBe(true);
|
||||
});
|
||||
|
||||
it('FE-TP-TRIPVIEW-005: a save that fails keeps the switch for the session', async () => {
|
||||
let tried = false
|
||||
server.use(http.put('/api/settings', () => {
|
||||
tried = true
|
||||
return HttpResponse.json({ error: 'nope' }, { status: 500 })
|
||||
}))
|
||||
seedStore(useSettingsStore, { settings: buildSettings(), isLoaded: true })
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'overview'))
|
||||
let tried = false;
|
||||
server.use(
|
||||
http.put('/api/settings', () => {
|
||||
tried = true;
|
||||
return HttpResponse.json({ error: 'nope' }, { status: 500 });
|
||||
})
|
||||
);
|
||||
seedStore(useSettingsStore, { settings: buildSettings(), isLoaded: true });
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'overview'));
|
||||
|
||||
act(() => { result.current[1]() })
|
||||
await waitFor(() => expect(tried).toBe(true))
|
||||
await act(async () => { await Promise.resolve() })
|
||||
expect(result.current[0]).toBe(true)
|
||||
expect(sessionStorage.getItem('trip-overview-42')).toBe('1')
|
||||
})
|
||||
act(() => {
|
||||
result.current[1]();
|
||||
});
|
||||
await waitFor(() => expect(tried).toBe(true));
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(result.current[0]).toBe(true);
|
||||
expect(sessionStorage.getItem('trip-overview-42')).toBe('1');
|
||||
});
|
||||
|
||||
it('FE-TP-TRIPVIEW-006: settings that cannot be loaded leave the tab copy in charge and write nothing', async () => {
|
||||
const writes = captureSettingWrites()
|
||||
server.use(http.get('/api/settings', () => HttpResponse.json({ error: 'offline' }, { status: 503 })))
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'))
|
||||
const writes = captureSettingWrites();
|
||||
server.use(http.get('/api/settings', () => HttpResponse.json({ error: 'offline' }, { status: 503 })));
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const { result } = renderHook(() => usePlannerTripView(42, 'roadtrip'));
|
||||
|
||||
act(() => { result.current[1]() })
|
||||
await act(async () => { await new Promise(r => setTimeout(r, 20)) })
|
||||
expect(result.current[0]).toBe(true)
|
||||
expect(writes).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
act(() => {
|
||||
result.current[1]();
|
||||
});
|
||||
await act(async () => {
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
});
|
||||
expect(result.current[0]).toBe(true);
|
||||
expect(writes).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import { PLANNER_TRIP_VIEWS_KEY, compactPlannerTripViews, type PlannerTripViewFlag } from '@trek/shared'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { PLANNER_TRIP_VIEWS_KEY, compactPlannerTripViews, type PlannerTripViewFlag } from '@trek/shared';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useSettingsStore } from '../../store/settingsStore';
|
||||
|
||||
function readSession(key: string): boolean | null {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(key)
|
||||
return raw === '1' ? true : raw === '0' ? false : null
|
||||
const raw = sessionStorage.getItem(key);
|
||||
return raw === '1' ? true : raw === '0' ? false : null;
|
||||
} catch {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function writeSession(key: string, on: boolean): void {
|
||||
try { sessionStorage.setItem(key, on ? '1' : '0') } catch { /* the account row still has it */ }
|
||||
try {
|
||||
sessionStorage.setItem(key, on ? '1' : '0');
|
||||
} catch {
|
||||
/* the account row still has it */
|
||||
}
|
||||
}
|
||||
|
||||
interface TabCopy {
|
||||
key: string
|
||||
on: boolean | null
|
||||
key: string;
|
||||
on: boolean | null;
|
||||
/** A switch made here that the account row has not taken yet. */
|
||||
pending: boolean
|
||||
pending: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,39 +35,39 @@ interface TabCopy {
|
||||
* decide, because a switch flipped on another device is newer than this tab.
|
||||
*/
|
||||
export function usePlannerTripView(tripId: number, flag: PlannerTripViewFlag): [boolean, () => void] {
|
||||
const sessionKey = `trip-${flag}-${tripId}`
|
||||
const saved = useSettingsStore(s => s.settings.planner_trip_views?.[String(tripId)]?.[flag] === true)
|
||||
const loaded = useSettingsStore(s => s.isLoaded)
|
||||
const [local, setLocal] = useState<TabCopy>(() => ({ key: sessionKey, on: readSession(sessionKey), pending: false }))
|
||||
const sessionKey = `trip-${flag}-${tripId}`;
|
||||
const saved = useSettingsStore((s) => s.settings.planner_trip_views?.[String(tripId)]?.[flag] === true);
|
||||
const loaded = useSettingsStore((s) => s.isLoaded);
|
||||
const [local, setLocal] = useState<TabCopy>(() => ({ key: sessionKey, on: readSession(sessionKey), pending: false }));
|
||||
// A different trip in the same planner reads its own copy instead of keeping this one.
|
||||
const copy = local.key === sessionKey ? local : { key: sessionKey, on: readSession(sessionKey), pending: false }
|
||||
const shown = loaded && !copy.pending ? saved : (copy.on ?? saved)
|
||||
const copy = local.key === sessionKey ? local : { key: sessionKey, on: readSession(sessionKey), pending: false };
|
||||
const shown = loaded && !copy.pending ? saved : (copy.on ?? saved);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
const next = !shown
|
||||
setLocal({ key: sessionKey, on: next, pending: true })
|
||||
writeSession(sessionKey, next)
|
||||
const next = !shown;
|
||||
setLocal({ key: sessionKey, on: next, pending: true });
|
||||
writeSession(sessionKey, next);
|
||||
void remember(tripId, flag, next).finally(() => {
|
||||
setLocal(prev => (prev.key === sessionKey && prev.on === next ? { ...prev, pending: false } : prev))
|
||||
})
|
||||
}, [shown, sessionKey, tripId, flag])
|
||||
setLocal((prev) => (prev.key === sessionKey && prev.on === next ? { ...prev, pending: false } : prev));
|
||||
});
|
||||
}, [shown, sessionKey, tripId, flag]);
|
||||
|
||||
return [shown, toggle]
|
||||
return [shown, toggle];
|
||||
}
|
||||
|
||||
async function remember(tripId: number, flag: PlannerTripViewFlag, on: boolean): Promise<void> {
|
||||
const store = useSettingsStore.getState()
|
||||
const store = useSettingsStore.getState();
|
||||
// The row holds every trip, so it is only written over once the account's
|
||||
// own copy is here; otherwise one switch would erase all the others. The
|
||||
// store takes the new value before the request goes out, so an offline save
|
||||
// still shows for the rest of the session.
|
||||
if (!store.isLoaded) await store.loadSettings()
|
||||
const { settings, isLoaded, updateSetting } = useSettingsStore.getState()
|
||||
if (!isLoaded) return
|
||||
const views = { ...settings.planner_trip_views }
|
||||
views[String(tripId)] = { ...views[String(tripId)], [flag]: on }
|
||||
if (!store.isLoaded) await store.loadSettings();
|
||||
const { settings, isLoaded, updateSetting } = useSettingsStore.getState();
|
||||
if (!isLoaded) return;
|
||||
const views = { ...settings.planner_trip_views };
|
||||
views[String(tripId)] = { ...views[String(tripId)], [flag]: on };
|
||||
try {
|
||||
await updateSetting(PLANNER_TRIP_VIEWS_KEY, compactPlannerTripViews(views))
|
||||
await updateSetting(PLANNER_TRIP_VIEWS_KEY, compactPlannerTripViews(views));
|
||||
} catch {
|
||||
// Offline or refused: the store and the tab copy keep the switch for this session.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user