Skip to content

Commit

Permalink
Add sortings to the assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlurak committed Jul 3, 2024
1 parent 0718af0 commit a9e3ede
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 46 deletions.
36 changes: 34 additions & 2 deletions src/lib/components/assignment/SideMenu/SideMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@
import CreateAssignment from './CreateAssignment.svelte';
import Filter from './Filter/Filter.svelte';
import PageSelector from '$lib/components/pageSelector/DefaultLimitOffsetSelector.svelte';
import Sorting from './Sorting.svelte';
import { createEventDispatcher } from 'svelte';
import type { SortOrder, OrderKey } from '$lib/types/sorting';
export let query: {
let direction: SortOrder = 'desc';
let orderKey: OrderKey = 'due';
type FilterQuery = {
direction: SortOrder;
orderKey: OrderKey;
};
type Query = {
school: string | null;
classes: string[];
Expand All @@ -20,11 +31,17 @@
fromEnd: CustomDate | null;
};
export let query: Query;
export let totalAmount: Promise<number | undefined> | undefined;
const { isLoggedIn } = useAuth();
const userDetails = svocal('dlool.ownUserDetails');
const dispatch = createEventDispatcher<{
change: Query & FilterQuery;
}>();
$: isInClass =
$userDetails?.classes.some(({ school, name }) => {
const schoolMatches = query.school === school.name;
Expand All @@ -35,8 +52,23 @@
</script>

<div class="flex flex-col gap-4">
<Sorting
bind:direction
bind:orderKey
on:change={({ detail }) => dispatch('change', { ...query, ...detail })}
/>
<div>
<Filter {query} on:filterApply />
<Filter
bind:query
on:filterApply={({ detail }) =>
dispatch('change', {
...detail,
direction,
orderKey,
limit: query.limit,
offset: query.offset
})}
/>
</div>

{#if isInClass && $isLoggedIn && query.school}
Expand Down
54 changes: 54 additions & 0 deletions src/lib/components/assignment/SideMenu/Sorting.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script lang="ts">
import Chips from '$lib/components/filter/Chips.svelte';
import Store from '$lib/components/utils/Store.svelte';
import { i } from '$lib/i18n/store';
import type { OrderKey, SortOrder } from '$lib/types/sorting';
import { objectEntries } from '$lib/utils/objects/entries';
import { createEventDispatcher } from 'svelte';
import { ArrowDownRight, ArrowUpRight } from 'svelte-hero-icons';
const ORDER_KEYS = [
'due',
'from',
'subject',
'description',
'versionsCount'
] as const satisfies OrderKey[];
export let direction: SortOrder = 'desc';
export let orderKey: OrderKey = 'due';
const orderings = {
asc: ArrowUpRight,
desc: ArrowDownRight
};
const dispatch = createEventDispatcher<{
change: {
direction: SortOrder;
orderKey: OrderKey;
};
}>();
</script>

<h3><Store store={i('sorting')} /></h3>
<div class="flex gap-2">
<Chips
bind:value={direction}
options={objectEntries(orderings).map(([value, icon]) => ({
icon,
value,
label: i(`sorting.${value}`)
}))}
on:change={({ detail: direction }) => dispatch('change', { direction, orderKey })}
/>

<Chips
bind:value={orderKey}
options={ORDER_KEYS.map((value) => ({
value,
label: i(`sorting.assignments.${value}`)
}))}
on:change={({ detail: orderKey }) => dispatch('change', { direction, orderKey })}
/>
</div>
59 changes: 40 additions & 19 deletions src/lib/components/filter/Chips.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import Store from '../utils/Store.svelte';
import { offset, flip, shift } from 'svelte-floating-ui/dom';
import { createFloatingActions } from 'svelte-floating-ui';
import { useToggle } from 'nutzlich';
import { clickOutside, useToggle } from 'nutzlich';
import { readable } from 'svelte/store';
import { createEventDispatcher } from 'svelte';
import { slide } from 'svelte/transition';
import { animationLength } from '$lib/utils/store/animation';
// eslint-disable-next-line no-undef
export let options: Option<V>[];
Expand All @@ -20,7 +22,11 @@
middleware: [offset(4), flip(), shift()]
});
const showSuggestions = useToggle(false);
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher<{
// eslint-disable-next-line no-undef
change: V;
}>();
</script>

<button
Expand All @@ -34,21 +40,36 @@
<Icon src={ChevronDown} micro class="h-5 w-5" />
</button>

<div use:floatingContent class="px-2" class:hidden={!$showSuggestions}>
<div class="flex w-fit flex-col overflow-hidden rounded bg-zinc-200 dark:bg-zinc-800">
{#each options as opt, ind}
<button
class="px-2 py-1 text-start hover:bg-zinc-300 focus:bg-zinc-300 dark:hover:bg-zinc-700 dark:focus:bg-zinc-700"
on:click={() => {
selectedIndex = ind;
value = options[ind].value;
showSuggestions.set(false);

dispatch('change', value);
}}
>
<Store store={opt.label} />
</button>
{/each}
{#if $showSuggestions}
<div
use:floatingContent
class="z-10 px-2"
use:clickOutside={{ callback: () => showSuggestions.set(false) }}
transition:slide={{ duration: $animationLength }}
>
<div class="flex w-fit flex-col overflow-hidden rounded bg-zinc-200 dark:bg-zinc-800">
{#each options as opt, ind}
<button
class="
flex items-center gap-2 px-2 py-1 text-start transition-colors
hover:bg-zinc-300 focus:bg-zinc-300
dark:hover:bg-zinc-700 dark:focus:bg-zinc-700
"
on:click={() => {
selectedIndex = ind;
value = options[ind].value;
showSuggestions.set(false);

dispatch('change', value);
}}
>
{#if opt.icon}
<Icon src={opt.icon} class="h-4 w-4" micro />
{/if}

<Store store={opt.label} />
</button>
{/each}
</div>
</div>
</div>
{/if}
3 changes: 3 additions & 0 deletions src/lib/components/select/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { Readable } from 'svelte/motion';
import type { IconSource } from 'svelte-hero-icons';

export type Option<T> = {
value: T;
label: Readable<string>;

icon?: IconSource;
};
2 changes: 1 addition & 1 deletion src/lib/dlool/assignments/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ interface TextFilter {
exact?: boolean;
}

interface AssignmentProps {
export interface AssignmentProps {
school: string;
classes: string[];
limit?: number;
Expand Down
10 changes: 10 additions & 0 deletions src/lib/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,16 @@ Deine bisherigen Einstellungen sind leider nicht mit der neuen Version kompatibe
}
},

sorting: 'Sortierung',
'sorting.asc': 'Aufsteigend',
'sorting.desc': 'Herabsteigend',

'sorting.assignments.due': 'Bis zum',
'sorting.assignments.from': 'Vom',
'sorting.assignments.subject': 'Fach',
'sorting.assignments.description': 'Beschreibung',
'sorting.assignments.versionsCount': 'Versionsanzahl',

literal: '$literal'
} as const satisfies I18nDict;

Expand Down
10 changes: 10 additions & 0 deletions src/lib/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,16 @@ Your current settings sadly won't be compatible withthe new version. But you can
}
},

sorting: 'Sorting',
'sorting.asc': 'Ascending',
'sorting.desc': 'Descending',

'sorting.assignments.due': 'Due',
'sorting.assignments.from': 'From',
'sorting.assignments.subject': 'Subject',
'sorting.assignments.description': 'Description',
'sorting.assignments.versionsCount': 'Version Count',

literal: '$literal'
} as const satisfies I18nDict;

Expand Down
5 changes: 5 additions & 0 deletions src/lib/types/sorting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { AssignmentProps } from '$lib/dlool/assignments/list';
import type { RemoveOneValue } from '$lib/types/utils';

export type OrderKey = RemoveOneValue<AssignmentProps['orderKey'], undefined>;
export type SortOrder = 'asc' | 'desc';
1 change: 1 addition & 0 deletions src/lib/types/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type RemoveOneValue<T, R> = T extends R ? never : T;
2 changes: 1 addition & 1 deletion src/routes/homework/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
fromEnd: null
}}
totalAmount={data.data?.then((d) => d?.data.totalCount)}
on:filterApply={({ detail }) => {
on:change={({ detail }) => {
goto(
`?${objToQueryParams({
...detail,
Expand Down
9 changes: 8 additions & 1 deletion src/routes/homework/+page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DATE } from '$lib/constants/regex';
import { loadAssignments } from '$lib/dlool/assignments/list';
import type { OrderKey, SortOrder } from '$lib/types/sorting';
import { deserialize } from '$lib/utils/dates/custom';
import { safeMap } from '$lib/utils/null/safeMap';
import { split } from '$lib/utils/strings/split';
Expand Down Expand Up @@ -29,6 +30,9 @@ export const load: PageLoad = ({ url }) => {
const fromStart = search.get('fromStart');
const fromEnd = search.get('fromEnd');

const orderKey = (search.get('orderKey') ?? 'due') as OrderKey;
const direction = (search.get('direction') ?? 'desc') as SortOrder;

if (school && classes && classes.length > 0) {
return {
data: loadAssignments({
Expand All @@ -45,8 +49,11 @@ export const load: PageLoad = ({ url }) => {
earliest: (DATE.test(fromStart ?? '') && fromStart) || undefined,
latest: (DATE.test(fromEnd ?? '') && fromEnd) || undefined
}
}
},
orderKey,
orderDirection: direction
}).catch(() => null),

query: {
school,
classes,
Expand Down
31 changes: 9 additions & 22 deletions src/routes/moderation/list/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
data = await foreignRequests({ type: 'all' }).then((d) => d.data);
});
const chipHandler = async (d: CustomEvent<'all' | 'Pending' | 'Accepted' | 'Rejected'>) => {
data = await foreignRequests({ type: d.detail }).then((d) => d.data);
};
const states = ['all', 'Pending', 'Accepted', 'Rejected'] as const;
</script>

<MetaData title={i('title.moderation.list')} />
Expand All @@ -26,25 +24,14 @@
<div class="w-full py-3">
<Chips
bind:value={filterValue}
on:change={chipHandler}
options={[
{
value: 'all',
label: i('moderation.state.all')
},
{
value: 'Pending',
label: i('moderation.state.Pending')
},
{
value: 'Accepted',
label: i('moderation.state.Accepted')
},
{
value: 'Rejected',
label: i('moderation.state.Rejected')
}
]}
options={states.map((state) => ({
value: state,
label: i(`moderation.state.${state}`)
}))}
on:change={async ({ detail }) => {
// @ts-expect-error Detail is a state but svelte generics are kinda broken
data = await foreignRequests({ type: detail }).then((d) => d.data);
}}
/>
</div>
{/if}
Expand Down

0 comments on commit a9e3ede

Please sign in to comment.