Skip to content

Commit

Permalink
Only Available subdivisions shown; Fixed typescript build errors;
Browse files Browse the repository at this point in the history
  • Loading branch information
pranav-suri committed May 5, 2024
1 parent e992d9b commit cbdcaaf
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 92 deletions.
17 changes: 15 additions & 2 deletions src/backend/api/routes/available.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Elysia, t } from "elysia";
import { getAvailableClassrooms, getAvailableTeachers } from "../../controllers";
import { getAvailableClassrooms, getAvailableTeachers, getAvailableSubdivisions } from "../../controllers";

const app = new Elysia({ prefix: "/available" })
.get(
Expand Down Expand Up @@ -43,5 +43,18 @@ const app = new Elysia({ prefix: "/available" })
tags: ["Classrooms"],
},
},
);
)
.get("/subdivisions", async ({ query }) => {
const { slotId, divisionId } = query;
return { subdivisions: await getAvailableSubdivisions(slotId, divisionId) };
}, {
query: t.Object({
slotId: t.Numeric(),
divisionId: t.Numeric(),
}),
detail: {
summary: "Get available subdivisions",
tags: ["Subdivisions"],
},
});
export default app;
2 changes: 0 additions & 2 deletions src/backend/api/upload/dataUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import {
} from "../../database";
import Papa from "papaparse";

// FIXME: #6 @pranav-suri Normalize variable names according to eslint rules

function removeDuplicates<T>(arr: T[]): T[] {
const uniqueArray = arr.filter((value, index) => {
const _value = JSON.stringify(value);
Expand Down
31 changes: 31 additions & 0 deletions src/backend/controllers/getAvailableSubdivisions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Subdivision } from "../database";

export default async function availableSubdivisions(slotId: number, divisionId: number) {
const subdivisions = await Subdivision.findAll({
where: { DivisionId: divisionId },
});
const subdivisionIds = subdivisions.map((subdivision) => subdivision.id);
const busySubdivisions = await Subdivision.findAll({
include: [
{
association: "SlotDataSubdivisions",
where: { SubdivisionId: subdivisionIds },
required: true,
attributes: [],
include: [
{
association: "SlotData",
where: { SlotId: slotId },
required: true,
attributes: [],
},
],
},
],
});
const availableSubdivisions = subdivisions.filter(
(availableSubdivision) =>
!busySubdivisions.some((busySubdivision) => busySubdivision.id === availableSubdivision.id),
);
return availableSubdivisions;
}
26 changes: 11 additions & 15 deletions src/backend/controllers/getAvailableTeachers.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
import { Subject, Teacher } from "../database";
import {getSubjectTeachers} from "./";
import { Teacher } from "../database";
import { getSubjectTeachers } from "./";

async function getAvailableTeachers(slotId: number, subjectId: number) {
const subjectTeachers = await getSubjectTeachers(subjectId);
const subject = await Subject.findByPk(subjectId);
console.log(subject?.toJSON())
// Busy teachers in the given slot
const busyTeachers = await Teacher.findAll({
include: [
{
association: "SlotDatas",
where: { slotId: slotId, subjectId: subjectId},
where: { slotId: slotId, subjectId: subjectId },
required: true,
include: [{
association: "SlotDataSubdivisions",
required: true,
attributes: [],
}]
include: [
{
association: "SlotDataSubdivisions",
required: true,
attributes: [],
},
],
},
],
});
const availableSubjectTeachers = subjectTeachers.filter(
(subjectTeacher) => !busyTeachers.some((teacher) => teacher.id === subjectTeacher.id)
(subjectTeacher) => !busyTeachers.some((teacher) => teacher.id === subjectTeacher.id),
);
console.log(busyTeachers.length)
console.log(availableSubjectTeachers.length)

return availableSubjectTeachers;
}

await getAvailableTeachers(21, 1)

export default getAvailableTeachers;
12 changes: 8 additions & 4 deletions src/backend/controllers/getTimetable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ async function getTimetableBySubdivision(subdivisionId: number) {
},
});
const subjectIds = slotDatas.map((slotData) => slotData.SubjectId);
const subjectIdsFiltered = subjectIds.filter((subjectId) => subjectId) as ForeignKey<number[]>;
const subjects = await Subject.findAll({
where: {
id: subjectIds,
id: subjectIdsFiltered,
},
});

Expand Down Expand Up @@ -141,9 +142,10 @@ async function getTimetableByDivision(divisionId: number) {
});

const subjectIds = slotDatas.map((slotData) => slotData.SubjectId);
const subjectIdsFiltered = subjectIds.filter((subjectId) => subjectId) as ForeignKey<number[]>;
const subjects = await Subject.findAll({
where: {
id: subjectIds,
id: subjectIdsFiltered,
},
});

