Skip to content

Commit

Permalink
feat: connect with usos api
Browse files Browse the repository at this point in the history
  • Loading branch information
unewMe committed Sep 9, 2024
1 parent 2763bee commit 4d745a3
Show file tree
Hide file tree
Showing 13 changed files with 1,590 additions and 342 deletions.
1,228 changes: 1,098 additions & 130 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/themes": "^3.1.3",
"@t3-oss/env-nextjs": "^0.11.0",
"@tanstack/react-query": "^5.54.1",
"cheerio": "^1.0.0-rc.12",
Expand Down
44 changes: 25 additions & 19 deletions src/app/api/data/[facultyId]/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @eslint-community/eslint-comments/disable-enable-pair */

import { NextResponse } from "next/server";

import type { ApiResponse } from "@/lib/types";
Expand All @@ -11,26 +13,30 @@ export async function GET(
) {
const service = createUsosService();

return NextResponse.json(
{
registrations: await Promise.all(
(await service.getRegistrations(params.facultyId)).map(async (r) => ({
registration: r,
courses: await Promise.all(
r.related_courses.flatMap(async (c) => ({
course: await service.getCourse(c.course_id),
groups: await service.getGroups(c.course_id, c.term_id),
})),
),
})),
),
},
{
headers: {
"Cache-Control": "public, max-age=3600",
try {
const registrations = await Promise.all(
(await service.getRegistrations(params.facultyId)).map(async (r) => ({
registration: r,
courses: await Promise.all(
r.related_courses.flatMap(async (c) => ({
course: await service.getCourse(c.course_id),
groups: await service.getGroups(c.course_id, c.term_id),
})),
),
})),
);

return NextResponse.json(
{ registrations },
{
headers: { "Cache-Control": "public, max-age=3600" },
},
},
);
);
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
return new Response("Internal Server Error", { status: 500 });
}
}

export type ApiProfileGet = ApiResponse<typeof GET>;
21 changes: 14 additions & 7 deletions src/app/api/registrations/route.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { NextResponse } from "next/server";
import type { Registration, Course, ClassBlockProps } from "@/lib/types";

import type { ClassBlockProps, Course, Registration } from "@/lib/types";

const mockRegistration1 = {
name: "Registration 1",
id: "1",
} satisfies Registration;

const mockRegistration2 = {
name: "Registration 2",
id: "2",
} satisfies Registration;

const mockRegistration3 = {
name: "Registration 3",
id: "3",
} satisfies Registration;

const mockCourse1 = {
Expand Down Expand Up @@ -41,6 +45,7 @@ const mockL = {
startTime: "17:05",
endTime: "19:50",
group: "1",
day: "poniedzi",
courseName: mockCourse1.name,
lecturer: "Jerzy Świątek",
week: "TN",
Expand All @@ -51,6 +56,7 @@ const mockL = {
const mockW = {
startTime: "18:55",
endTime: "19:50",
day: "poniedzi",
group: "2",
courseName: mockCourse2.name,
lecturer: "Jerzy Świątek",
Expand Down Expand Up @@ -83,16 +89,17 @@ export function GET(request: Request) {

// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (name) {
const registration = mockRegistrations.find((reg) => reg.registration.name === name);
const registration = mockRegistrations.find(
(reg) => reg.registration.name === name,
);
if (!registration) {
return NextResponse.json({ error: "Registration not found" }, { status: 404 });
return NextResponse.json(
{ error: "Registration not found" },
{ status: 404 },
);
}
return NextResponse.json(registration);
}


return NextResponse.json(mockRegistrations);
}



121 changes: 89 additions & 32 deletions src/components/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,74 @@
import React, { useState } from "react";

import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import type { ExtendedCourse } from "@/pages/createplan/[id]";
import { Combobox } from "@/components/ui/combobox";
import type { MockRegistration } from "@/lib/types";

const departmentOptions = [
"Filia w Legnicy [FLG]",
"Studium Języków Obcych [PRD/S1]",
"Studium Wychowania Fizycznego i Sportu [PRD/S3]",
"Politechnika Wrocławska [PWR]",
"Wydział Architektury [W1]",
"Wydział Mechaniczny [W10]",
"Wydział Podstawowych Problemów Techniki [W11]",
"Wydział Elektroniki, Fotoniki i Mikrosystemów [W12N]",
"Wydział Matematyki [W13]",
"Wydział Budownictwa Lądowego i Wodnego [W2]",
"Wydział Chemiczny [W3]",
"Wydział Informatyki i Telekomunikacji [W4N]",
"Wydział Elektryczny [W5]",
"Wydział Geoinżynierii, Górnictwa i Geologii [W6]",
"Wydział Zarządzania [W8N]",
"Wydział Mechaniczno-Energetyczny [W9]",
].sort();

export const GroupsAccordion = ({
registrationName,
index,
onClick,
courses,
onDepartmentChange,
onRegistrationChange,
updateDepartmentSelection,
updateRegistrationSelection,
}: {
registrationName: string;
index: number;
onClick: (id: string) => void;
courses: ExtendedCourse[];
onDepartmentChange: (value: string) => Promise<MockRegistration[]>;
onRegistrationChange: () => void;
updateDepartmentSelection: (value: string) => void;
updateRegistrationSelection: (value: string) => void;
}) => {
const [selectedDepartment, setSelectedDepartment] = useState<string | null>(
null,
);

const [selectedRegistration, setSelectedRegistration] = useState<
string | null
>(null);

const [showRegistrationSelect, setShowRegistrationSelect] = useState(false);

const [registrationOptions, setRegistrationOptions] = useState<string[]>([]);

const handleDepartmentChange = async (value: string) => {
setSelectedDepartment(value);
updateDepartmentSelection(value);
const plan = await onDepartmentChange(value);
setShowRegistrationSelect(true);
setRegistrationOptions(plan.map((p) => p.registration.name));
};

const handleRegistrationChange = (value: string) => {
setSelectedRegistration(value);
updateRegistrationSelection(value);
onRegistrationChange();
};

return (
<div className="max-w-96">
<Accordion type="single" collapsible={true} className="">
Expand All @@ -30,33 +82,38 @@ export const GroupsAccordion = ({
</div>
</AccordionTrigger>
<AccordionContent>
{courses.map(
(course) =>
course.registrationName === registrationName && (
<div key={course.name}>
<div className="grid grid-cols-[1fr_5fr] items-center justify-between break-all p-4 py-2 text-base hover:cursor-pointer hover:bg-stone-300">
<div className="flex h-[50px] w-[50px] items-center justify-center rounded-[50px] bg-secondary">
{course.name.slice(0, 1).toUpperCase()}
</div>
<label
htmlFor={`${index}-${course.name}`}
className="ml-4 flex justify-between hover:cursor-pointer"
>
{course.name}
<input
id={`${index}-${course.name}`}
type="checkbox"
onChange={() => {
onClick(course.name);
}}
className="h-6 w-6 cursor-pointer"
checked={course.isChecked}
/>
</label>
</div>
</div>
),
)}
<div className="mt-4">
<label
htmlFor={`department-select-${index}`}
className="block text-sm font-medium text-gray-700"
>
Wybierz wydział:
</label>
<Combobox
id={`department-select-${index}`}
options={departmentOptions}
value={selectedDepartment ?? ""}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onChange={handleDepartmentChange}
/>
</div>

{showRegistrationSelect ? (
<div className="mt-4">
<label
htmlFor={`registration-select-${index}`}
className="block text-sm font-medium text-gray-700"
>
Wybierz rejestrację:
</label>
<Combobox
id={`registration-select-${index}`}
options={registrationOptions}
value={selectedRegistration ?? ""}
onChange={handleRegistrationChange}
/>
</div>
) : null}
</AccordionContent>
</AccordionItem>
</Accordion>
Expand Down
20 changes: 20 additions & 0 deletions src/components/PlanDisplayLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Link from "next/link";
import { useEffect, useState } from "react";

import { cn } from "@/lib/utils";

import { buttonVariants } from "./ui/button";

export function PlanDisplayLink({ hash }: { hash: string }) {
const [linkURL, setLinkURL] = useState("");

useEffect(() => {
setLinkURL(`${window.location.origin}/shareplan/${hash}`);
}, [hash]);

return (
<Link href={linkURL} className={cn(buttonVariants(), "font-semibold")}>
<span>Podgląd</span>
</Link>
);
}
28 changes: 23 additions & 5 deletions src/components/Schedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,61 @@ export const ScheduleTest = ({
groups: ExtendedGroup[];
onClick: (id: string) => void;
}) => {
const filterScheduleByDay = (dayCode: string) => {
return schedule.filter((item) => item.day === dayCode);
};

return (
<div className="flex max-h-[80vh] flex-col gap-2 overflow-auto p-1 scrollbar-thin scrollbar-track-sky-300 scrollbar-thumb-sky-900">
<ClassSchedule
schedule={schedule}
schedule={filterScheduleByDay("poniedzi")}
day="Poniedziałek"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={schedule}
schedule={filterScheduleByDay("wtor")}
day="Wtorek"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={schedule}
schedule={filterScheduleByDay("środ")}
day="Środa"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={schedule}
schedule={filterScheduleByDay("czwart")}
day="Czwartek"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={schedule}
schedule={filterScheduleByDay("piąt")}
day="Piątek"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={filterScheduleByDay("sobot")}
day="Sobota"
courses={courses}
groups={groups}
onClick={onClick}
/>
<ClassSchedule
schedule={filterScheduleByDay("niedziel")}
day="Niedziela"
courses={courses}
groups={groups}
onClick={onClick}
/>
</div>
);
};
Loading

0 comments on commit 4d745a3

Please sign in to comment.