feat(frontend): alle leerpaden en klasses worden gefetched via de controllers

This commit is contained in:
Joyelle Ndagijimana 2025-04-08 01:29:42 +02:00
parent 23947ecd92
commit 1328771551
7 changed files with 113 additions and 83 deletions

View file

@ -1,17 +1,19 @@
import { BaseController } from "@/controllers/base-controller.ts";
import { LearningPath } from "@/data-objects/learning-paths/learning-path.ts";
import type { Language } from "@/data-objects/language.ts";
import { single } from "@/utils/response-assertions.ts";
import type { LearningPathDTO } from "@/data-objects/learning-paths/learning-path-dto.ts";
import {BaseController} from "@/controllers/base-controller.ts";
import {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
import type {Language} from "@/data-objects/language.ts";
import {single} from "@/utils/response-assertions.ts";
import type {LearningPathDTO} from "@/data-objects/learning-paths/learning-path-dto.ts";
export class LearningPathController extends BaseController {
constructor() {
super("learningPath");
}
async search(query: string): Promise<LearningPath[]> {
const dtos = await this.get<LearningPathDTO[]>("/", { search: query });
const dtos = await this.get<LearningPathDTO[]>("/", {search: query});
return dtos.map((dto) => LearningPath.fromDTO(dto));
}
async getBy(
hruid: string,
language: Language,
@ -25,8 +27,15 @@ export class LearningPathController extends BaseController {
});
return LearningPath.fromDTO(single(dtos));
}
async getAllByTheme(theme: string): Promise<LearningPath[]> {
const dtos = await this.get<LearningPathDTO[]>("/", { theme });
const dtos = await this.get<LearningPathDTO[]>("/", {theme});
return dtos.map((dto) => LearningPath.fromDTO(dto));
}
async getAllLearningPaths(language: string | null = null): Promise<LearningPath[]> {
const query = language ? { language } : undefined;
const dtos = await this.get<LearningPathDTO[]>("/", query);
return dtos.map((dto) => LearningPath.fromDTO(dto));
}
}

View file

View file

@ -1,8 +1,8 @@
import { type MaybeRefOrGetter, toValue } from "vue";
import type { Language } from "@/data-objects/language.ts";
import { useQuery, type UseQueryReturnType } from "@tanstack/vue-query";
import { getLearningPathController } from "@/controllers/controllers";
import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts";
import {type MaybeRefOrGetter, toValue} from "vue";
import type {Language} from "@/data-objects/language.ts";
import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query";
import {getLearningPathController} from "@/controllers/controllers";
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
const LEARNING_PATH_KEY = "learningPath";
const learningPathController = getLearningPathController();
@ -44,3 +44,15 @@ export function useSearchLearningPathQuery(
enabled: () => Boolean(toValue(query)),
});
}
export function useGetAllLearningPaths(language: MaybeRefOrGetter<string | undefined>
): UseQueryReturnType<LearningPath[], Error> {
return useQuery({
queryKey: [LEARNING_PATH_KEY, "getAllLearningPaths", language],
queryFn: async () => {
const lang = toValue(language);
return learningPathController.getAllLearningPaths(lang);
},
enabled: () => Boolean(toValue(language))
});
}

View file

@ -1,6 +1,6 @@
import { computed, toValue } from "vue";
import type { MaybeRefOrGetter } from "vue";
import { useMutation, useQuery, useQueryClient, UseMutationReturnType, UseQueryReturnType } from "@tanstack/vue-query";
import { useMutation, useQuery, useQueryClient, type UseMutationReturnType, type UseQueryReturnType } from "@tanstack/vue-query";
import { TeacherController, type TeacherResponse, type TeachersResponse } from "@/controllers/teachers.ts";
import type { ClassesResponse } from "@/controllers/classes.ts";
import type { JoinRequestResponse, JoinRequestsResponse, StudentsResponse } from "@/controllers/students.ts";

View file

