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
23 changes: 21 additions & 2 deletions capstone-showcase/backend/ProductionServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -928,13 +928,32 @@ app.get("/api/winners", (req, res) => {
WHEN MONTH(submitDate) IN (9, 10, 11) THEN 'Fall'
END AS semester
FROM survey_entries
WHERE position IS NOT NULL;`;
db.query(sql, (err, results) => {
WHERE position IS NOT NULL`; // Sort winners pages by ascending position
const params = [];
// Adding filters to the SQL query if they are provided
if (semester && semester !== 'all') {
const semMap = { sp: 'Spring', su: 'Summer', fa: 'Fall', wi: 'Winter' }; // Mapping 'sp' to 'Spring', etc., to match CASE statement results
sql += ` AND CASE
WHEN MONTH(submitDate) IN (12, 1, 2) THEN 'Winter'
WHEN MONTH(submitDate) IN (3, 4, 5) THEN 'Spring'
WHEN MONTH(submitDate) IN (6, 7, 8) THEN 'Summer'
WHEN MONTH(submitDate) IN (9, 10, 11) THEN 'Fall'
END = ?`;
params.push(semMap[semester] || semester);
}
if (year && year !== 'all') {
sql += ` AND YEAR(submitDate) = ?`;
params.push(year);
}
sql += ` ORDER BY position ASC;`; // ordering results by ascending position
db.query(sql, params, (err, results) => {
if (err) {
console.error("Error retrieving winners data:", err);
return res.status(500).send("Server error");
}
console.log("Query results:", results);
console.log("Executed SQL:", sql);
console.log("With Params:", params);
res.json(results);
});
});
Expand Down
29 changes: 25 additions & 4 deletions capstone-showcase/backend/localServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,10 @@ app.get("/api/winners", async (req, res) => {
// Ensuring all below necessary columns exist locally first
await ensureColumns("survey_entries", LOCAL_DBSCHEMA.survey_entries_Columns);

const { semester, year } = req.query; // Get filters from the URL query string
// The below "SELECT" code needs to match the "survey_entries_Columns" constant above.
// Any additions the below code makes needs to be reflected in the "survey_entries_Columns" constant above
const sql = `SELECT
let sql = `SELECT
Major AS course,
youtubeLink AS video,
position AS position,
Expand All @@ -562,14 +563,34 @@ app.get("/api/winners", async (req, res) => {
WHEN MONTH(submitDate) IN (9, 10, 11) THEN 'Fall'
END AS semester
FROM survey_entries
WHERE position IS NOT NULL
ORDER BY submitDate DESC, position ASC;`;
db.query(sql, (err, results) => {
WHERE position IS NOT NULL`;
//ORDER BY position ASC;`; // Sort winners pages by ascending position
//ORDER BY submitDate DESC, position ASC;`; // this is the old local sort
const params = [];
// Adding filters to the SQL query if they are provided
if (semester && semester !== 'all') {
const semMap = { sp: 'Spring', su: 'Summer', fa: 'Fall', wi: 'Winter' }; // Mapping 'sp' to 'Spring', etc., to match CASE statement results
sql += ` AND CASE
WHEN MONTH(submitDate) IN (12, 1, 2) THEN 'Winter'
WHEN MONTH(submitDate) IN (3, 4, 5) THEN 'Spring'
WHEN MONTH(submitDate) IN (6, 7, 8) THEN 'Summer'
WHEN MONTH(submitDate) IN (9, 10, 11) THEN 'Fall'
END = ?`;
params.push(semMap[semester] || semester);
}
if (year && year !== 'all') {
sql += ` AND YEAR(submitDate) = ?`;
params.push(year);
}
sql += ` ORDER BY position ASC;`; // ordering results by ascending position
db.query(sql, params, (err, results) => {
if (err) {
console.error("Error retrieving winners data:", err);
return res.status(500).send("Server error");
}
console.log("Query results:", results);
console.log("Executed SQL:", sql);
console.log("With Params:", params);
res.json(results);
});
});
Expand Down
14 changes: 13 additions & 1 deletion capstone-showcase/src/Components/WinnerComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
import "../CSS/WinnerComponent.css";

import { Link } from "react-router-dom";

const displayDepartmentMap: Record<string, string> = {
"computer-science": "Computer Science",
"computer-systems-engineering": "Computer Systems Engineering",
"biomedical-engineering": "Biomedical Engineering",
"mechanical-engineering": "Mechanical Engineering",
"electrical-engineering": "Electrical Engineering",
"industrial-engineering": "Industrial Engineering",
"informatics": "Informatics",
"interdisciplinary": "Interdisciplinary",
};

type ShowcaseEntry = {
course: string;
id: number;
Expand Down Expand Up @@ -104,7 +116,7 @@ export function WinnerComponent({ winners }: { winners: ShowcaseEntry[] }) {
{winner.semester} {winner.year}
</span>
<span className="winner-component__winner-department">
{winner.department || "Computer Science"}
{displayDepartmentMap[winner.course] || winner.course || "General Engineering"}
</span>
</div>
<p className="winner-component__winner-description">
Expand Down
53 changes: 46 additions & 7 deletions capstone-showcase/src/Hooks/useWinners.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom"; // To detect when URL changes, to force hook fetch data whenever user clicks something in the top nav

export type ShowcaseEntry = {
course: string;
Expand All @@ -24,6 +25,7 @@ interface Filters {
};

export default function useWinners() {
const location = useLocation(); // To listen to URL changes
const [pastWinnersData, setPastWinnersData] = useState<ShowcaseEntry[]>([]);
const [filteredWinnersData, setFilteredWinnersData] = useState<ShowcaseEntry[]>([]);
const [hasFiltered, setHasFiltered] = useState(false);
Expand All @@ -36,16 +38,27 @@ export default function useWinners() {

const currentYear = new Date().getFullYear();
const years = Array.from({ length: currentYear - 2000 + 1 }, (_, i) => 2000 + i);
const API_BASE_URL =
import.meta.env.PROD
const API_BASE_URL = import.meta.env.PROD
? "/api" // Relative URL - will use https://showcase.asucapstone.com/api
: "http://localhost:3000/api";
// EFFECT 1: Sync URL with Data
// Rruns whenever URL changes (e.g., clicking "Fall 2024" in Nav)
useEffect(() => {
fetch(`${API_BASE_URL}/winners`)
const queryParams = new URLSearchParams(location.search);
const urlSem = queryParams.get("semester") || "all";
const urlYear = queryParams.get("year") || "all";
setFilters(prev => ({ ...prev, semester: urlSem, year: urlYear })); // Update the dropdown states to match the URL

// Fetch from backend using URL params
fetch(`${API_BASE_URL}/winners?semester=${urlSem}&year=${urlYear}`)
.then((res) => res.json())
.then((data) => setPastWinnersData(data))
.then((data) => {
setPastWinnersData(data);
setHasFiltered(false); // Resets in-page filtering when moving to new year
setSearchValue("");
})
.catch(() => setPastWinnersData([]));
}, []);
}, [location.search]); // Triggered by URL changes

const departmentMap: Record<string, string> = {
"computer-science": "CS/E",
Expand Down Expand Up @@ -92,11 +105,37 @@ export default function useWinners() {
setFilteredWinnersData(searched);
};

// This handles the "In-Page" filter button
const handleFilterSubmit = (e?: React.FormEvent) => {
e?.preventDefault();
setHasFiltered(true);
const filtered = applySelectFilters(pastWinnersData, filters);
setFilteredWinnersData(filtered);

let results = [...pastWinnersData]; // To filter the data we already fetched for specific year

// Apply Department filter
if (filters.department !== "all") {

const prefix = departmentMap[filters.department]; // e.g., "CS/E"
results = results.filter((entry) => {
const matchesMajor = entry.course === filters.department; // Matches the official Major
const matchesPrefix = entry.ProjectTitle.startsWith(prefix); // OR title starts with the Department Code (CS/E, MEE, etc.)
return matchesMajor || matchesPrefix;
});

// old filter
//const deptKey = departmentMap[filters.department];
//results = results.filter(entry => entry.ProjectTitle.includes(deptKey));
}

// Apply Search text
if (searchValue) {
results = applyTextSearch(results, searchValue);
}
setFilteredWinnersData(results);

// old filter
//const filtered = applySelectFilters(pastWinnersData, filters);
//setFilteredWinnersData(filtered);
};

const clearFilters = (e?: React.MouseEvent) => {
Expand Down