refiling and api call for search (#11)

* refiling and api call for search

* updating allowed hosts

* update search

* proper api call

* search page working

* navbar

* small fixes

* fix types

---------

Co-authored-by: Sahej Panag <spanag3@gatech.edu>
Co-authored-by: afazio1 <alexa.fazio04@gmail.com>
This commit is contained in:
Sahej Panag
2024-04-20 23:22:45 -04:00
committed by GitHub
parent 5089a36bf7
commit 9e618803ed
12 changed files with 233 additions and 97 deletions

View File

@@ -21,8 +21,15 @@ export default function Login() {
},
body: JSON.stringify({ username, password }),
})
.then(() => {
navigate('/');
.then(response => response.json())
.then(data => {
console.log("Login response data:", data);
if (data.token) {
// localStorage.setItem('authToken', data.token);
navigate('/search');
} else {
console.error('No token received:', data);
}
})
.catch((error) => {
console.error('Error:', error);

View File

@@ -0,0 +1,148 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import '../styles/MainScreenWrapper.css';
import { getSessionCookie } from '../contexts/session';
import { Professor, Course, Topic } from "../types/types";
interface Filters extends Record<string, string> {
professor: string;
course: string;
topic: string;
}
const MainSearch: React.FC = () => {
const [filters, setFilters] = useState<Filters>({
professor: '',
course: '',
topic: '',
});
const [professors, setProfessors] = useState<Professor[]>([]);
const [courses, setCourses] = useState<Course[]>([]);
const [topics, setTopics] = useState<Topic[]>([]);
const navigate = useNavigate();
useEffect(() => {
// Fetch professors
fetchProfessors();
// Fetch courses
fetchCourses();
// Fetch topics
fetchTopics();
}, []);
const getAuthHeaders = () => {
const token = getSessionCookie();
// const token = localStorage.getItem('authToken');
console.log("Using token for API call:", token);
return {
'Authorization': `Token ${token}`,
'Content-Type': 'application/json'
};
};
const fetchProfessors = async () => {
try {
const response = await fetch('http://localhost:8000/api/professors', {
method: 'GET',
headers: getAuthHeaders(),
});
const data = await response.json();
console.log("Professors fetched:", data);
if (Array.isArray(data)) {
console.log("Professors fetched:", data);
setProfessors(data);
} else {
console.error('Data fetched is not an array:', data);
}
} catch (error) {
console.error('Error fetching professors:', error);
}
};
const fetchCourses = async () => {
try {
const response = await fetch('http://localhost:8000/api/courses', {
method: 'GET',
headers: getAuthHeaders(),
});
const data = await response.json();
if (Array.isArray(data)) {
setCourses(data);
} else {
console.error('Data fetched is not an array:', data);
}
} catch (error) {
console.error('Error fetching courses:', error);
}
};
const fetchTopics = async () => {
try {
const response = await fetch('http://localhost:8000/api/topics', {
method: 'GET',
headers: getAuthHeaders(),
});
const data = await response.json();
if (Array.isArray(data)) {
setTopics(data);
} else {
console.error('Data fetched is not an array:', data);
}
} catch (error) {
console.error('Error fetching topics:', error);
}
};
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();
const searchParams = new URLSearchParams(filters);
navigate(`/results?${searchParams}`);
};
return (
<>
<img src="/PeerNotes.png" alt="PeerNotes Logo" style={{ height: "100px" }} />
<form onSubmit={handleSubmit} className="filter-container">
<div className="filter-item">
<label htmlFor="professors">Professors:</label>
<select id="professors" name="professor" value={filters.professor} onChange={handleChange}>
<option value="">Select a Professor</option>
{professors.map((professor) => (
<option key={professor.id} value={professor.id}>{professor.name}</option>
))}
</select>
</div>
<div className="filter-item">
<label htmlFor="courses">Course:</label>
<select id="courses" name="course" value={filters.course} onChange={handleChange}>
<option value="">Select a Course</option>
{courses.map((course) => (
<option key={course.id} value={course.id}>{course.name}</option>
))}
</select>
</div>
<div className="filter-item">
<label htmlFor="topics">Topic:</label>
<select id="topics" name="topic" value={filters.topic} onChange={handleChange}>
<option value="">Select a Topic</option>
{topics.map((topic) => (
<option key={topic.id} value={topic.id}>{topic.name}</option>
))}
</select>
</div>
<button type="submit" className="submit-button">Submit</button>
</form>
</>
);
}
export default MainSearch;

View File

@@ -1,57 +0,0 @@
.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 */
}

View File

@@ -0,0 +1,69 @@
import React, { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import styles from '../styles/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('/search');
};
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;