From d0d6f31095a20b95359f2d9ddfce11c09882ad30 Mon Sep 17 00:00:00 2001 From: Ahmon Date: Sat, 26 Apr 2025 00:49:56 -0700 Subject: [PATCH 01/16] [add] feat: Implement auth checks in CourseMap, enhance UI - Add authentication checks to CourseMap component to handle logged-in/out states, disabling features and preventing API calls for logged-out users. - Replace navigation Links with styled Buttons in App and AgreementViewerPage. - Introduce CustomCourseNode for React Flow and apply it in CourseMap. - Overhaul application styling in App.css for a modern look and feel. fix: Correct major/dept fetching and API category code - Fix bug in AgreementViewerPage where 'dept' category was not fetched correctly if 'major' returned empty. - Fix bug in college_transfer_API.py where category_code was sometimes hardcoded instead of using the provided parameter. refactor: Improve caching, state management, and logging - Refine caching logic for majors and images in AgreementViewerPage. - Improve state management and cache updates in CourseMap for map creation, loading, saving, and deletion. - Add console logs to PdfViewer for debugging. --- .../college_transfer_API.py | 10 +- src/App.css | 142 ++++++++++------ src/App.jsx | 34 +++- src/components/AgreementViewerPage.jsx | 131 ++++++++++----- src/components/CourseMap.jsx | 151 +++++++++++++----- src/components/CustomCourseNode.jsx | 55 +++++++ src/components/PdfViewer.jsx | 5 + 7 files changed, 396 insertions(+), 132 deletions(-) create mode 100644 src/components/CustomCourseNode.jsx diff --git a/backend/college_transfer_ai/college_transfer_API.py b/backend/college_transfer_ai/college_transfer_API.py index fc71d86..0c432bf 100644 --- a/backend/college_transfer_ai/college_transfer_API.py +++ b/backend/college_transfer_ai/college_transfer_API.py @@ -69,7 +69,7 @@ def get_all_majors(self, sending_institution_id, receiving_institution_id, acade # sending_institution_id = 61 # receiving_institution_id = 79 # academic_year_id = 75 - # category_code = "major" + category_code = "major" # Define the API endpoint and parameters @@ -108,8 +108,14 @@ def get_major_from_key(self, key): sending_institution_id = int(keyArray[1]) receiving_institution_id = int(keyArray[3]) academic_year_id = int(keyArray[0]) + category_code = "major" + + if "Department" in key: + category_code = "dept" + + url = f"https://assist.org/api/agreements?receivingInstitutionId={receiving_institution_id}&sendingInstitutionId={sending_institution_id}&academicYearId={academic_year_id}&categoryCode={category_code}" - url = f"https://assist.org/api/agreements?receivingInstitutionId={receiving_institution_id}&sendingInstitutionId={sending_institution_id}&academicYearId={academic_year_id}&categoryCode=major" + print(url) result = requests.get(url) diff --git a/src/App.css b/src/App.css index 6e2e23c..7749adb 100644 --- a/src/App.css +++ b/src/App.css @@ -1,129 +1,181 @@ /* Reset and Base Styles */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + + body { - font-family: Arial, Helvetica, sans-serif; /* Common sans-serif font */ + /* Use a modern system font stack */ + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; margin: 0; padding: 0; - background-color: #f0f0f0; /* Light gray background like assist.org */ - color: #333; /* Standard dark text color */ + /* Placeholder background - replace with actual college images */ + background-size: cover; + background-position: center; + background-attachment: fixed; /* Keep background fixed during scroll */ + color: #333; line-height: 1.6; + font-size: 16px; /* Slightly larger base font */ } /* Container for centering content */ #root > div { /* Target the main div rendered by React */ - margin: 20px auto; /* Center the container */ - padding: 20px; - background-color: #fff; /* White background for content area */ - border: 1px solid #ccc; /* Subtle border */ - box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* Slight shadow */ + margin: 40px auto; /* More vertical margin */ + padding: 30px 40px; /* Increased padding */ + /* Slightly transparent white background */ + background-color: rgba(255, 255, 255, 0.95); + border: 1px solid #e0e0e0; /* Softer border */ + border-radius: 8px; /* Rounded corners */ + box-shadow: 0 6px 18px rgba(0,0,0,0.12); /* Slightly stronger shadow */ + /* Add a subtle fade-in animation */ + animation: fadeIn 0.5s ease-out forwards; } h1, h2, h3 { - color: #003366; /* Dark blue for headings */ + color: #1a2b4d; /* Darker, less saturated blue */ margin-top: 0; + margin-bottom: 1em; /* Consistent bottom margin */ + font-weight: 600; /* Slightly bolder */ +} + +h1 { + font-size: 2.2em; /* Larger H1 */ + text-align: center; /* Center main title */ + margin-bottom: 1.5em; } /* Form Styling */ .form-group { - margin-bottom: 1rem; - position: relative; /* Needed for absolute positioning of dropdown */ + margin-bottom: 1.5rem; /* Increased spacing */ + position: relative; + /* Add transition for potential future effects */ + transition: all 0.3s ease-in-out; } label { display: block; - margin-bottom: 0.5rem; - font-weight: bold; + margin-bottom: 0.6rem; + font-weight: 500; /* Medium weight */ color: #555; + font-size: 0.95em; } input[type="text"], -select { /* Style both text inputs and selects similarly */ - padding: 8px 12px; - width: 100%; /* Full width within the container */ - border: 1px solid #ccc; - border-radius: 4px; - box-sizing: border-box; /* Include padding and border in width */ +select { + padding: 12px 15px; /* More padding */ + width: 100%; + border: 1px solid #d1d5db; /* Slightly darker border */ + border-radius: 6px; /* More rounded corners */ + box-sizing: border-box; font-size: 1rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; /* Smooth transitions */ +} + +input[type="text"]:focus, +select:focus { + outline: none; + border-color: #3b82f6; /* Blue focus border */ + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); /* Subtle blue glow */ } input[type="text"]:disabled { - background-color: #e9ecef; /* Gray out disabled inputs */ + background-color: #f3f4f6; /* Lighter disabled background */ cursor: not-allowed; + color: #9ca3af; } /* Button Styling */ button { - background-color: #005ea2; /* Assist.org primary blue */ + background-image: linear-gradient(to right, #3b82f6, #2563eb); /* Blue gradient */ color: white; border: none; - padding: 10px 20px; - border-radius: 4px; + padding: 12px 25px; /* More padding */ + border-radius: 6px; cursor: pointer; - font-size: 1rem; - transition: background-color 0.2s ease; - display: inline-block; /* Allow setting width if needed, but default to content size */ - width: auto; /* Override previous 100% width */ - margin-bottom: 0; /* Remove default margin */ + font-size: 1.05rem; /* Slightly larger font */ + font-weight: 500; + transition: all 0.2s ease; /* Transition all properties */ + display: inline-block; + width: auto; + margin-bottom: 0; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* Subtle shadow */ } button:hover { - background-color: #003366; /* Darker blue on hover */ + background-image: linear-gradient(to right, #2563eb, #1d4ed8); /* Darker gradient on hover */ + box-shadow: 0 4px 8px rgba(0,0,0,0.15); /* Slightly larger shadow on hover */ + transform: translateY(-2px); /* Slightly more lift effect */ +} + +button:active { + transform: translateY(0); /* Remove lift on click */ + box-shadow: 0 1px 2px rgba(0,0,0,0.1); } button:disabled { - background-color: #a0a0a0; /* Gray out disabled button */ + background-image: none; /* Remove gradient */ + background-color: #9ca3af; /* Gray out disabled button */ cursor: not-allowed; + box-shadow: none; + transform: none; } /* Result Area */ .result { margin-top: 25px; - padding: 15px; + padding: 20px; /* Increased padding */ border: 1px solid #ddd; - background-color: #f8f8f8; - border-radius: 4px; + background-color: #f8f9fa; /* Slightly different background */ + border-radius: 6px; /* Match other elements */ + animation: fadeIn 0.5s ease-out forwards; /* Fade in results */ } .result h3 { margin-top: 0; - color: #555; + color: #495057; /* Slightly darker heading */ } /* Dropdown Styling */ .dropdown { position: absolute; background-color: white; - border: 1px solid #ccc; - border-top: none; /* Attach visually to input */ + border: 1px solid #d1d5db; /* Match input border */ + border-top: none; max-height: 250px; overflow-y: auto; - width: 100%; /* Match input width */ + width: 100%; box-sizing: border-box; z-index: 1000; - box-shadow: 0 4px 8px rgba(0,0,0,0.1); - border-radius: 0 0 4px 4px; /* Rounded bottom corners */ + box-shadow: 0 6px 12px rgba(0,0,0,0.1); /* Slightly larger shadow */ + border-radius: 0 0 6px 6px; /* Match input rounding */ + margin-top: -1px; /* Overlap slightly with input */ } .dropdown-item { - padding: 8px 12px; + padding: 10px 15px; /* More padding */ cursor: pointer; font-size: 0.95rem; - border-bottom: 1px solid #eee; /* Separator lines */ + border-bottom: 1px solid #f3f4f6; /* Lighter separator */ + transition: background-color 0.15s ease, color 0.15s ease; /* Smooth hover */ } .dropdown-item:last-child { border-bottom: none; } .dropdown-item:hover { - background-color: #e9f5ff; /* Light blue hover */ - color: #005ea2; + background-color: #eff6ff; /* Very light blue hover */ + color: #1d4ed8; /* Darker blue text on hover */ } -/* Link Styling (e.g., Back to Form in PdfViewer) */ +/* Link Styling */ a { - color: #005ea2; + color: #2563eb; /* Match button blue */ text-decoration: none; + transition: color 0.2s ease; } a:hover { + color: #1d4ed8; /* Darker blue on hover */ text-decoration: underline; } \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 2c05e64..27c3761 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; -import { Routes, Route, Link, useNavigate } from 'react-router-dom'; +// Import useNavigate +import { Routes, Route, useNavigate } from 'react-router-dom'; import { GoogleLogin, googleLogout } from '@react-oauth/google'; import { jwtDecode } from "jwt-decode"; import CollegeTransferForm from './components/CollegeTransferForm'; @@ -46,7 +47,7 @@ function App() { return null; // Default to null }); - const navigate = useNavigate(); + const navigate = useNavigate(); // Get navigate function // Function to handle successful login const handleLoginSuccess = (credentialResponse) => { @@ -105,19 +106,39 @@ function App() { {/* Navigation/Header remains the same */}