Add pre-selection of calendars (#20)

Co-authored-by: Tom Hubrecht <tom.hubrecht@ens.fr>
Co-authored-by: Raito Bezarius <masterancpp@gmail.com>
Reviewed-on: https://git.rz.ens.wtf/Klub-RZ/metis/pulls/20
Co-authored-by: tomate <tom.hubrecht@ens.fr>
Co-committed-by: tomate <tom.hubrecht@ens.fr>
This commit is contained in:
tomate 2022-03-29 20:33:05 +02:00
parent 1559e5cdd9
commit 6f9a84fed6
4 changed files with 75 additions and 13 deletions

View file

@ -10,7 +10,7 @@
import frLocale from '@fullcalendar/core/locales/fr'; import frLocale from '@fullcalendar/core/locales/fr';
import EventModal from './EventModal.svelte'; import EventModal from './EventModal.svelte';
import FilterBar from './FilterBar.svelte'; import FilterBar from './FilterBar.svelte';
import { mkSource, calendarTree } from './calendar'; import { mkSource, calendarTree, initialCalendars, getSubCalendars } from './calendar';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import Help from './Help.svelte'; import Help from './Help.svelte';
@ -30,6 +30,8 @@
return time.toLocaleTimeString(); return time.toLocaleTimeString();
})(); })();
const params = new URL(document.location).searchParams.getAll('c');
let calendar; let calendar;
let options = writable({ let options = writable({
@ -71,7 +73,28 @@
progressiveEventRendering: true progressiveEventRendering: true
}); });
const flatten = d => {
let array = [];
if (!d) {
return [];
}
if (Array.isArray(d)) {
d.forEach(a => (array = array.concat(flatten(a))));
} else {
for (const [n, s] of Object.entries(d)) {
array = array.concat(n, flatten(s));
}
}
return array;
};
let selectedCalendars = []; let selectedCalendars = [];
const initial =
params.length > 0
? flatten(params.map(cal => getSubCalendars(cal))).concat(params)
: initialCalendars;
const updateEvents = debounce(calendars => { const updateEvents = debounce(calendars => {
options.update(opts => ({ options.update(opts => ({
@ -88,7 +111,7 @@
<Help /> <Help />
<FilterBar {calendarTree} bind:selected={selectedCalendars} /> <FilterBar {calendarTree} bind:selected={selectedCalendars} {initial} />
<FullCalendar bind:this={calendar} options={$options} /> <FullCalendar bind:this={calendar} options={$options} />

View file

@ -5,15 +5,17 @@
export let calendarTree = []; export let calendarTree = [];
export let selected = null; export let selected = null;
export let initial = [];
let open = false; let open = false;
let icon;
let generalToggle = writable(true); let generalToggle = writable(true);
const toggle = () => (open = !open); const toggle = () => (open = !open);
$: icon = () => ($generalToggle ? 'toggle-on' : 'toggle-off');
let subSelections = Array.from({ length: Object.keys(calendarTree).length }, _ => []); let subSelections = Array.from({ length: Object.keys(calendarTree).length }, _ => []);
$: selected = subSelections.flat(); $: selected = subSelections.flat();
generalToggle.subscribe(v => (icon = v ? 'toggle-on' : 'toggle-off'));
</script> </script>
<Button on:click={toggle} class="mb-3 col-6 mx-auto"> <Button on:click={toggle} class="mb-3 col-6 mx-auto">
@ -29,7 +31,7 @@
header="Sélection des calendriers" header="Sélection des calendriers"
> >
<span class="fs-5 toggle" on:click={() => ($generalToggle = !$generalToggle)}> <span class="fs-5 toggle" on:click={() => ($generalToggle = !$generalToggle)}>
<Icon name={icon()} /> <Icon name={icon} />
<span class="ms-2">Tous les calendriers</span> <span class="ms-2">Tous les calendriers</span>
</span> </span>
<hr class="my-3" /> <hr class="my-3" />
@ -39,7 +41,8 @@
item={toplevel} item={toplevel}
children={subtrees} children={subtrees}
bind:selected={subSelections[i]} bind:selected={subSelections[i]}
bind:generalToggle generalToggle={$generalToggle}
{initial}
/> />
{/each} {/each}
</Offcanvas> </Offcanvas>

View file

@ -11,11 +11,15 @@
export let item = null; export let item = null;
export let level = 1; export let level = 1;
export let generalToggle = undefined; export let generalToggle = undefined;
export let initial;
export let children = []; export let children = [];
export let selected = []; export let selected = [];
export let filtering = createTriState(UNCHECKED);
let subfiltering = createTriStates(UNCHECKED, Object.entries(children).length); const initialState = initial.includes(item) ? CHECKED : UNCHECKED;
export let filtering = createTriState(initialState);
let subfiltering = createTriStates(initialState, Object.entries(children).length);
let subselected = Array.from({ length: Object.entries(children).length }, _ => []); let subselected = Array.from({ length: Object.entries(children).length }, _ => []);
let collapsed = Object.entries(children).length ? false : undefined; let collapsed = Object.entries(children).length ? false : undefined;
@ -73,11 +77,18 @@
dispatch('change', { value: evt.detail.value }); dispatch('change', { value: evt.detail.value });
} }
if (generalToggle) { function handleGeneralToggleChange(value) {
generalToggle.subscribe(value => { if (value) {
setTimeout(() => (value ? filtering.setChecked() : filtering.setUnchecked()), 0); filtering.setChecked();
dispatch('change', { value: $filtering }); } else {
}); filtering.setUnchecked();
}
dispatch('change', { value: $filtering });
}
$: if (generalToggle != null) {
handleGeneralToggleChange(generalToggle);
} }
const url = (() => { const url = (() => {
@ -85,6 +96,11 @@
return source ? source.export_url : undefined; return source ? source.export_url : undefined;
})(); })();
setTimeout(
() => (initial.includes(item) ? filtering.setChecked() : filtering.setUnchecked()),
0
);
$: selected = $: selected =
$filtering === CHECKED ? [item, ...subselected.flat()] : subselected.flat(); $filtering === CHECKED ? [item, ...subselected.flat()] : subselected.flat();
$: subHidden = () => (collapsed ? 'd-none' : ''); $: subHidden = () => (collapsed ? 'd-none' : '');
@ -111,6 +127,7 @@
filtering={subfiltering.storeAt(i)} filtering={subfiltering.storeAt(i)}
bind:selected={subselected[i]} bind:selected={subselected[i]}
level={level + 1} level={level + 1}
{initial}
/> />
{:else} {:else}
<svelte:self <svelte:self
@ -119,6 +136,7 @@
filtering={subfiltering.storeAt(i)} filtering={subfiltering.storeAt(i)}
bind:selected={subselected[i]} bind:selected={subselected[i]}
level={level + 1} level={level + 1}
{initial}
/> />
{/if} {/if}
{/each} {/each}

View file

@ -50,6 +50,12 @@ const calendarsByName = Object.fromEntries(
Object.entries(calendars).map(([id, { name }]) => [name, id]) Object.entries(calendars).map(([id, { name }]) => [name, id])
) )
export const initialCalendars = Array.from(
Object.entries(calendars).map(([_, { name, initial }]) => [name, initial ?? true])
)
.filter(cal => cal[1])
.map(cal => cal[0])
export const calendarTree = { export const calendarTree = {
'Clubs COF': { 'Clubs COF': {
'Club réseau': {}, 'Club réseau': {},
@ -68,6 +74,18 @@ export const calendarTree = {
'K-Fêt': {} 'K-Fêt': {}
} }
export function getSubCalendars(name, tree = calendarTree) {
let ret
for (const [cal, subTree] of Object.entries(tree)) {
if (cal === name) {
ret = subTree
} else {
ret = ret || getSubCalendars(name, subTree)
}
}
return ret
}
const calendarIds = Object.keys(calendars) const calendarIds = Object.keys(calendars)
function mkCalendarUrl(id, { cloud }, extra = {}) { function mkCalendarUrl(id, { cloud }, extra = {}) {