mirror of
https://github.com/AmanTahiliani/PeerNotes.git
synced 2026-08-07 11:55:12 -04:00
second screen draft
This commit is contained in:
41
frontend/package-lock.json
generated
41
frontend/package-lock.json
generated
@@ -9,7 +9,8 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.22.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.64",
|
"@types/react": "^18.2.64",
|
||||||
@@ -569,6 +570,14 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@remix-run/router": {
|
||||||
|
"version": "1.15.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
|
||||||
|
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.13.0",
|
"version": "4.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
|
||||||
@@ -2373,6 +2382,36 @@
|
|||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "6.22.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||||
|
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.15.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "6.22.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
|
||||||
|
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@remix-run/router": "1.15.3",
|
||||||
|
"react-router": "6.22.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8",
|
||||||
|
"react-dom": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve-from": {
|
"node_modules/resolve-from": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.22.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.64",
|
"@types/react": "^18.2.64",
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.App {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center; /* If you're centering the content */
|
||||||
|
height: 100vh; /* Full height */
|
||||||
|
margin-top: -100px; /* Move up */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #0C2D48;
|
||||||
|
font-family: 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
import './App.css'
|
import './App.css'
|
||||||
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||||
import MainSearch from './components/MainSearch';
|
import MainSearch from './components/MainSearch';
|
||||||
|
import Results from './components/Results';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<BrowserRouter>
|
||||||
<div className="App" style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100vh' , gap: 15}}>
|
<div className="App">
|
||||||
<img
|
<header style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100px', gap: 15 }}>
|
||||||
src="/PeerNotes.png"
|
</header>
|
||||||
alt="PeerNotes Logo"
|
<Routes>
|
||||||
style={{
|
<Route path="/" element={<MainSearch />} />
|
||||||
height: "100px"
|
<Route path="/results" element={<Results />} />
|
||||||
}}
|
</Routes>
|
||||||
/>
|
</div>
|
||||||
<MainSearch />
|
</BrowserRouter>
|
||||||
</div>
|
);
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|||||||
@@ -1,38 +1,73 @@
|
|||||||
import React from 'react';
|
import React, { useState, FormEvent } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import '../screens/MainScreenWrapper.css';
|
import '../screens/MainScreenWrapper.css';
|
||||||
|
|
||||||
|
interface Filters {
|
||||||
|
professor: string;
|
||||||
|
course: string;
|
||||||
|
topic: string;
|
||||||
|
}
|
||||||
|
|
||||||
const MainSearch: React.FC = () => {
|
const MainSearch: React.FC = () => {
|
||||||
|
const [filters, setFilters] = useState<Filters>({
|
||||||
|
professor: '',
|
||||||
|
course: '',
|
||||||
|
topic: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const { name, value } = event.target;
|
||||||
|
setFilters((prevFilters: Filters) => ({
|
||||||
|
...prevFilters,
|
||||||
|
[name]: value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
var input = filters.toString()
|
||||||
|
const searchParams = new URLSearchParams(input)
|
||||||
|
navigate(`/results?${searchParams}`);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="filter-container">
|
<>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<img src="/PeerNotes.png" alt="PeerNotes Logo" className="logo" />
|
||||||
|
</div>
|
||||||
|
<form onSubmit={handleSubmit} className="filter-container">
|
||||||
<div className="filter-item">
|
<div className="filter-item">
|
||||||
<label htmlFor="professors">Professors:</label>
|
<label htmlFor="professors">Professors:</label>
|
||||||
<select id="professors">
|
<select id="professors" name="professor" value={filters.professor} onChange={handleChange}>
|
||||||
<option value="">Select a Professor</option>
|
<option value="">Select a Professor</option>
|
||||||
{/* temporary */}
|
{/* temporary options */}
|
||||||
<option value="professor1">Professor 1</option>
|
<option value="professor1">Professor 1</option>
|
||||||
<option value="professor2">Professor 2</option>
|
<option value="professor2">Professor 2</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="filter-item">
|
<div className="filter-item">
|
||||||
<label htmlFor="courses">Course:</label>
|
<label htmlFor="courses">Course:</label>
|
||||||
<select id="courses">
|
<select id="courses" name="course" value={filters.course} onChange={handleChange}>
|
||||||
<option value="">Select a Course</option>
|
<option value="">Select a Course</option>
|
||||||
{/* temporary */}
|
{/* temporary options */}
|
||||||
<option value="course1">Course 1</option>
|
<option value="course1">Course 1</option>
|
||||||
<option value="course2">Course 2</option>
|
<option value="course2">Course 2</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="filter-item">
|
<div className="filter-item">
|
||||||
<label htmlFor="topics">Topic:</label>
|
<label htmlFor="topics">Topic:</label>
|
||||||
<select id="topics">
|
<select id="topics" name="topic" value={filters.topic} onChange={handleChange}>
|
||||||
<option value="">Select a Topic</option>
|
<option value="">Select a Topic</option>
|
||||||
{/* temporary */}
|
{/* temporary options */}
|
||||||
<option value="topic1">Topic 1</option>
|
<option value="topic1">Topic 1</option>
|
||||||
<option value="topic2">Topic 2</option>
|
<option value="topic2">Topic 2</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className="submit-button">Submit</button>
|
<button type="submit" className="submit-button">Submit</button>
|
||||||
</div>
|
</form>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
69
frontend/src/components/Results.tsx
Normal file
69
frontend/src/components/Results.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import styles from '../screens/Results.module.css'; // Make sure this path is correct
|
||||||
|
|
||||||
|
interface File {
|
||||||
|
id: string;
|
||||||
|
name: string; // do we even use id and name?
|
||||||
|
professor: string;
|
||||||
|
course: string;
|
||||||
|
type?: string; // Assumed type is optional
|
||||||
|
// what other properties to add?semester?
|
||||||
|
}
|
||||||
|
|
||||||
|
const Results: React.FC = () => {
|
||||||
|
const [files, setFiles] = useState<File[]>([]);
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchFiles = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// Need to double check this
|
||||||
|
const queryString = location.search; // Includes the '?' prefix
|
||||||
|
const response = await fetch(`/api/path-to-filefilterview${queryString}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
setFiles(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not fetch files", e);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchFiles();
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
|
const handleSearchAgain = () => {
|
||||||
|
navigate('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) return <div>Loading...</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.wrapper}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<img src="/PeerNotes.png" alt="PeerNotes Logo" className={styles.logo} />
|
||||||
|
<button onClick={handleSearchAgain} className={styles.searchAgainButton}>Search Again</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles.resultsContainer}>
|
||||||
|
{isLoading ? (
|
||||||
|
<p>Loading...</p>
|
||||||
|
) : files.length ? (
|
||||||
|
<table className={styles.resultsTable}>
|
||||||
|
{/* Table structure here */}
|
||||||
|
</table>
|
||||||
|
) : (
|
||||||
|
<p>No results found.</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Results;
|
||||||
@@ -15,9 +15,16 @@ html, body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #B1D4E0;
|
background: #B1D4E0;
|
||||||
|
gap: 15;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* shadow */
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* shadow */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 100px; /* Adjust this value as needed */
|
||||||
|
width: auto; /* Keep the logo's aspect ratio */
|
||||||
|
margin-bottom: 15px; /* Gap between logo and search box */
|
||||||
|
}
|
||||||
|
|
||||||
.filter-item + .filter-item {
|
.filter-item + .filter-item {
|
||||||
margin-top: 20px; /* space between filter items */
|
margin-top: 20px; /* space between filter items */
|
||||||
|
|||||||
57
frontend/src/screens/Results.module.css
Normal file
57
frontend/src/screens/Results.module.css
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #145DA0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 80px; /* Adjust according to preference */
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.resultsContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 100px; /* Adjust based on header height to ensure content doesn't overlap */
|
||||||
|
margin: auto;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resultsTable {
|
||||||
|
/* to be filled out */
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.searchAgainButton {
|
||||||
|
height: 50px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background-color: #0C2D48;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 35px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchAgainButton:hover {
|
||||||
|
background-color: #B1D4E0; /* lighter shade for hover effect */
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user