Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6bf9c8c
sidebar component add
kexana Mar 28, 2025
8e291f2
tailwind workin, beggining page building
kexana Mar 28, 2025
9492d09
structure
Dinoxh Mar 28, 2025
d7c45ab
fixed app
Dinoxh Mar 28, 2025
2ad2b52
Main design layout
Dinoxh Mar 28, 2025
e504235
initial sidebar
kexana Apr 2, 2025
368096f
courseView init
kexana Apr 2, 2025
bda6d94
the course page initial tests
LSKpr Apr 2, 2025
80c665a
Make it run on my comuter
Sailet03 Apr 2, 2025
6d27140
Tree without database integration
Sailet03 Apr 3, 2025
b9fbf6b
fixes
Sailet03 Apr 4, 2025
cce6da0
Merge branch 'main' of https://github.com/InferenceKTH/Find-My-Next-C…
Sailet03 Apr 9, 2025
2f64054
npm update
Sailet03 Apr 9, 2025
dc1d233
add to page
Sailet03 Apr 9, 2025
249fee8
Merge branch 'main' into prereq-tree
Sailet03 Apr 9, 2025
697a9b9
Merge branch 'main' into prereq-tree
Sailet03 Apr 9, 2025
b233d1f
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
Sailet03 Apr 9, 2025
e235a7a
Biiiiig Refactoring
Sailet03 Apr 9, 2025
266e079
Broken version of prereq tree
Sailet03 Apr 11, 2025
45f1247
Fixed not rendering anything. Still broken
Sailet03 Apr 11, 2025
abaa804
Working v1
daDevBoat Apr 11, 2025
407425e
handling #prereqs
daDevBoat Apr 11, 2025
764de1d
Merge of Prereq Tree working v1
daDevBoat Apr 11, 2025
cda4065
Test
daDevBoat Apr 11, 2025
0287df4
removed commented out code
Sailet03 Apr 11, 2025
3216309
More info expands now
daDevBoat Apr 11, 2025
a5b6909
More info expands now
daDevBoat Apr 11, 2025
30f7e76
More info expands now
daDevBoat Apr 11, 2025
e748152
Start coding on line 135 in PrereqTreePresenter Mr. PO
daDevBoat Apr 11, 2025
2f067e8
Merge remote-tracking branch 'origin/main' into prereq-oaktree
Sailet03 Apr 16, 2025
88e94f6
Prereqs colored and expands more info
daDevBoat Apr 16, 2025
47e67a8
Prereqs colored and expands more info
daDevBoat Apr 16, 2025
a8ef8ec
Merge branch 'main' of github.com:InferenceKTH/Find-My-Next-Course in…
daDevBoat Apr 16, 2025
810b63f
added css styling
daDevBoat Apr 16, 2025
771b4c9
Fixed copy bug
daDevBoat Apr 16, 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
2 changes: 1 addition & 1 deletion my-app/src/assets/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -145248,4 +145248,4 @@
"prerequisites_text": "null",
"learning_outcomes": "null"
}
}
}
18 changes: 10 additions & 8 deletions my-app/src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,17 @@ export const model = {
entries.forEach(entry => {
const course = {
code: entry[1].code,
name: entry[1]?.name ?? "",
location: entry[1]?.location ?? "",
department: entry[1]?.department ?? "",
language: entry[1]?.language ?? "",
description: entry[1]?.description ?? "",
academicLevel: entry[1]?.academic_level ?? "",
period: entry[1]?.period ?? "",
name: entry[1]?.name ?? "null",
location: entry[1]?.location ?? "null",
department: entry[1]?.department ?? "null",
language: entry[1]?.language ?? "null",
description: entry[1]?.description ?? "null",
academicLevel: entry[1]?.academic_level ?? "null",
period: entry[1]?.period ?? "null",
credits: entry[1]?.credits ?? 0,
prerequisites: entry[1]?.prerequisites ?? "",
prerequisites: entry[1]?.prerequisites ?? "null",
prerequisites_text: entry[1]?.prerequisites_text ?? "null",
learning_outcomes: entry[1]?.learning_outcomes ?? "null"
};
this.addCourse(course);
});
Expand Down
17 changes: 11 additions & 6 deletions my-app/src/presenters/ListViewPresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const ListViewPresenter = observer(({ model }) => {
const addFavourite = (course) => {
model.addFavourite(course);
}
const removeFavourite = (course) => {
const removeFavourite = (course) => {
model.removeFavourite(course);
}
const handleFavouriteClick = (course) => {
Expand All @@ -72,8 +72,13 @@ const ListViewPresenter = observer(({ model }) => {

const [isPopupOpen, setIsPopupOpen] = useState(false);
const [selectedCourse, setSelectedCourse] = useState(null);
const preP = <PrerequisitePresenter model={model} selectedCourse={selectedCourse} />;
const reviewPresenter = <ReviewPresenter model={model} course={selectedCourse}/>;
const preP = <PrerequisitePresenter
model={model}
isPopupOpen={isPopupOpen}
setIsPopupOpen={setIsPopupOpen}
setSelectedCourse={setSelectedCourse}
selectedCourse={selectedCourse} />;
const reviewPresenter = <ReviewPresenter model={model} course={selectedCourse} />;

const popup = <CoursePagePopup
favouriteCourses={model.favourites}
Expand All @@ -82,9 +87,9 @@ const ListViewPresenter = observer(({ model }) => {
handleFavouriteClick={handleFavouriteClick}
isOpen={isPopupOpen} onClose={() => setIsPopupOpen(false)}
course={selectedCourse}
prerequisiteTree={preP}
reviewPresenter={reviewPresenter}/>
prerequisiteTree={preP}
reviewPresenter={reviewPresenter} />



return <ListView
Expand Down
139 changes: 102 additions & 37 deletions my-app/src/presenters/PrerequisitePresenter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export const PrerequisitePresenter = observer((props) => {
let uniqueCounter = 0;
let textCounter = 0;
let codeCounter = 0;
//let toAdd = [];

let input_text_obj = {};

const position = { x: 0, y: 0 };
const edgeType = 'smoothstep';
Expand All @@ -35,11 +36,8 @@ export const PrerequisitePresenter = observer((props) => {
const nodeWidth = 172;
const nodeHeight = 36;

//initialNodes.push(createNode("IK1203", "IK1203", "default"));
//initialNodes.push(createNode("IK1204", "IK1204", "default"));
//initialEdges.push(createEdge(props.selectedCourse.code, "IK1203"));
//initialEdges.push(createEdge(props.selectedCourse.code, "IK1204"));
loadTree(props.selectedCourse.code);
console.log(initialNodes);

const getLayoutedElements = (nodes, edges, direction = 'LR') => {
const isHorizontal = direction === 'LR';
Expand Down Expand Up @@ -79,9 +77,6 @@ export const PrerequisitePresenter = observer((props) => {


const Flow = () => {
//console.log("arived in Flow");


const [nodes, setNodes, onNodesChange] = useNodesState(layoutedNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(layoutedEdges);

Expand All @@ -104,6 +99,7 @@ export const PrerequisitePresenter = observer((props) => {
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onNodeClick={clicked}
connectionLineType={ConnectionLineType.SmoothStep}
fitView
style={{ backgroundColor: 'white', borderRadius: '10px'}}
Expand All @@ -119,8 +115,30 @@ export const PrerequisitePresenter = observer((props) => {
</div>

);
};

function setLabel(id, label) {
setNodes((nodes) =>
nodes.map((n) =>
n.id === id ? { ...n, data: { ...n.data, label } } : n
)
);
}

function clicked(event, node) {
if (node["id"].split(" ")[0] === "text") {
if (node["data"]["label"] === "More Info...") {
node["style"]["zIndex"] = 1;
setLabel(node["id"], <span>{input_text_obj[node["id"]]} <br/> <b style={{ color: 'blue' }}>CLOSE</b></span>);
} else {
node["style"]["zIndex"] = 0;
setLabel(node["id"], "More Info...");
}
} else if (node["data"]["label"] !== "One of these" && node["data"]["label"] !== "No Prerequisites" && node["id"] !== props.selectedCourse.code) {
// ADD FUNCTIONALITY FOR CLICKING COURSE CODE NODE (Tu eres muy retrasado y gordo)! :)
// ONCLICK HERE
}
}
};



Expand All @@ -131,13 +149,15 @@ export const PrerequisitePresenter = observer((props) => {
id: id,
type: node_type,
data: { label: name },
style: { zIndex: 0 },
position,
};
} else {
return {
id: id,
type: node_type,
data: { label: name },
style: { zIndex: 0 },
position,
};

Expand All @@ -148,18 +168,19 @@ export const PrerequisitePresenter = observer((props) => {
}


function prereq_convert(current_object, previous_key, previous_node_id) {
function prereq_convert(courses_taken, current_object, previous_key, previous_node_id) {
let current_node = null;
if (current_object == undefined) {return}

if (!Array.isArray(current_object)) { // Is object
let key = Object.keys(current_object)[0];
//console.log("key: " + key);
if (key == "or") {
initialNodes.push(createNode(key + uniqueCounter, "One of these", "default"));
current_node = createNode(key + uniqueCounter, "One of these", "default")
initialNodes.push(current_node);
initialEdges.push(createEdge(previous_node_id, key + uniqueCounter));
prereq_convert(current_object[key], key, key + uniqueCounter++);
prereq_convert(courses_taken, current_object[key], key, key + uniqueCounter++);
} else if (key == "and") {
prereq_convert(current_object[key], key, previous_node_id);
prereq_convert(courses_taken, current_object[key], key, previous_node_id);
}

} else { // Is an array
Expand All @@ -168,65 +189,109 @@ export const PrerequisitePresenter = observer((props) => {
let input_id = "";
let input_text = current_object[i];
if (current_object[i].startsWith("#")) {
input_text = "More Info..."; //input_text.slice(1, 115);
input_id = "text" + ++textCounter;
input_text = "More Info...";
input_id = "text " + ++textCounter;
input_text_obj[input_id] = current_object[i].slice(1);
} else {
input_id = current_object[i] + " " + ++codeCounter;
}
initialNodes.push(createNode(input_id, input_text, "output"));
let new_node = createNode(input_id, input_text, "output");
if (courses_taken.includes(current_object[i])) {
new_node["style"]["backgroundColor"] = "lightgreen";
current_object[i] = true;
} else {
current_object[i] = false;
}
current_node = new_node;
initialNodes.push(new_node);
initialEdges.push(createEdge(previous_node_id, input_id, "output"));
} else {
prereq_convert(current_object[i], previous_key, previous_node_id);
prereq_convert(courses_taken, current_object[i], previous_key, previous_node_id);
}
}
}
/*

/* STEP 2: Check if an object is true or false based on content of the inner object */

if (typeof current_object == "object" && !Array.isArray(current_object)) {
let key = Object.keys(current_object)[0];
let object_array = current_object[key];
console.log(key);
console.log(object_array);
let num_of_matches = 0;
for (let i = 0; i < object_array.length; i++) {
if (Array.isArray(object_array[i])) {
let num_of_inner_matches = 0;
for (let j = 0; j < object_array[i].length; j++) {
if (object_array[i][j]) {
num_of_inner_matches ++;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
}
}
if (key == "or" && num_of_inner_matches > 0) {
object_array[i] = true; num_of_matches++;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
continue;
}
if (key == "and" && num_of_inner_matches == object_array[i].length) {
object_array[i] = true; num_of_matches++;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
continue;
}
if (key == "or" && num_of_inner_matches > 0) {object_array[i] = true; num_of_matches++; continue;}
if (key == "and" && num_of_inner_matches == object_array[i].length) {object_array[i] = true; num_of_matches++; continue;}
object_array[i] = false;
} else if (typeof object_array[i] == "object") {
let inner_key = Object.keys(object_array[i])[0];
if (object_array[i][inner_key]) {num_of_matches++;}
} else if(object_array[i]) {num_of_matches++}
}
if (key == "or" && num_of_matches > 0) {current_object[key] = true}
else if (key == "and" && num_of_matches == object_array.length) {current_object[key] = true}
if (key == "or" && num_of_matches > 0) {
current_object[key] = true;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
}
else if (key == "and" && num_of_matches == object_array.length) {
current_object[key] = true;
if (current_node != null) {
current_node["style"]["backgroundColor"] = "lightgreen";
}
}
else {current_object[key] = false}

}
*/

}

function generateTree(prereqs) {
console.log(JSON.stringify(prereqs, null, 4));
prereq_convert(prereqs, null, props.selectedCourse.code);
function generateTree(courses_taken, prereqs) {
prereq_convert(courses_taken, prereqs, null, props.selectedCourse.code);
let key = Object.keys(prereqs);
return prereqs[key];

}


function loadTree(course) {
let root = createNode(props.selectedCourse.code, props.selectedCourse.code, "input")
initialNodes.push(root);
function loadTree(courses_taken) {

console.log(JSON.stringify(props.selectedCourse.prerequisites, null, 4));
if (props.selectedCourse.prerequisites === "null" || props.selectedCourse.prerequisites.length == 0) {
let display_node = createNode("No Prerequisites", "No Prerequisites", "default");
display_node.style["pointerEvents"] = "none";
display_node["className"] = 'no-handles';
initialNodes.push(display_node);
} else {
let root = createNode(props.selectedCourse.code, props.selectedCourse.code, "input");
let copy = JSON.parse(JSON.stringify(props.selectedCourse.prerequisites));
let eligible = generateTree(JSON.parse(localStorage.getItem("completedCourses")), copy);
if (eligible) {
root["style"]["backgroundColor"] = "lightgreen";
}
initialNodes.push(root);
}

generateTree(props.selectedCourse.prerequisites);

console.log(initialNodes);
console.log(initialEdges);
}

/* return <PrerequisiteTreeView initialNodes={initialNodes} initialEdges={initialEdges} /> */
Expand Down
4 changes: 4 additions & 0 deletions my-app/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
.font-kanit {
font-family: var(--font-kanit);
}

.react-flow__node.no-handles .react-flow__handle {
display: none;
}