Expand Down Expand Up @@ -201,9 +203,10 @@ async function getTimetableByTeacher(teacherId: number) {
});
const slotDataIds = slotDatas.map((slotData) => slotData.id);
const subjectIds = slotDatas.map((slotData) => slotData.SubjectId);
const subjectIdsFiltered = subjectIds.filter((subjectId) => subjectId) as ForeignKey<number[]>;
const subjects = await Subject.findAll({
where: {
id: subjectIds,
id: subjectIdsFiltered,
},
});
const slotDataClasses = await SlotDataClasses.findAll({
Expand Down Expand Up @@ -292,9 +295,10 @@ async function getTimetableByClassroom(classroomId: number) {
},
});
const subjectIds = slotDatas.map((slotData) => slotData.SubjectId);
const subjectIdsFiltered = subjectIds.filter((subjectId) => subjectId) as ForeignKey<number[]>;
const subjects = await Subject.findAll({
where: {
id: subjectIds,
id: subjectIdsFiltered,
},
});
const slotDataSubdivisions = await SlotDataSubdivisions.findAll({
Expand Down
2 changes: 0 additions & 2 deletions src/frontend/Components/NavBar/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const NavBar = () => {
// TODO: #7 @MatricalDefunkt Implement the ability to select an academic year, batch, division and thus a timetable

return (
<SelectedValuesProvider>
<AppBar position="fixed" sx={{ padding: "0.5rem" }}>
<Toolbar>
<AcademicYearButton />
Expand All @@ -25,7 +24,6 @@ const NavBar = () => {
<ViewButton />
</Toolbar>
</AppBar>
</SelectedValuesProvider>
);
};

Expand Down
15 changes: 6 additions & 9 deletions src/frontend/Components/Sidebar/ClassroomAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React, { Dispatch, useEffect, useState } from "react";
import { Autocomplete, TextField } from "@mui/material";
import {
ClassroomResponse,
TimetableResponse,
} from "../../../backend/api/routes/responseTypes";
import { ClassroomResponse, TimetableResponse } from "../../../backend/api/routes/responseTypes";
import { edenFetch } from "../fetchAndSet";
import api from "../..";

Expand Down Expand Up @@ -32,23 +29,23 @@ export function ClassroomAutocomplete({
(slotDataClassroom) => slotDataClassroom.Classroom!,
);
const [inputValue, setInputValue] = useState("");
const [value, setValue] = useState<Classrooms>([]);
const [availableClassroomData, setAvailableClassroomData] = useState<Classrooms>([]);
const [value, setValue] = useState<Classrooms>(currentClassrooms);
const [availableClassroomData, setAvailableClassroomData] = useState<Classrooms>([...currentClassrooms]);

useEffect(() => {
if (!subjectId) return;

edenFetch<ClassroomResponse>(
api.available.classrooms.get({ query: { subjectId, slotId } }),
).then((data) => {
const availableClassrooms = data.classrooms ?? [];
const allClassrooms = availableClassrooms.concat(currentClassrooms ?? []);
const availableClassrooms = data.classrooms;
const allClassrooms = availableClassrooms.concat(currentClassrooms);
setAvailableClassroomData(allClassrooms);
setValue(currentClassrooms);
});
// It is the only needed dependency, other dependencies are not needed
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [slotData]);
}, [slotDatas]);

return (
<Autocomplete
Expand Down
29 changes: 10 additions & 19 deletions src/frontend/Components/Sidebar/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
TimetableResponse,
ClassroomResponse,
} from "../../../backend/api/routes/responseTypes";
import { fetchAndSet } from "../fetchAndSet";
import { checkIfSlotDataExists } from "../fetchAndSet";
import api from "../../index";
import { TeacherAutocomplete } from "./TeacherAutocomplete";
import { SubjectAutocomplete } from "./SubjectAutocomplete";
Expand Down Expand Up @@ -54,8 +54,6 @@ export function DrawerRight({
timetableData: TimetableResponse | null;
}) {
const [update, setUpdate] = useState(false);
const [subjects, setSubjects] = useState<SubjectResponse>({ subjects: [] });
const [subdivisions, setSubdivisions] = useState<SubdivisionResponse>({ subdivisions: [] });
const [slotDataIndexToUpdate, setSlotDataIndexToUpdate] = useState<number | null>(null);

function updateSubject(subject: SubjectResponse["subjects"][0] | null, slotDataIndex: number) {
Expand Down Expand Up @@ -114,13 +112,13 @@ export function DrawerRight({
const classroomIds = slotData.SlotDataClasses!.map(
(slotDataClass) => slotDataClass.Classroom!.id,
);
console.log("SlotId: ", slotId);
console.log("SlotDataId: ", slotDataId);
console.log("SubjectId: ", subjectId);
console.log("TeacherId: ", teacherId);
console.log("SubdivIds: : ", subdivisionIds);
console.log("ClassIds: ", classroomIds);
console.log("Rendered");
// console.log("SlotId: ", slotId);
// console.log("SlotDataId: ", slotDataId);
// console.log("SubjectId: ", subjectId);
// console.log("TeacherId: ", teacherId);
// console.log("SubdivIds: : ", subdivisionIds);
// console.log("ClassIds: ", classroomIds);
// console.log("Rendered");

// if (!subjectId || !subdivisionIds.length) return;

Expand All @@ -145,19 +143,13 @@ export function DrawerRight({

const slot = timetableData?.timetable?.slots[selectedSlotIndex!];
const slotDatas =
slot?.SlotDatas?.filter((slotData) => slotData.Subject?.id) || ([] as SlotDatas);
slot?.SlotDatas?.filter(checkIfSlotDataExists) || ([] as SlotDatas);
useEffect(() => {
if (!update || slotDataIndexToUpdate == null) return;
updateSlotData(slotDataIndexToUpdate);
setUpdate(false);
}, [slotDatas, update, slotDataIndexToUpdate]);

useEffect(() => {
// This has to be changed, department can divisionId must come from props or somewhere
fetchAndSet(setSubjects, api.departments({ id: 2 }).subjects.get());
fetchAndSet(setSubdivisions, api.divisions({ id: 2 }).subdivisions.get());
}, []);

useEffect(() => {
if (selectedSlotIndex == null || !slot) return;
// Create a new slotData
Expand Down Expand Up @@ -215,7 +207,6 @@ export function DrawerRight({
{slot.SlotDatas!.map((_, index) => (
<React.Fragment key={index}>
<SubjectAutocomplete
subjects={subjects.subjects}
slotDatas={slot.SlotDatas}
slotDataIndex={index}
updateSubject={updateSubject}
Expand All @@ -239,7 +230,7 @@ export function DrawerRight({
<SubdivisionAutocomplete
slotDatas={slot.SlotDatas}
slotDataIndex={index}
subdivisions={subdivisions.subdivisions}
// subdivisions={subdivisions.subdivisions}
updateSubdivisions={updateSubdivisions}
setSlotDataIndexToUpdate={setSlotDataIndexToUpdate}
setUpdate={setUpdate}
Expand Down
39 changes: 30 additions & 9 deletions src/frontend/Components/Sidebar/SubdivisionAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { Dispatch, useEffect } from "react";
import React, { Dispatch, useContext, useEffect, useState } from "react";
import { Autocomplete, TextField } from "@mui/material";
import { SubdivisionResponse, TimetableResponse } from "../../../backend/api/routes/responseTypes";
import { SelectedValuesContext } from "../../context/SelectedValuesContext";
import { edenFetch } from "../fetchAndSet";
import api from "../..";

// Implementing SubdivisionAutocomplete
type Subdivisions = SubdivisionResponse["subdivisions"];

interface SubdivisionAutocompleteProps {
subdivisions: Subdivisions;
slotDatas: TimetableResponse["timetable"]["slots"][0]["SlotDatas"];
slotDataIndex: number;
updateSubdivisions: (subdivisions: Subdivisions, slotDataIndex: number) => void;
Expand All @@ -15,28 +17,47 @@ interface SubdivisionAutocompleteProps {
}

export function SubdivisionAutocomplete({
subdivisions,
slotDatas,
slotDataIndex,
updateSubdivisions,
setUpdate,
setSlotDataIndexToUpdate,

}: SubdivisionAutocompleteProps) {
const { selectedValues } = useContext(SelectedValuesContext);
const divisionId = Number(selectedValues.division.value);
const slotData = slotDatas![slotDataIndex];
const slotId = slotData.SlotId;
const currentSubdivisions: Subdivisions = slotData.SlotDataSubdivisions!.map(
(slotDataSubdivision) => slotDataSubdivision.Subdivision!,
);
const [inputValue, setInputValue] = React.useState("");
const [value, setValue] = React.useState<Subdivisions>(currentSubdivisions ?? []);
const [value, setValue] = React.useState<Subdivisions>(currentSubdivisions);
const [availableSubdivisionData, setAvailableSubdivisionData] = useState<
SubdivisionResponse["subdivisions"]
>([...currentSubdivisions]);

// useEffect(() => {
// setValue(currentSubdivisions);
// }, [currentSubdivisions]);

useEffect(() => {
setValue(currentSubdivisions);
}, [currentSubdivisions]);
// console.log(selectedValues)
if (!divisionId) return;
edenFetch<SubdivisionResponse>(
api.available.subdivisions.get({ query: { slotId, divisionId } }),
).then((data) => {
const subdivisions = data.subdivisions;
const allSubdivisions = subdivisions.concat(currentSubdivisions ?? []);
setAvailableSubdivisionData(allSubdivisions);
setValue(currentSubdivisions);
});
// It is the only needed dependency, other dependencies are not needed
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [slotDatas]);

return (
<Autocomplete
disableCloseOnSelect
// disableCloseOnSelect
multiple
limitTags={2}
sx={{ margin: "5px" }}
Expand All @@ -53,7 +74,7 @@ export function SubdivisionAutocomplete({
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
options={subdivisions}
options={availableSubdivisionData}
getOptionLabel={(option) => option.subdivisionName}
isOptionEqualToValue={(option, value) => option.id === value.id}
renderInput={(params) => <TextField {...params} label="Subdivisions" />}
Expand Down
Loading

0 comments on commit cbdcaaf

Please sign in to comment.