Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
da166c7
applied filters into the search function using flags in the model, wi…
boldizsarbenedek Apr 16, 2025
190a822
wrote departments filter option
boldizsarbenedek Apr 16, 2025
c61814b
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
a865fa4
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
7ca07a1
added check to make sure to not recommend courses the client has take…
boldizsarbenedek Apr 16, 2025
df2872b
initial state good
kexana Apr 16, 2025
000d882
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
41c4cfe
commit?
boldizsarbenedek Apr 16, 2025
d8f1543
departments go to model
kexana Apr 16, 2025
b162882
trying to add filtering out courses with NULL fields as an implementa…
boldizsarbenedek Apr 16, 2025
1ca3881
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
170e1b4
merging into brain?
boldizsarbenedek Apr 16, 2025
c33ceb3
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
9d9bf3e
merging/
boldizsarbenedek Apr 16, 2025
855f4ab
some ?. properties check, because skill issue
boldizsarbenedek Apr 16, 2025
fce40c0
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
boldizsarbenedek Apr 16, 2025
fb0554b
more course?. things
boldizsarbenedek Apr 16, 2025
05f9fd2
finished the noNull feature, essentially fixed typos
boldizsarbenedek Apr 16, 2025
f1ac1bf
null course checkbox
kexana Apr 16, 2025
917184e
null check linked
kexana Apr 16, 2025
b41e5a8
Null field toggle works
kexana Apr 16, 2025
2d2a84a
rebase to main
kexana May 7, 2025
db72583
nice and beutiful
kexana May 7, 2025
a97fa17
rebase with main
kexana May 7, 2025
17cb87c
removed the explicit null string checks, hopefully doesnt break, also…
boldizsarbenedek May 7, 2025
4dc5311
period filter
kexana May 7, 2025
95b9000
a bit polishing, touching on the period presenter since i thought its…
boldizsarbenedek May 7, 2025
401ce83
fixed some filters logic (level filter, period filter), added descrip…
boldizsarbenedek May 8, 2025
20c98a5
visually persistent filters
kexana May 8, 2025
a0925dd
check period filter
kexana May 8, 2025
882f7a1
good filters merge
kexana May 8, 2025
3518e20
now fixed
kexana May 8, 2025
1ae1a5b
once again
kexana May 8, 2025
bf5401c
pulling main and merging
boldizsarbenedek May 8, 2025
36abf33
unlocking departments and locations
boldizsarbenedek May 8, 2025
1f83e38
wip
kexana May 8, 2025
40e26eb
filters enabled by clicking on them
kexana May 8, 2025
0c5047f
My side merge with Dean's side
boldizsarbenedek May 8, 2025
c81034b
departments half functional
kexana May 9, 2025
73a2f38
rebase to main
kexana May 9, 2025
7fefd1f
rebase to main
kexana May 9, 2025
16497c4
rebase to main
kexana May 9, 2025
1d77e0f
Merge branch 'main' of https://github.com/jkluge/Find-My-Next-Course …
kexana May 9, 2025
1b0e488
Refactoring transcript scraper (#126)
boldizsarbenedek May 9, 2025
7a48c87
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 9, 2025
6b30175
fixed couple errors relating to the new LocaleStorage finished course…
boldizsarbenedek May 9, 2025
a182c12
fixed a lot of typos (deparmen != department)
boldizsarbenedek May 9, 2025
466adef
trying to add hover over tooltips such that it displayes name of course
boldizsarbenedek May 9, 2025
e4b8f52
inbetween
kexana May 9, 2025
a5036e1
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 9, 2025
dc2463a
removing the console.logs because theyre dumb and we should remove th…
boldizsarbenedek May 13, 2025
6e7775f
department percistency done only SU and Education Office broken
kexana May 13, 2025
0d5d816
even more documentation, added descriptions and cleared up toolTips o…
boldizsarbenedek May 13, 2025
5131b25
Merge branch 'responsive-filtering' of github.com:InferenceKTH/Find-M…
boldizsarbenedek May 13, 2025
144b302
departments should be working
kexana May 14, 2025
9b4bf95
nothing really
boldizsarbenedek May 14, 2025
dbc3deb
work on upload bahaviour
kexana May 14, 2025
4436fdf
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 14, 2025
d077a32
merge-rebase w main
boldizsarbenedek May 14, 2025
2b6a3f7
fix of animated gif
boldizsarbenedek May 14, 2025
bb05ec0
fixed upload
kexana May 14, 2025
c0a37c8
Merge branch 'responsive-filtering' of https://github.com/jkluge/Find…
kexana May 14, 2025
c6bc4d3
merge main
kexana May 14, 2025
4ed4590
merge main
kexana May 14, 2025
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
1,866 changes: 1,751 additions & 115 deletions my-app/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions my-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"firebase": "^11.5.0",
"fuse.js": "^7.1.0",
"ldrs": "^1.1.6",
"lint": "^0.8.19",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"mobx": "^6.13.7",
Expand Down
3 changes: 0 additions & 3 deletions my-app/src/presenters/FilterPresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ const FilterPresenter = observer(({ model }) => {
model.filteredCourses = filteredCourses;
}, [filteredCourses]);



/* functions declared here are generally things the main function of this observer takes and runs if the given filters are enabled,
* this is determined through model.filterOptions.apply*Insert filter name* flags.
* This presenter should be changed such that it uses side-effects instead model.filtersChange flag, since
Expand Down Expand Up @@ -414,7 +412,6 @@ const FilterPresenter = observer(({ model }) => {
}

/* function that should run every single time the model changes (see note below) */

/* the problem is that unless using sideeffects, the run() not being async and/or it setting the filterschange = false very early can mean
* that 0 courses will get put into the model.filtered courses (which is the list of courses getting passed to search, and then listview)
* therefore TODO: rework it to stop using this dumb flags we started before learning anything about react,observers,js
Expand Down
6 changes: 3 additions & 3 deletions my-app/src/presenters/SidebarPresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const SidebarPresenter = observer(({ model }) => {

useEffect(() => {
model.setFiltersChange();
},[]);
},[model]);

function handleLanguageFilterChange(param) {
if (param === "English") {
Expand Down Expand Up @@ -219,9 +219,9 @@ const SidebarPresenter = observer(({ model }) => {
const handleFileChange = (event) => {
const truncatedCourses = model.courses.map(({ id, name }) => ({ id, name }));
const file = event.target.files[0];
//document.getElementById('PDF-Scraper-Error').style.visibility = "visible";
document.getElementById('PDF-Scraper-Error').style.visibility = "visible";
transcriptScraperFunction(file, setErrorMessage, setErrorVisibility, reApplyFilter, truncatedCourses);
//document.getElementById('PDF-Scraper-Input').value = '';
document.getElementById('PDF-Scraper-Input').value = '';
setFileInputValue('');


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function ButtonGroupField(props) {
};
return (
<div className="my-1">
<div className="flex flex-col sm:inline-flex sm:flex-row rounded-lg shadow-2xs
<div className="flex sm:inline-flex rounded-lg shadow-2xs
w-full items-center font-medium text-white bg-[#aba8e0]">
{props.items.map((item, index) => (
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import FilterEnableCheckbox from "./FilterEnableCheckbox";
import Tooltip from "./ToolTip";

const CollapsibleCheckboxes = (props) => {
const [expandedLabel, setExpandedLabel] = useState(props?.initialValues?.map(i => i?.label));
const [expanded, setExpanded] = useState([]);
const [filterEnabled, setFilterEnabled] = useState(props.filterEnable);
const [checkedSubItems, setCheckedSubItems] = useState({});
Expand Down Expand Up @@ -83,7 +82,7 @@ const CollapsibleCheckboxes = (props) => {
setInitalLoad(false);
setExpanded(tempExpanded);
}
}, [rows]);
}, [rows, initalLoad, props?.initialValues]);



Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useRef, forwardRef } from "react";
import Tooltip from "./ToolTip";
import { useState, forwardRef } from "react";

export default function CourseTranscriptList(props) {
const CourseTranscriptList = forwardRef((props,ref) => {
let local = [];
if (localStorage.getItem("completedCourses"))
local = JSON.parse(localStorage.getItem("completedCourses"));
Expand Down Expand Up @@ -31,14 +30,11 @@ export default function CourseTranscriptList(props) {
localStorage.setItem("completedCourses", JSON.stringify(newitems));
window.dispatchEvent(new Event("completedCourses changed"));
props.reApplyFilter();
if (props.checkboxRef && props.checkboxRef.current) {
props.checkboxRef.current.click();
}
ref.current.click();
};


//=====================================
const tooltipRef = useRef(null);

const tooltipClasses = [
"absolute",
Expand Down Expand Up @@ -80,25 +76,25 @@ export default function CourseTranscriptList(props) {
<div
className="absolute inset-0 mt-30 pointer-events-none bg-gradient-to-b from-transparent to-[#553d65] z-100"
></div>
<div className="grid grid-cols-3 w-full max-[1200px]:grid-cols-2 max-[700px]:grid-cols-1 gap-1 sm:gap-2 overflow-y-auto overflow-x-hidden max-h-[180px] pb-10" style={{
<div className="grid grid-cols-3 w-full max-[1200px]:grid-cols-2 gap-1 sm:gap-2 overflow-y-auto overflow-x-hidden max-h-[180px] pb-10" style={{
scrollbarWidth: "thin",
scrollbarColor: "#888 #f1f1f1",
}}>
{items.map((item, index) => (
<div
key={index}
className="flex items-center bg-[#aba8e0] px-3 py-1 rounded-md shadow-md text-sm min-w-18 relative"
className="flex items-center bg-[#aba8e0] px-3 py-1 rounded-md shadow-md text-sm min-w-18"
>
<div className="relative">
<span className="flex-auto mr-2 peer">{item?.id}</span>

<div className={tooltipClasses}>
{item?.name + (item?.is_in_DB ? "" : " (Course discontinued)")}
{item?.name}
</div>
</div>
<button
onClick={() => removeItem(index)}
className="text-violet-600 hover:text-red-700 font-bold text-sm hover:bg-red-300 rounded-md absolute right-2 top-1/2 -translate-y-1/2"
className="text-violet-600 hover:text-red-700 font-bold text-sm hover:bg-red-300 rounded-md"
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -120,4 +116,6 @@ export default function CourseTranscriptList(props) {
</div>
</div>
);
}
});

export default CourseTranscriptList;
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function MultipleChoiceButtons(props) {

useEffect(() => {
setFilterEnabled(props.filterEnable);
})
},[props.filterEnable])

const handleClick = (index) => {
setSelectedItems((prev) => {
Expand All @@ -36,17 +36,18 @@ export default function MultipleChoiceButtons(props) {
return "default-button-class"; // Fallback class for invalid index
}

const baseClasses = `flex-auto py-1 px-4 inline-flex items-center gap-x-2 text-sm
font-medium focus:z-10 border border-gray-200 shadow-2xs hover:bg-[#8785ac]
focus:outline-hidden disabled:opacity-50 disabled:pointer-events-none pl-8`;
const baseClasses = `flex-auto py-1 px-4 inline-flex items-center text-sm
font-medium focus:z-10 border border-gray-200 shadow-2xs hover:bg-[#8785ac]
focus:outline-hidden sm:pl-7 pl-4 text-center`;
const activeClass = selectedItems[index] ? "bg-violet-500" : "bg-transparent";
const roundedClasses =
index === 0
? "rounded-l-lg"
: index === props.items.length - 1
? "rounded-r-lg"
: "border-l-0";
return `${baseClasses} ${activeClass} ${roundedClasses}`;
? "rounded-l-lg"
: index === props.items.length - 1
? "rounded-r-lg"
: "border-l-0 ";
const mobileClasses = "w-full sm:w-auto"; // Adjust for mobile
return `${baseClasses} ${activeClass} ${roundedClasses} ${mobileClasses}`;
};

return (
Expand Down Expand Up @@ -74,7 +75,7 @@ export default function MultipleChoiceButtons(props) {
}}>

<div className="my-1">
<div className="flex flex-col sm:inline-flex sm:flex-row rounded-lg shadow-2xs
<div className="flex sm:inline-flex rounded-lg shadow-2xs
w-full items-center font-medium text-white bg-[#aba8e0]">
{props.items.map((item, index) => (
<button
Expand Down
18 changes: 10 additions & 8 deletions my-app/src/views/Components/SideBarComponents/SliderField.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useState, useRef, useEffect } from "react";
import React, { useState, useRef, useEffect, useMemo } from "react";
import FilterEnableCheckbox from "./FilterEnableCheckbox";
import Tooltip from "./ToolTip";

export default function UploadField(props) {
let paramFieldType = "slider";

const values = [

const values = useMemo(() => [
1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5,
6, 7, 7.5, 8, 8.5, 9, 10, 11, 12, 13.5,
14, 15, 20, 22.5, 30, 45
];
], []);

const [minIndex, setMinIndex] = useState(0);
const [maxIndex, setMaxIndex] = useState(values.length - 1);
Expand All @@ -19,14 +20,15 @@ export default function UploadField(props) {

useEffect(() => {
for (let i = 0; i < values.length; i++) {
if (values[i] === props.initialValues[0]) {
if (values[i] === props?.initialValues[0]) {
setMinIndex(i);
}
if (values[i] === props.initialValues[1]) {
if (values[i] === props?.initialValues[1]) {
setMaxIndex(i);
}
}
}, []); // Empty dependency array ensures this runs only once
}, [props?.initialValues, values]); // Empty dependency array ensures this runs only once



const handleDrag = (e, thumbType) => {
Expand Down Expand Up @@ -110,7 +112,7 @@ export default function UploadField(props) {
window.addEventListener("mousemove", move);
window.addEventListener("mouseup", up);
}}
onTouchStart={(e) => {
onTouchStart={() => {
const move = (ev) => handleDrag(ev, "min");
const end = () => {
window.removeEventListener("touchmove", move);
Expand Down Expand Up @@ -139,7 +141,7 @@ export default function UploadField(props) {
window.addEventListener("mousemove", move);
window.addEventListener("mouseup", up);
}}
onTouchStart={(e) => {
onTouchStart={() => {
const move = (ev) => handleDrag(ev, "max");
const end = () => {
window.removeEventListener("touchmove", move);
Expand Down
6 changes: 4 additions & 2 deletions my-app/src/views/Components/SideBarComponents/ToggleField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ export default function ToggleField(props) {
let paramFieldType = "toggle";

const [filterEnabled, setFilterEnabled] = useState(props.filterEnable);
const [prop1Set, setprop1Set] = useState((props.initialValues=="both") || (props.initialValues==String(props.fields[0]).charAt(0).toLowerCase() + String(props.fields[0]).slice(1)));
//eslint-disable-next-line @typescript-eslint/no-unused-vars
const [prop1Set, setprop1Set] = useState((props.initialValues == "both") || (props.initialValues == String(props.fields[0]).charAt(0).toLowerCase() + String(props.fields[0]).slice(1)));
//eslint-disable-next-line @typescript-eslint/no-unused-vars
const [prop2Set, setprop2Set] = useState((props.initialValues=="both") || (props.initialValues==String(props.fields[1]).charAt(0).toLowerCase() + String(props.fields[1]).slice(1)));

const checkboxRef = useRef(null);
Expand Down Expand Up @@ -36,7 +38,7 @@ export default function ToggleField(props) {
checkboxRef.current.click();
}
}}>
<div className="flex flex-col sm:flex-row md:flex-row rounded-lg shadow-2xs w-full items-center
<div className="flex sm:flex-row rounded-lg shadow-2xs w-full items-center
font-medium text-white bg-[#aba8e0] ">
<label className="flex-auto py-3 px-4 inline-flex gap-x-2 -mt-px -ms-px
first:rounded-t-md last:rounded-b-md sm:first:rounded-s-md sm:mt-0 sm:first:ms-0 s
Expand Down
34 changes: 18 additions & 16 deletions my-app/src/views/Components/SideBarComponents/UploadField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import FilterEnableCheckbox from "./FilterEnableCheckbox";
//import * as scraper from '../../../../src/scripts/transcript-scraper/transcript-scraper.js';
import ButtonGroupField from './ButtonGroupField';
import ToolTip from './ToolTip';
import UploadGif from "../../../assets/upload.gif";

export default function UploadField(props) {

Expand All @@ -27,8 +28,7 @@ export default function UploadField(props) {
setIsDragging(false);
if (event.dataTransfer.files.length > 0) {
props.handleFileChange({ target: { files: event.dataTransfer.files } });
setfileUploaded(localStorage.getItem("completedCourses") != undefined);
console.log(localStorage.getItem("completedCourses") != undefined);
setfileUploaded(true);
}
};

Expand All @@ -39,20 +39,20 @@ export default function UploadField(props) {
<h3>{String(props.filterName).charAt(0).toUpperCase() + String(props.filterName).slice(1)} scraper</h3>
</div>

<div className={`pt-1 flex-none ${!fileUploaded? "hidden" : ""}`}>
<div className={`pt-1 flex-none ${!fileUploaded ? "hidden" : ""}`}>

<FilterEnableCheckbox
ref={checkboxRef}
initialValue={filterEnabled}
onToggle={() => {
setFilterEnabled(!filterEnabled);
props.HandleFilterEnable(["transcript", !filterEnabled]);
}}
}}
/>
</div>
</div>
<div></div>
<div className={`${(!fileUploaded) ? ("opacity-100") : (filterEnabled? "opacity-100": "opacity-50")}`} onClick={() => {
<div className={`${(!fileUploaded) ? ("opacity-100") : (filterEnabled ? "opacity-100" : "opacity-50")}`} onClick={() => {
if (!filterEnabled && checkboxRef.current) {
checkboxRef.current.click();
}
Expand All @@ -73,32 +73,34 @@ export default function UploadField(props) {
/>
</div>
<div className="flex flex-col items-center justify-center pt-5">
<img src="..\..\..\..\src\assets\upload.gif" alt="Upload GIF" className="object-contain" />
<img src={UploadGif} alt="Upload GIF" className="object-contain" />
<p className=" text-sm "><span className="font-semibold">Click to upload</span> or drag and drop</p>
<p className="text-xs">National Official Transcript of Records in PDF format</p>
</div>
<input
id="PDF-Scraper-Input"
type="file"
className="hidden"
id="PDF-Scraper-Input"
type="file"
className="hidden"
onChange={(event) => {
props.handleFileChange(event);
setfileUploaded(true);
}} />
}} />
</label>
</div>
<ButtonGroupField
items={["Weak", "Moderate", "Strong"]}
HandleFilterChange={props.HandleFilterChange}
initialValue={props.initialValue}
/>
<div className={`${(!fileUploaded) ? ("opacity-50 pointer-events-none") : (filterEnabled ? "opacity-100" : "opacity-50")}`}>
<ButtonGroupField
items={["Weak", "Moderate", "Strong"]}
HandleFilterChange={props.HandleFilterChange}
initialValue={props.initialValue}
/>
</div>
</div>
<div className='max-w-70'>
<pre id="PDF-Scraper-Error" className={`text-red-500 text-xs text-wrap ${props.errorVisibility}`}>
{props.errorMessage}
</pre>
</div>
<div className={`${(filterEnabled? "opacity-100": "opacity-50")} ${filterEnabled ? "pointer-events-auto" : "pointer-events-none user-select-none"
<div className={`${(filterEnabled ? "opacity-100" : "opacity-50")} ${filterEnabled ? "pointer-events-auto" : "pointer-events-none user-select-none"
}`}>
<CourseTranscriptList
reApplyFilter={props.reApplyFilter}
Expand Down