Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calendar view improvements #258

Merged
merged 4 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/api/management/commands/makeAdmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Command(BaseCommand):

help = 'seed the db with data'
help = 'make yourself admin'

def add_arguments(self, parser):
parser.add_argument('username', type=str, help='The username of the student user to make admin')
Expand All @@ -18,4 +18,4 @@ def handle(self, *args, **options):
student = student.get()
student.is_staff = True
student.save()
self.stdout.write(self.style.SUCCESS('Successfully made yourself admin!'))
self.stdout.write(self.style.SUCCESS('Successfully made the user admin!'))
21 changes: 21 additions & 0 deletions backend/api/management/commands/makeTeacher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.core.management.base import BaseCommand
from api.models.student import Student
from api.models.teacher import Teacher


class Command(BaseCommand):

help = 'make yourself teacher'

def add_arguments(self, parser):
parser.add_argument('username', type=str, help='The username of the student user to make teacher')

def handle(self, *args, **options):
username = options['username']
student = Student.objects.filter(username=username)
if student.count() == 0:
self.stdout.write(self.style.ERROR('User not found, first log in !'))
return
student = student.get()
Teacher.objects.create(id=student.id, create_time=student.create_time)
self.stdout.write(self.style.SUCCESS('Successfully made the user teacher!'))
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
28 changes: 28 additions & 0 deletions frontend/src/composables/filters/filter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
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>): void {
watchDebounced(
filter,
async () => {
await push({
query: {
...query,
...filter.value,
},
});

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

return {
filter,
onFilter,
};
}
13 changes: 13 additions & 0 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 Down Expand Up @@ -54,10 +55,22 @@ export function usePaginator(initialPage: number = 1, initialPageSize: number =
});
}

/**
* On paginate callback
*
* @param callback
*/
function onPaginate(callback: () => Promise<void>): 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 { type 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 !== undefined) {
filters.faculties = getQueryList(query.faculties as string | string[]);
}

if (query.years !== undefined) {
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
Loading