Skip to content

Commit

Permalink
Finished AllTasks component
Browse files Browse the repository at this point in the history
  • Loading branch information
patrick11514 committed Oct 5, 2024
1 parent 943a45f commit 088b6f3
Showing 1 changed file with 129 additions and 73 deletions.
202 changes: 129 additions & 73 deletions frontend/src/Teacher/AllTasks.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<script setup lang="ts">
import '@mdi/font/css/materialdesignicons.css';
import { computed, ref } from 'vue';
import 'vuetify/styles';
import type { Config, ConfigColumns, Api as DataTableObject } from 'datatables.net';
import DataTablesCore from 'datatables.net-bs5';
import DataTable from 'datatables.net-vue3';
import { ref, watchEffect } from 'vue';
import Loader from '../components/Loader.vue';
import { getFromAPI } from '../utilities';
import { getDate, getFromAPI } from '../utilities';
DataTable.use(DataTablesCore);
type Task = {
id: string;
Expand All @@ -16,11 +19,24 @@ type RawTask = Omit<Task, 'date'> & {
date: string;
};
const tasksLoaded = ref(false);
const allTasks = ref(Array<Task>());
const taskCount = ref(0);
const getTasks = async (subject: string, count: number, start = 0) => {
type SortValue = 'asc' | 'desc';
/**
* Get tasks from API
* @param subject Subject abbreviation
* @param count Count of records
* @param start Offset of records
* @param sort Type of sorting
* @param search Search query
* @returns Tuple of [total count, tasks]
*/
const getTasks = async (
subject: string,
count: number,
start = 0,
sort: SortValue = 'desc',
search: string = ''
): Promise<[number, Task[]]> => {
const params = new URLSearchParams();
if (subject !== 'all') {
Expand All @@ -29,131 +45,167 @@ const getTasks = async (subject: string, count: number, start = 0) => {
params.append('count', count.toString());
params.append('start', start.toString());
params.append('sort', sort);
params.append('search', search);
const data = await getFromAPI<{
tasks: RawTask[];
count: number;
}>(`/api/tasks/all?${params.toString()}`);
if (data) {
allTasks.value = data.tasks.map((task) => {
return {
...task,
date: new Date(task.date)
} satisfies Task;
});
taskCount.value = data.count;
tasksLoaded.value = true;
return [
data.count,
data.tasks.map((task) => {
return {
...task,
//parse date, and since django returns the correct format we can just pass it to the Date constructor
date: new Date(task.date)
} satisfies Task;
})
];
}
};
getTasks('all', 30);
return [0, []];
};
type Subject = {
abbr: string;
name: string;
};
const subjects = ref(Array<Subject>());
const subjectsLoaded = ref(false);
const loaded = ref(false);
const getSubjects = async () => {
const data = await getFromAPI<{
subjects: Subject[];
}>('/api/subjects/all');
if (data) {
subjects.value = data.subjects;
subjectsLoaded.value = true;
loaded.value = true;
}
};
getSubjects();
const loaded = computed(() => subjectsLoaded.value && tasksLoaded);
const selectedTasks = computed(() => {
let tasks = [...allTasks.value].reverse();
if (selectedSubject.value !== 'all') {
tasks = tasks.filter((task) => task.subject === selectedSubject.value);
}
if (taskSearch.value) {
tasks = tasks.filter((task) =>
task.title.toLowerCase().includes(taskSearch.value.toLowerCase())
);
}
return tasks;
});
const selectedSubject = ref('all');
const taskSearch = ref('');
const headers = [
const columns = [
{
title: 'Id',
align: 'start',
sortable: false,
key: 'id'
data: 'id',
searchable: false,
orderable: false,
visible: false
},
{
title: 'Title',
align: 'end',
sortable: true,
key: 'title'
data: 'title',
orderable: false,
searchable: true
},
{
title: 'Subject',
align: 'end',
sortable: true,
key: 'subject'
data: 'subject',
orderable: false,
searchable: false
},
{
title: 'Created At',
data: 'date',
orderable: true,
searchable: false,
render: (data: Date) => getDate(data, true)
},
{
title: 'Date',
align: 'end',
sortable: true,
key: 'date'
title: 'Moss check',
orderable: false,
searchable: false,
render: '#moss',
data: null,
className: 'dt-body-right dt-head-right'
}
] satisfies ConfigColumns[];
let subject = ref('all');
const options = {
stripeClasses: ['table-striped', 'table-hover'],
serverSide: true,
ajax: async (
data: {
length: number;
start: number;
order: {
column: number;
dir: SortValue;
name: string;
}[];
search: {
value: string;
};
},
callback: (data: { data: Task[]; recordsTotal: number; recordsFiltered: number }) => void
) => {
const [count, items] = await getTasks(
subject.value,
data.length,
data.start,
data.order.find((order) => order.column === 3)?.dir ?? 'desc',
data.search.value
);
callback({ data: items, recordsTotal: count, recordsFiltered: count }); // https://datatables.net/manual/server-side#Returned-data
}
] as const;
} satisfies Config;
const loadItems = () => {
console.log('Loaded');
//save ref to data table and if it changes save datatable instance to table variable
const dataTable = ref();
let table: undefined | DataTableObject<unknown> = undefined;
watchEffect(() => {
table = dataTable.value?.dt;
});
const onChangeSubject = () => {
//invalidate cells to load data again with
table.draw();
};
</script>

<template>
<div v-if="!loaded.value" class="d-flex justify-content-center loading-animation">
<div v-if="!loaded" class="d-flex justify-content-center loading-animation">
<Loader />
</div>
<template v-else>
<div class="d-flex gap-1 justify-content-start">
<input
v-model="taskSearch"
type="search"
class="form-control"
placeholder="Search task by name"
/>
<select v-model="selectedSubject" class="form-select">
<select v-model="subject" class="form-select" @change="onChangeSubject">
<option value="all" selected>All</option>
<option v-for="subject in subjects" :key="subject.abbr" :value="subject.abbr">
{{ subject.name }}
<option v-for="subj in subjects" :key="subj.abbr" :value="subj.abbr">
{{ subj.name }}
</option>
</select>
</div>

<v-data-table-server
<DataTable ref="dataTable" class="table table-striped" :columns="columns" :options="options">
<template #moss="props">
<a class="btn btn-secondary btn-sm" :href="`/teacher/task/${props.cellData.id}/moss`">
MOSS check
</a>
</template>
</DataTable>

<!--<v-data-table-server
:items-per-page="10"
:headers="headers"
:items="selectedTasks"
:items-length="taskCount"
:loading="false"
item-value="name"
@update:options="loadItems"
></v-data-table-server>
></v-data-table-server>-->

<table class="table table-striped table-hover table-sm">
<!--<table class="table table-striped table-hover table-sm">
<thead>
<tr>
<th>Name</th>
Expand All @@ -174,6 +226,10 @@ const loadItems = () => {
</td>
</tr>
</tbody>
</table>
</table>-->
</template>
</template>

<style>
@import 'datatables.net-bs5';
</style>

0 comments on commit 088b6f3

Please sign in to comment.