@ -1,4 +1,3 @@
/**
* Submits the form data to the backend.
*
@ -16,21 +15,21 @@ import type {AssignmentDTO} from "@dwengo-1/common/interfaces/assignment";
export const submitForm = async (
assignmentTitle: string,
selectedLearningPath: any,
selectedLearningPath: string,
selectedClass: string,
groups: string[][],
groups: string[],
deadline: string,
description: string,
currentLanguage: string
) => {
const formData: AssignmentDTO = {
id: 0,
id: 4,
class: selectedClass,
title: assignmentTitle,
description: description,
learningPath: selectedLearningPath,
language: currentLanguage,
groups: [],
language: currentLanguage
//groups: [],
//deadline: deadline,
};

View file

@ -29,7 +29,7 @@ const teacher02: Student = {username: "id12", firstName: "John", lastName: "Hiat
const teacher03: Student = {username: "id13", firstName: "Aaron", lastName: "Lewis", classes: []};
const class01: Class = {
id: "34d484a1-295f-4e9f-bfdc-3e7a23d86a89",
id: "8764b861-90a6-42e5-9732-c0d9eb2f55f9",
displayName: "class 01",
teachers: [teacher01],
students: [student01, student02],

View file

@ -2,7 +2,6 @@
import {useI18n} from "vue-i18n";
import {computed, onMounted, ref, watch} from "vue";
import GroupSelector from "@/components/GroupSelector.vue";
import {classes} from "@/utils/tempData.ts";
import {
assignmentTitleRules,
classRules,
@ -11,39 +10,80 @@
submitForm
} from "@/utils/assignmentForm.ts";
import DeadlineSelector from "@/components/DeadlineSelector.vue";
import auth from "@/services/auth/auth-service.ts";
import {useTeacherClassesQuery} from "@/queries/teachers.ts";
import {useRouter} from "vue-router";
import {useGetAllLearningPaths} from "@/queries/learning-paths.ts";
import UsingQueryResult from "@/components/UsingQueryResult.vue";
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
import type {Language} from "@/data-objects/language.ts";
const router = useRouter();
const {t, locale} = useI18n();
const role = ref(auth.authState.activeRole);
const username = ref<string | null>(null);
onMounted(async () => {
// Redirect student
if (role.value === 'student') {
await router.push('/user');
}
// Get the user's username
const user = await auth.loadUser();
username.value = user?.profile?.preferred_username ?? null;
});
const language = computed(() => locale.value);
//Fetch all learning paths
const learningPathsQueryResults = useGetAllLearningPaths(language);
watch(language, (newLanguage) => {
console.log(newLanguage);
learningPathsQueryResults.refetch();
});
// Fetch and store all the teacher's classes
const { data: classes, isLoading, error, refetch } = useTeacherClassesQuery(username, true);
const allClasses = computed(() => {
if (isLoading.value) {
return [];
}
if (error.value) {
return [];
}
return classes.value?.classes || [];
});
const form = ref();
const language = ref(locale.value);
const searchQuery = ref('');
const assignmentTitle = ref('');
const deadline = ref(null);
const description = ref('');
const allLearningPaths = ref([]);
const filteredLearningPaths = ref([]);
const selectedLearningPath = ref(null);
const allClasses = ref([...classes.map(cl => ({title: cl.displayName, value: cl.id}))]);
const selectedClass = ref(null);
const groups = ref<string[][]>([]);
const availableClass = computed(() => {
//TODO: replace by real data
return classes.find(cl => selectedClass.value?.value === cl.id) || null;
return /*classes.find(cl => selectedClass.value?.value === cl.id) ||*/ null;
});
const allStudents = computed(() => {
//TODO: replace by real data
if (!selectedClass.value) return [];
/*if (!selectedClass.value) return [];
const cl = classes.find(c => c.id === selectedClass.value.value);
return cl ? cl.students.map(st => ({
title: `${st.firstName} ${st.lastName}`,
value: st.username,
classes: cl
})) : [];
})) : [];*/
return [];
});
@ -54,48 +94,13 @@
}
};
async function fetchAllLearningPaths() {
try {
//TODO: replace by function from controller
const response = await fetch(`http://localhost:3000/api/learningPath?language=${language.value}`);
if (!response.ok) throw new Error("Failed to fetch learning paths");
const data = await response.json();
allLearningPaths.value = data.map((lp: { hruid: string; title: string }) => ({
hruid: lp.hruid,
title: lp.title
}));
filteredLearningPaths.value = [...allLearningPaths.value];
} catch (error) {
console.error(error);
}
}
watch(
() => locale.value,
(newLocale) => {
if (!["nl", "en"].includes(newLocale)) {
language.value = "en";
}
fetchAllLearningPaths();
},
{immediate: true}
);
watch(selectedClass, () => {
groups.value = [];
});
const searchResults = computed(() => {
return filteredLearningPaths.value.filter((lp: { hruid: string; title: string }) =>
lp.title.toLowerCase().includes(searchQuery.value.toLowerCase())
);
});
onMounted(fetchAllLearningPaths);
const submitFormHandler = async () => {
const { valid } = await form.value.validate();
// Don't submit thr form if all rules don't apply
// Don't submit the form if all rules don't apply
if (!valid) return;
submitForm(assignmentTitle.value, selectedLearningPath.value?.hruid, selectedClass.value.value, groups.value, deadline.value, description.value, locale.value);
};
@ -113,23 +118,28 @@
density="compact" variant="outlined" clearable required></v-text-field>
</v-card-text>
<v-card-text>
<v-combobox
v-model="selectedLearningPath"
:items="searchResults"
:label="t('choose-lp')"
:rules="learningPathRules"
variant="outlined"
clearable
hide-details
density="compact"
append-inner-icon="mdi-magnify"
item-title="title"
item-value="value"
required
:filter="(item, query: string) => item.title.toLowerCase().includes(query.toLowerCase())"
></v-combobox>
</v-card-text>
<using-query-result
:query-result="learningPathsQueryResults"
v-slot="{ data }: { data: LearningPath[] }"
>
<v-card-text>
<v-combobox
v-model="selectedLearningPath"
:items="data"
:label="t('choose-lp')"
:rules="learningPathRules"
variant="outlined"
clearable
hide-details
density="compact"
append-inner-icon="mdi-magnify"
item-title="title"
item-value="value"
required
:filter="(item, query: string) => item.title.toLowerCase().includes(query.toLowerCase())"
></v-combobox>
</v-card-text>
</using-query-result>
<v-card-text>
<v-combobox
@ -142,8 +152,8 @@
hide-details
density="compact"
append-inner-icon="mdi-magnify"
item-title="title"
item-value="value"
item-title="displayName"
item-value="id"
required
></v-combobox>