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
154 changes: 93 additions & 61 deletions app/CalculatorSessions/page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import React, { useState, useEffect } from "react";
import axios from "axios";
import {
Card,
CardHeader,
Expand All @@ -10,102 +11,133 @@ import {
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { useRouter } from "next/navigation";

function SavedSessions() {
const router = useRouter();

// State to store all saved sessions and user search text
const [sessions, setSessions] = useState([]);
const [grades, setGrades] = useState([]);
const [search, setSearch] = useState("");

// Utilize local storage to load saved sessions
const fetchGrades = async () => {
try {
const userId = 1;
const response = await axios.get(
`http://localhost:8080/api/grade-calculator/grade-entries/${userId}`
);
console.log(response.data);
setGrades(response.data);
} catch (error) {
console.error("Error fetching saved sessions: ", error);
// setSessions([]);
}
};
useEffect(() => {
const saved = JSON.parse(localStorage.getItem("savedSessions")) || [];
setSessions(saved);
fetchGrades();
}, []);

// Function to delete a session via ID
const handleDelete = (id) => {
// remove session from the session list
const updated = sessions.filter((session) => session.id !== id);
setSessions(updated);
// axios function to delete a session via ID
const handleDelete = async (id) => {
try {
await axios.delete(
`http://localhost:8080/api/grade-calculator/grade-entry/${id}`
);
// remove session from the session list
const updated = grades.filter((grade) => grade.id !== id);
setGrades(updated);
} catch (error) {
console.error("Error deleting session: ", error);
alert("Failed to delete session. Please try again.");
}
};

// handle edit by redirecting user to Grade Calculator via entry ID
const handleEdit = (id) => {
router.push(`/GradeCalculator?editId=$[id]`);
};

// Filter sessions based on user search text input (note: case-insensitive)
const filteredSessions = sessions.filter((session) =>
session.title.toLowerCase().includes(search.toLowerCase())
// Filter assignments based on user search text input (note: case-insensitive)
const filteredGrades = grades.filter((grade) =>
grade.assignment_name.toLowerCase().includes(search.toLowerCase())
);

return (
<div className="min-h-screen flex flex-col items-center bg-white p-6">
{/* Page Title*/}
<h1 className="text-2xl font-bold mb-4">Saved Sessions</h1>
{/* Page Title and "Save Session" button aligned right*/}
<div className="relative w-full max-w-4xl mb-4 h-10 flex items-center">
<h1 className="absolute left-1/2 -translate-x-1/2 text-2xl font-bold">
Saved Assignments
</h1>
<Button
className="ml-auto"
onClick={() => router.push("/GradeCalculator")}
>
New Assignment
</Button>
</div>

{/* Search Input */}
<Input
type="text"
placeholder="Search by session title"
placeholder="Search by assignment title"
value={search}
onChange={(e) => setSearch(e.target.value)}
className="mb-4 w-full max-w-lg"
/>

{/* List of filtered sessions */}
{/* List of assignments */}
<div className="w-full max-w-4xl space-y-4">
{filteredSessions.map((session) => (
{filteredGrades.map((grade) => (
<Card
key={session.id}
className="p-4 flex justify-between items-center"
key={grade.id}
className="p-4 shadow-md rounded-2xl hover:shadow-lg transition"
>
<div>
<CardHeader>
<CardTitle>{session.title}</CardTitle>
</CardHeader>

{/* Assignments within session card */}
<CardContent>
{session.assignments.map((a, i) => (
<div key={i} className="flex gap-4">
<span>{a.assignment_type}</span>
<span>{a.assignment_name}</span>
<span>{a.grade} %</span>
<span>{a.weight}%</span>
</div>
))}
</CardContent>
</div>

{/* Delete button and trash icon*/}
<CardFooter>
<button
type="button"
onClick={() => handleDelete(session.id)}
className="text-red-500 hover:text-red-700"
<CardHeader>
<CardTitle className="text-lg font-semibold text-gray-800 text-center">
{grade.assignment_name}
</CardTitle>
</CardHeader>
<CardContent className="text-sm text-gray-600 space-y-1 text-center">
<p>
<span className="font-medium">Assignment Type:</span>{" "}
{grade.assignment_type ?? "N/A"}
</p>
<p>
<span className="font-medium">Grade:</span>{" "}
{grade.assignment_grade ?? "N/A"}
</p>
<p>
<span className="font-medium">Weight:</span>{" "}
{grade.assignment_weight ?? "N/A"}%
</p>
</CardContent>
<CardFooter className="flex justify-end gap-3">
{/* <Button
variant="outline"
size="sm"
onClick={() => handleEdit(grade.id)}
>
Edit
</Button> */}
<Button
variant="destructive"
size="sm"
onClick={() => handleDelete(grade.id)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5-4h4m-4 0a1 1 0 00-1 1v1h6V4a1 1 0 00-1-1m-4 0h4"
/>
</svg>
</button>
Delete
</Button>
</CardFooter>
</Card>
))}

{/* Message to user when no sessions match their text search*/}
{filteredSessions.length === 0 && (
<p className="text-center text-gray-500">No sessions found.</p>
{grades.length === 0 && (
<p className="text-center text-gray-500">No grades found.</p>
)}
</div>
</div>
);
}

export default SavedSessions;
export default SavedSessions;
Loading