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:
parent
1559e5cdd9
commit
6f9a84fed6
4 changed files with 75 additions and 13 deletions
|
@ -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} />
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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 = {}) {
|
||||||
|
|
Loading…
Reference in a new issue