Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/actions/v2/get-class-group-dates.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";
Expand Down
34 changes: 26 additions & 8 deletions src/actions/v2/get-course-edition-details.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";

import type { LecturerDTO, UsosLecturer } from "./get-lecturer";

interface UsosCourseEdition {
course_id: string;
term_id: string;
course_units_ids: string[] | null;
}

function normalizeLecturers(lecturers: UsosLecturer[]): LecturerDTO[] {
return lecturers.map((lecturer) => {
return {
id: lecturer.id,
firstName: lecturer.first_name,
lastName: lecturer.last_name,
titlesBefore: lecturer.titles?.before ?? null,
titlesAfter: lecturer.titles?.after ?? null,
photoUrl: lecturer.photo_urls?.["50x50"] ?? null,
homepageUrl: lecturer.homepage_url ?? null,
profileUrl: lecturer.profile_url ?? null,
};
});
}

interface UsosCourseUnitGroup {
course_unit_id: string;
group_number: number;
lecturer_ids: string[] | null;
lecturers: UsosLecturer[];
}

interface UsosCourseUnit {
id: string;
classtype_id: string;
use_groups: boolean;
groups: UsosCourseUnitGroup[] | null;
}

export interface CourseGroupDTO {
unitId: string;
groupNumber: string;
classtypeId: string;
lecturerIds: string[];
lecturers: LecturerDTO[];
}

