Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connecting Students and Classes #59

Merged
merged 5 commits into from
Nov 25, 2024
Merged
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
38 changes: 38 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ const Level = mongoose.model("Level", LevelSchema)

//------------------ ENDPOINTS ------------------//

/* USER RELATED ENDPOINTS */

// Sign up
app.post('/api/users', async (req, res) => {
try {
Expand Down Expand Up @@ -208,6 +210,9 @@ app.get('/api/users', async (req, res) => {
}
})


/* CONTACT RELATED ENDPOINTS */

// Post Contact
app.post('/api/contact', async (req, res) => {
const { name, email, subject, message } = req.body
Expand All @@ -227,6 +232,9 @@ app.post('/api/contact', async (req, res) => {
}
})


/* CLASS RELATED ENDPOINTS */

// Get Classes
app.get('/api/classes', async (req, res) => {
try {
Expand Down Expand Up @@ -263,6 +271,36 @@ app.get("/api/conversations", async (req, res) => {
}
})

// Get Student's classes
app.get('/api/students-classes', async (req, res) => {
try {
const allowedFields = ['_id'];
const filters = validateInput(req.query, allowedFields);

//apply the filters directly to the database query
const data = await User.findOne(filters, { enrolledClasses: 1, _id: 0 });
res.json(data);

} catch (err) {
res.status(500).send(err);
}
})

// Get class by ID
app.get('/api/class', async (req, res) => {
try {
const allowedFields = ['_id'];
const filters = validateInput(req.query, allowedFields);

//apply the filters directly to the database query
const data = await Class.findOne(filters);
res.json(data)

} catch (err) {
res.status(500).send(err);
}
})

// Enroll in a class
app.put('/api/users/:id/enroll', async (req, res) => {
const { classId } = req.body
Expand Down
32 changes: 26 additions & 6 deletions src/api/class-wrapper.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import axios from 'axios'

const apiUrl = (endpoint) => `${endpoint}`

// query should be a string
const getClasses = async (query = "") => {
try {
const response = await axios.get(apiUrl(`/api/classes?${query}`))
const response = await axios.get(`/api/classes?${query}`)
return response.data
} catch (error) {
console.error('Error fetching courses:', error)
Expand All @@ -15,7 +13,7 @@ const getClasses = async (query = "") => {
// query should be a string
const getLevels = async (query = "") => {
try {
const response = await axios.get(apiUrl(`/api/levels?${query}`));
const response = await axios.get(`/api/levels?${query}`);
return response.data
} catch (error) {
console.error('Error fetching levels:', error);
Expand All @@ -24,7 +22,7 @@ const getLevels = async (query = "") => {

const getConversations = async () => {
try {
const response = await axios.get(apiUrl("/api/conversations/"))
const response = await axios.get("/api/conversations/")
return response.data
} catch (error) {
console.error('Error fetching conversations:', error)
Expand Down Expand Up @@ -61,10 +59,32 @@ const unenrollInClass = async (classId, userId) => {
}
}

const getStudentClasses = async (studentId) => {
const queryString = new URLSearchParams(`_id=${studentId}`);
try {
const response = await axios.get(`/api/students-classes?${queryString.toString()}`);
return response.data;
} catch (error) {
console.error("Error fetching student's classes:", error);
}
}

const getClassById = async (classId) => {
const queryString = new URLSearchParams(`_id=${classId}`);
try {
const response = await axios.get(`/api/class?${queryString.toString()}`);
return response.data;
} catch (error) {
console.error("Error fetching class from id:", error);
}
}

export {
getClasses,
getLevels,
getConversations,
enrollInClass,
unenrollInClass
unenrollInClass,
getStudentClasses,
getClassById,
}
2 changes: 1 addition & 1 deletion src/components/NavBar/NavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const NavBar = () => {
<img className="h-14 w-auto" src={dillarLogo} alt="Dillar English Academy" />
</Link>
{/* Desktop navigation */}
<div className="hidden sm:flex sm:items-center sm:space-x-4">
<div className="hidden sm:flex sm:items-center lg:space-x-20 md:space-x-10">
<NavLink href="/levels">Classes</NavLink>
<NavLink href="/contact">Contact</NavLink>
<NavLink href="/about">About</NavLink>
Expand Down
30 changes: 15 additions & 15 deletions src/pages/AdminView.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { useEffect, useState } from "react";

const AdminView = () => {
const [user, setUser] = useState(null);
const [user, setUser] = useState(null);

useEffect(() => {
const params = new URLSearchParams(location.search);
const user = {
firstName: params.get('firstName'),
lastName: params.get('lastName'),
username: params.get('username')
};
setUser(user);
}, []);
useEffect(() => {
const params = new URLSearchParams(location.search);
const user = {
firstName: params.get('firstName'),
lastName: params.get('lastName'),
username: params.get('username')
};
setUser(user);
}, []);

return (
<div>
<h1>Admin: {user ? `${user.firstName} ${user.lastName}` : 'Loading...'}</h1>
</div>
);
return (
<div className="h-full">
<h1>Admin: {user ? `${user.firstName} ${user.lastName}` : 'Loading...'}</h1>
</div>
);
};

export default AdminView;
2 changes: 1 addition & 1 deletion src/pages/ClassesPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ClassesPage = () => {
if (loading || !level) return <></>;

return (
<div className="min-h-screen bg-white">
<div className="h-full bg-white">
{/* Banner Section */}
<div className="bg-gradient-to-r from-[#FFFFFF] from-5% via-[#D3EDFC] via-35% via-[#B2A0FA] via-75% via-[#8AC7F4] to-[#3F96EA] py-12">
<div className="max-w-7xl mx-auto px-8">
Expand Down
48 changes: 21 additions & 27 deletions src/pages/PageNotFound.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,26 @@ import { useLocation } from 'wouter';
import Button from '../components/Button/Button';

const PageNotFound = () => {
const [, setLocation] = useLocation();

return (
<div className="flex items-center justify-center h-5/6">
<div>
<h1 className="flex items-center justify-center h-5/6 text-6xl mb-2 font-bold pt-5 py-5" >Page Not Found</h1>
<h2 className="flex items-center justify-center text-3xl mb-2 font-normal"> The page you're looking for doesn't exist.</h2>
<div className='flex items-center justify-center space-x-5 whitespace-nowrap pt-8'>
<Button
label={"Return Home"}
onClick={() => setLocation("/")}
isOutline={false}
/>
<Button
label={"Get Help"}
onClick={() => setLocation("/")}
isOutline={true}
/>
</div>


</div>


</div>
)
const [, setLocation] = useLocation();

return (
<div className="flex flex-col items-center justify-center h-full">
<h1 className="text-6xl mb-2 font-bold pt-5 py-5" >Page Not Found</h1>
<h2 className="text-3xl mb-2 font-normal"> The page you're looking for doesn't exist.</h2>
<div className='flex space-x-5 whitespace-nowrap pt-8'>
<Button
label={"Return Home"}
onClick={() => setLocation("/")}
isOutline={false}
/>
<Button
label={"Get Help"}
onClick={() => setLocation("/")}
isOutline={true}
/>
</div>
</div>
)
}

export default PageNotFound
export default PageNotFound;
58 changes: 41 additions & 17 deletions src/pages/StudentPortal.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,47 @@
import { useEffect, useState } from "react";
import { useEffect, useState } from 'react';
import Class from '@/components/Class';
import { getClassById, getStudentClasses } from '@/api/class-wrapper';

const StudentPortal = () => {
const [user, setUser] = useState(null);
const [classes, setClasses] = useState([]);
const [user, setUser] = useState(null);

useEffect(() => {
const params = new URLSearchParams(location.search);
const user = {
firstName: params.get('firstName'),
lastName: params.get('lastName'),
username: params.get('username')
};
setUser(user);
}, []);
useEffect(() => {
const params = new URLSearchParams(location.search);
const user = {
firstName: params.get('firstName'),
lastName: params.get('lastName'),
username: params.get('username')
};
setUser(user);

return (
<div>
<h1>Student: {user ? `${user.firstName} ${user.lastName}` : 'Loading...'}</h1>
</div>
);
};
// get classes for student
const fetchData = async () => {
// fetch a specific user
const response = await getStudentClasses("671edb6d31e448b23d0dc384");
const classes = await Promise.all(
response.enrolledClasses.map(async (classID) => {
const classResponse = await getClassById(classID);
return classResponse; // Return the class details
})
);
setClasses(classes);
};

fetchData();
}, []);

return (
<div className='h-full'>
<h1>Student: {user ? `${user.firstName} ${user.lastName}` : 'Loading...'}</h1>
<div className='grid grid-cols-3'>
{classes.map((classObj, classIndex) => (
<Class key={classIndex} classObj={classObj} />
))}
</div>
</div>
);

}

export default StudentPortal;