Skip to content

Commit

Permalink
feat: better calendar view
Browse files Browse the repository at this point in the history
  • Loading branch information
EwoutV committed Apr 9, 2024
1 parent 0cb4bc4 commit f4f3d71
Show file tree
Hide file tree
Showing 10 changed files with 520 additions and 287 deletions.
465 changes: 231 additions & 234 deletions frontend/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"msw": "^2.2.13",
"pinia": "^2.1.7",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
"primeicons": "^7.0.0",
"primevue": "^3.50.0",
"vue": "^3.4.18",
"vue-i18n": "^9.10.2",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/assets/lang/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"logo": "Logo van de Universiteit Gent",
"login": "Login",
"view": "Bekijken als {0}",
"user": "Ingelogd als {0}",
"navigation": {
"dashboard": "Dashboard",
"calendar": "Kalender",
Expand Down Expand Up @@ -37,7 +38,8 @@
}
},
"calendar": {
"title": "Kalender"
"title": "Kalender",
"noProjects": "Geen projecten op geselecteerde datum."
},
"projects": {
"deadline": "Deadline",
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/components/layout/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const items = computed(() => [
route: 'courses',
},
{
icon: 'file-plus',
icon: 'bookmark',
label: t('layout.header.navigation.projects'),
route: 'projects',
},
Expand All @@ -59,16 +59,18 @@ const items = computed(() => [
</div>
<div class="text-right ml-auto text-sm flex flex-column align-items-end gap-3">
<div class="flex align-items-center gap-3">
<!-- Role selector -->
<RoleSelector v-if="user !== null && user.roles.length > 1" />
<template v-if="user !== null && user.hasMultipleRoles()">
<!-- Role selector -->
<RoleSelector />
</template>
<!-- Language selector -->
<LanguageSelector />
</div>
<div>
<!-- User information -->
<template v-if="isAuthenticated && user">
<template v-if="user !== null">
<RouterLink :to="{ name: 'logout' }" class="text-white">
Ingelogd als {{ user.getFullName() }}
{{ t('layout.header.user', [user.getFullName()]) }}
</RouterLink>
</template>
<!-- Login button -->
Expand Down
29 changes: 28 additions & 1 deletion frontend/src/composables/filters/filter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
import { type Ref, ref } from 'vue';
import { type Filter } from '@/types/filter/Filter.ts';
import { watchDebounced } from '@vueuse/core';
import { useRoute, useRouter } from 'vue-router';

export interface FilterState {
filter: Ref<Filter>;
onFilter: (callback: () => Promise<void>) => void;
}

export function useFilter(initial: Filter): FilterState {
/* State */
const filter = ref<Filter>(initial);
const { query } = useRoute();
const { push } = useRouter();

/**
* On filter callback
*
* @param callback
*/
function onFilter(callback: () => Promise<void>) {
watchDebounced(
filter,
async () => {
await push({
query: {
...query,
...filter.value
},
});

await callback();
},
{ debounce: 500, immediate: true, deep: true },
);
}

return {
filter,
filter, onFilter
};
}
17 changes: 15 additions & 2 deletions frontend/src/composables/filters/paginator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface PaginatorState {
pageSize: Ref<number>;
first: Ref<number>;
paginate: (newFirst: number) => Promise<void>;
onPaginate: (callback: () => Promise<void>) => void;
}

export function usePaginator(initialPage: number = 1, initialPageSize: number = 20): PaginatorState {
Expand All @@ -14,8 +15,8 @@ export function usePaginator(initialPage: number = 1, initialPageSize: number =
const { push } = useRouter();

/* State */
const page = ref<number>(initialPage);
const pageSize = ref<number>(initialPageSize);
const page = ref<number>(parseInt(query.page as string) || initialPage);
const pageSize = ref<number>(parseInt(query.pageSize as string) || initialPageSize);

/* Watchers */
watch(
Expand Down Expand Up @@ -54,10 +55,22 @@ export function usePaginator(initialPage: number = 1, initialPageSize: number =
});
}

/**
* On paginate callback
*
* @param callback
*/
async function onPaginate(callback: () => Promise<void>) {
watch(page, async () => {
await callback();
});
}

return {
page,
pageSize,
first,
paginate,
onPaginate,
};
}
51 changes: 45 additions & 6 deletions frontend/src/types/filter/Filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,49 @@
export const COURSE_FILTER = {
search: '',
faculties: [],
years: [],
};
import { LocationQuery } from 'vue-router';

export type CourseFilter = {
faculties: string[];
years: string[];
} & Filter;

export interface Filter {
search: string;
[key: string]: any;
[key: string]: string|string[];
}

/**
* Get the course filters from the query.
*
* @param query
*/
export function getCourseFilters(query: LocationQuery): CourseFilter {
const filters: CourseFilter = {
search: query.search?.toString() || '',
faculties: [],
years: [],
};

if (query.faculties) {
filters.faculties = getQueryList(query.faculties as string|string[]);
}

if (query.years) {
filters.years = getQueryList(query.years as string|string[]);
}

return filters;
}

/**
* Get the query list.
*
* @param query
*/
function getQueryList(query: string | string[] | undefined): string[] {
if (query === undefined) return [];

if (Array.isArray(query)) {
return query;
}

return [query?.toString()];
}
18 changes: 18 additions & 0 deletions frontend/src/types/users/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ export class User {
return this.isStudent() || this.isAssistant() || this.isTeacher();
}

/**
* Check if the user has a role.
*
* @param roles
*/
public hasRoles(...roles: Role[]): boolean {
return roles.every((role) => this.roles.includes(role));
}

/**
* Check if the user has multiple roles.
*
* @returns boolean
*/
public hasMultipleRoles(): boolean {
return this.roles.length > 1;
}

/**
* Convert a user object to a user instance.
*
Expand Down
Loading

0 comments on commit f4f3d71

Please sign in to comment.