export interface CourseEditionDetailsDTO {
Expand All @@ -37,18 +55,18 @@ export interface CourseEditionDetailsDTO {
async function fetchCourseUnitGroups(
unitId: string,
): Promise<CourseGroupDTO[]> {
const data = await fetchUsosApi<UsosCourseUnit>("courses/course_unit", {
const data = await fetchUsosApi<UsosCourseUnit>("courses/unit", {
unit_id: unitId,
fields: "id|classtype_id|use_groups|groups[group_number|lecturer_ids]",
fields: "id|classtype_id|groups[group_number|lecturers]",
});

if (!data.use_groups || data.groups == null || data.groups.length === 0) {
if (data.groups == null || data.groups.length === 0) {
return [
{
unitId: data.id,
groupNumber: "1",
classtypeId: data.classtype_id,
lecturerIds: [],
lecturers: [],
},
];
}
Expand All @@ -57,7 +75,7 @@ async function fetchCourseUnitGroups(
unitId: data.id,
groupNumber: String(group.group_number),
classtypeId: data.classtype_id,
lecturerIds: group.lecturer_ids ?? [],
lecturers: normalizeLecturers(group.lecturers),
}));
}

Expand Down
2 changes: 2 additions & 0 deletions src/actions/v2/get-course-editions-details.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";
Expand Down
2 changes: 2 additions & 0 deletions src/actions/v2/get-course-editions-preview.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import { createHash } from "node:crypto";

import redis from "@/lib/redis";
Expand Down
62 changes: 39 additions & 23 deletions src/actions/v2/get-course-groups-for-planner.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import type { GroupSchedulePattern } from "@/lib/utils/build-group-schedule-pattern";
"use server";

import type {
GroupSchedulePattern,
ScheduleParity,
} from "@/lib/utils/build-group-schedule-pattern";
import { buildGroupSchedulePattern } from "@/lib/utils/build-group-schedule-pattern";
import type { ClassgroupDate } from "@/types";

import { getClassgroupDatesAction } from "./get-class-group-dates";
import type { CourseGroupDTO } from "./get-course-edition-details";
import { getCourseEditionDetailsAction } from "./get-course-edition-details";
import type { LecturerDTO } from "./get-lecturer";
import { getLecturerAction } from "./get-lecturer";
import { getTermAction } from "./get-term";

export interface PlannerGroupDTO {
unitId: string;
Expand Down Expand Up @@ -34,15 +39,40 @@ function toClassgroupDates(
}));
}

async function fetchGroupWithPattern(group: CourseGroupDTO): Promise<{
function daysBetween(a: string, b: string): number {
const msPerDay = 1000 * 60 * 60 * 24;
return Math.round((new Date(b).getTime() - new Date(a).getTime()) / msPerDay);
}

async function getSchedulePatternParity(
termId: string,
classGroupStartTime: string,
): Promise<ScheduleParity> {
const term = await getTermAction(termId);
const weekNumber =
Math.floor(daysBetween(classGroupStartTime, term.startDate) / 7) + 1;
return weekNumber % 2 === 0 ? "odd" : "even";
}

async function fetchGroupWithPattern(
group: CourseGroupDTO,
termId: string,
): Promise<{
group: CourseGroupDTO;
schedulePattern: GroupSchedulePattern | null;
}> {
const dates = await getClassgroupDatesAction(group.unitId, group.groupNumber);
const classgroupDates = toClassgroupDates(dates);
const schedulePattern = buildGroupSchedulePattern(classgroupDates);
if (schedulePattern?.pattern === "biweekly") {
schedulePattern.parity = await getSchedulePatternParity(
termId,
dates[1].startTime ?? "",
);
}
return {
group,
schedulePattern: buildGroupSchedulePattern(classgroupDates),
schedulePattern,
};
}

Expand All @@ -52,31 +82,17 @@ export async function getPlannerCourseGroupsAction(
): Promise<PlannerGroupDTO[]> {
const editionDetails = await getCourseEditionDetailsAction(courseId, termId);

const [groupsWithPatterns, lecturersMap] = await Promise.all([
Promise.all(
editionDetails.groups.map(async (group) => fetchGroupWithPattern(group)),
const groupsWithPatterns = await Promise.all(
editionDetails.groups.map(async (group) =>
fetchGroupWithPattern(group, termId),
),
(async () => {
const uniqueLecturerIds = [
...new Set(editionDetails.groups.flatMap((g) => g.lecturerIds)),
];
const lecturerEntries = await Promise.all(
uniqueLecturerIds.map(async (id) => {
const lecturer = await getLecturerAction(id);
return [id, lecturer] as const;
}),
);
return new Map<string, LecturerDTO>(lecturerEntries);
})(),
]);
);

return groupsWithPatterns.map(({ group, schedulePattern }) => ({
unitId: group.unitId,
groupNumber: group.groupNumber,
classtypeId: group.classtypeId,
lecturers: group.lecturerIds
.map((id) => lecturersMap.get(id))
.filter((l): l is LecturerDTO => l != null),
lecturers: group.lecturers,
schedulePattern,
}));
}
97 changes: 97 additions & 0 deletions src/actions/v2/get-faculties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
interface Faculty {
value: string;
name: string;
}

interface getFacultiesDTO {
data: Faculty[];
isLoading: boolean;
isError: boolean;
}

//in future can be replaced with database get

export function getFacultiesAction(): getFacultiesDTO {
return {
data: [
{
value: "W1",
name: "Wydział Architektury",
},
{
value: "W2",
name: "Wydział Budownictwa Lądowego i Wodnego",
},
{
value: "W3",
name: "Wydział Chemiczny",
},
{
value: "W4N",
name: "Wydział Informatyki i Telekomunikacji",
},
{
value: "W5",
name: "Wydział Elektryczny",
},
{
value: "W6",
name: "Wydział Geoinżynierii, Górnictwa i Geologii",
},
{
value: "W7",
name: "Wydział Inżynierii Środowiska",
},
{
value: "W8N",
name: "Wydział Zarządzania",
},
{
value: "W9",
name: "Wydział Mechaniczno-Energetyczny",
},
{
value: "W10",
name: "Wydział Mechaniczny",
},
{
value: "W11",
name: "Wydział Podstawowych Problemów Techniki",
},
{
value: "W12",
name: "Wydział Elektroniki, Fotoniki i Mikrosystemów",
},
{
value: "W13",
name: "Wydział Matematyki",
},
{
value: "W14",
name: "Wydział Medyczny",
},
{
value: "FLG",
name: "Filia w Legnicy",
},
{
value: "SD1",
name: "Szkoła Doktorska Politechniki Wrocławskiej",
},
{
value: "PRK24/S1",
name: "PRK24/S1",
},
{
value: "PRK24/S3",
name: "PRK24/S3",
},
{
value: "PWR",
name: "PWR",
},
],
isLoading: false,
isError: false,
};
}
2 changes: 2 additions & 0 deletions src/actions/v2/get-faculty-registrations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";
Expand Down
4 changes: 3 additions & 1 deletion src/actions/v2/get-lecturer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";

interface UsosLecturer {
export interface UsosLecturer {
id: string;
first_name: string;
last_name: string;
Expand Down
5 changes: 3 additions & 2 deletions src/actions/v2/get-registration-rounds.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";
Expand Down Expand Up @@ -37,10 +39,9 @@ export async function getRegistrationRoundsAction(
`registrations/course_registration_rounds`,
{
registration_id: registrationId,
fields: "fields=id|name|status|registration_mode|start_date|end_date",
fields: "id|name|status|registration_mode|start_date|end_date",
},
);

return data.toSorted(sortByStartDateFunction);
},
});
Expand Down
2 changes: 2 additions & 0 deletions src/actions/v2/get-round-courses.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";
Expand Down
48 changes: 48 additions & 0 deletions src/actions/v2/get-term.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use server";

import redis from "@/lib/redis";
import { getOrSetRedis } from "@/lib/redis/get-set";
import { fetchUsosApi } from "@/lib/usos";

interface TermDTO {
id: string;
name: string;
startDate: string;
endDate: string;
finishDate: string;
isActive: boolean;
}

interface UsosTerm {
id: string;
name: { pl: string };
start_date: string;
end_date: string;
finish_date: string;
is_active: boolean;
}

function normalizeTerm(data: UsosTerm): TermDTO {
return {
id: data.id,
name: data.name.pl,
startDate: data.start_date,
endDate: data.end_date,
finishDate: data.finish_date,
isActive: data.is_active,
};
}

export async function getTermAction(termId: string): Promise<TermDTO> {
return getOrSetRedis({
redis,
key: `usos:term:${termId}:`,
ttlSeconds: 60 * 60 * 24 * 7,
fetcher: async () => {
const data = await fetchUsosApi<UsosTerm>("terms/term", {
term_id: termId,
});
return normalizeTerm(data);
},
});
}
Loading
Loading