Skip to content

Commit

Permalink
Teacher student prem (#134)
Browse files Browse the repository at this point in the history
* reject teacher from joinig own course + add is teacher checkbox

* serve two different interfaces based on premissions

* modify tests to pass with isTeacher

* Update users.js

Fix indentation inconsistency

* remove comment in seeder

---------

Co-authored-by: Nils Streedain <tannins_berets_0@icloud.com>
  • Loading branch information
karinocheretny and nilsstreedain authored Mar 8, 2024
1 parent fe24e77 commit d05c9e4
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 88 deletions.
24 changes: 12 additions & 12 deletions client/src/components/JoinCourse.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ import apiUtil from '../utils/apiUtil'
//no message for joinCodes which don't have a match
/******************************************************/

function JoinCourse(props){
function JoinCourse(props) {
const dispatch = useDispatch()
const navigate = useNavigate()
const [error, setError] = useState(false)
const [message, setMessage] = useState("")
const [joinCode, setJoinCode] = useState("")

async function handleJoinSubmit(e){
async function handleJoinSubmit(e) {
event.preventDefault()
//setJoinCode(e.target.value)
//post to the courses/join endpoint
const joinCodePayload = {
joinCode: joinCode
}
const response = await apiUtil("post", "courses/join", { dispatch: dispatch, navigate: navigate}, joinCodePayload);
const response = await apiUtil("post", "courses/join", { dispatch: dispatch, navigate: navigate }, joinCodePayload);
setError(response.error)
setMessage(response.message)
if (response.status === 201) {
Expand All @@ -36,15 +36,15 @@ function JoinCourse(props){

return (
<div id="join-course">
<Form onSubmit={(e) => { handleJoinSubmit(e)} }>
<Form.Group controlId="formJoinCourse">
<Form.Control type="text" placeholder="Enter Join Code" value={joinCode} onChange={(e) => setJoinCode(e.target.value)}/>
</Form.Group>
<Button className="btn-add" variant="primary" type="submit">
Join Course
</Button>
</Form>
{ message !== "" && <Notice status={error ? "error" : ""} message={message}/>}
<Form onSubmit={(e) => { handleJoinSubmit(e) }}>
<Form.Group controlId="formJoinCourse">
<Form.Control type="text" placeholder="Enter Join Code" value={joinCode} onChange={(e) => setJoinCode(e.target.value)} />
</Form.Group>
<Button className="btn-add" variant="primary" type="submit">
Join Course
</Button>
</Form>
{message !== "" && <Notice status={error ? "error" : ""} message={message} />}
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions client/src/hooks/useCourses.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function useCourses() {
populateCourses()
}
}, [])


return [courses, message, error, loading]
}
Expand Down
61 changes: 13 additions & 48 deletions client/src/pages/Landing.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,21 @@
import React from 'react';
import CourseCard from '../components/CourseCard'
import { Button, Card } from "react-bootstrap"
import useCourses from '../hooks/useCourses'
import Notice from '../components/Notice'
import JoinCourse from '../components/JoinCourse'
import { Link } from 'react-router-dom';
import { TailSpin } from 'react-loader-spinner'
import TeacherLanding from './TeacherLanding';
import StudentLanding from './StudentLanding';
import apiUtil from '../utils/apiUtil'
import { useSelector, useDispatch } from 'react-redux'
import { getUserState } from '../redux/selectors'

function Landing(props) {
// Will implement ability to hide/show once we figure out best way to modify the

const [ courses, message, error, loading ] = useCourses()

// cards for student and teacher courses
return(
//const { user } = useAuth(); // Assuming you have access to the user's role through an authentication context
//const user = await apiUtil('post', 'users/#', { dispatch: dispatch, navigate: navigate }, user)
const user = useSelector(getUserState)
console.log(user )
console.log(user.user.isTeacher)
return (
<div className="landing-page">
{/*No Courses*/}
{ message ? <Notice error={error ? "error" : ""} message={message}/> : (!courses.studentCourses && !courses.instructorCourses) ? <Notice message={"You do not have any courses yet"}/> : <></>}
{/*Join Course button for all users*/}
<JoinCourse className="buttons"/>

{/*Student Courses*/}
{ loading ? <TailSpin visible={true}/> : <div className="all-courses">
{courses.studentCourses != null && <div id="student-courses">
<p id="landing-subtitle" >Student Courses</p>
<hr></hr>

<div className='courses'>
{courses.studentCourses.map((studentCourse) => {
return <CourseCard key={studentCourse.id} course={studentCourse} role={"student"} />
})}
</div>
</div>}

{/*Teacher Courses*/}
{courses.teacherCourses && <div id="teacher-courses">
<Link id="create-course-btn" to={`/createcourse`}>
<Button variant="primary" className='btn-add'>Create Course</Button>
</Link>

<p id="landing-subtitle">Instructor Courses</p>
<hr></hr>

<div className='courses'>
{courses.teacherCourses.map((teacherCourse) => {
return <CourseCard key={teacherCourse.id} course={teacherCourse} role={"teacher"} />
})}
</div>
</div>}
</div>}
{user && user.user.isTeacher ? <TeacherLanding /> : <StudentLanding />}
</div>
)
);
}

export default Landing;
4 changes: 0 additions & 4 deletions client/src/pages/#.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,10 @@ function #(props){
<p className='mainText'> # </p>

<#Form />

</div>
</div>
</div>
)
}




export default #
38 changes: 38 additions & 0 deletions client/src/pages/StudentLanding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import CourseCard from '../components/CourseCard'
import useCourses from '../hooks/useCourses'
import Notice from '../components/Notice'
import JoinCourse from '../components/JoinCourse'
import { TailSpin } from 'react-loader-spinner'

function StudentLanding(props) {

const [courses, message, error, loading] = useCourses()

// cards for student and teacher courses
return (
<div className="Student-landing-page">
{/*No Courses*/}
{message ? <Notice error={error ? "error" : ""} message={message} /> : (!courses.studentCourses && !courses.instructorCourses) ? <Notice message={"You do not have any courses yet"} /> : <></>}
{/*Join Course button for all users*/}
<JoinCourse className="buttons" />

{/*Student Courses*/}
{loading ? <TailSpin visible={true} /> : <div className="all-courses">
{courses.studentCourses != null && <div id="student-courses">
<p id="landing-subtitle" >Student Courses</p>
<hr></hr>

<div className='courses'>
{courses.studentCourses.map((studentCourse) => {
return <CourseCard key={studentCourse.id} course={studentCourse} role={"student"} />
})}
</div>
</div>}
</div>}

</div>
)
}

export default StudentLanding;
36 changes: 36 additions & 0 deletions client/src/pages/TeacherLanding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import CourseCard from '../components/CourseCard'
import { Button, Card } from "react-bootstrap"
import useCourses from '../hooks/useCourses'
import Notice from '../components/Notice'
import { Link } from 'react-router-dom';

function TeacherLanding(props) {

const [courses, message, error, loading] = useCourses()

return (
<div className="Teacher-landing-page">
{/*No Courses*/}
{message ? <Notice error={error ? "error" : ""} message={message} /> : (!courses.studentCourses && !courses.instructorCourses) ? <Notice message={"You do not have any courses yet"} /> : <></>}

{/*Teacher Courses*/}
{courses.teacherCourses && <div id="teacher-courses">
<Link id="create-course-btn" to={`/createcourse`}>
<Button variant="primary" className='btn-add'>Create Course</Button>
</Link>

<p id="landing-subtitle">Instructor Courses</p>
<hr></hr>

<div className='courses'>
{courses.teacherCourses.map((teacherCourse) => {
return <CourseCard key={teacherCourse.id} course={teacherCourse} role={"teacher"} />
})}
</div>
</div>}
</div>
)
}

export default TeacherLanding;
2 changes: 2 additions & 0 deletions server/__tests__/app/api/courses.jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('/courses endpoints', () => {
firstName: 'Dan',
lastName: 'Smith',
email: 'dannySmith@myclassroom.com',
isTeacher: true,
rawPassword: 'Danny-o123!'
})
userToken = jwtUtils.encode({
Expand All @@ -39,6 +40,7 @@ describe('/courses endpoints', () => {
firstName: 'Mitchell',
lastName: 'DaGoat',
email: 'mitchdagoat@myclassroom.com',
isTeacher: false,
rawPassword: 'mitchell123!!'
})
user2Token = jwtUtils.encode({
Expand Down
3 changes: 3 additions & 0 deletions server/__tests__/app/api/lectures.jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('Test api/lecture.js request handlers', () => {
lastName: 'Smith',
email: 'danSmith2@myclassroom.com',
rawPassword: 'Danny-o123!',
isTeacher: true,
confirmedPassword: 'Danny-o123!'
})
teacher = await getUserFromEmail(teacher_resp.body.user.email) // used to get ID
Expand All @@ -63,6 +64,7 @@ describe('Test api/lecture.js request handlers', () => {
lastName: 'Doe',
email: 'johndoe@myclassroom.com',
rawPassword: 'superdupersecret',
isTeacher: true,
confirmedPassword: 'superdupersecret'
})
student = await getUserFromEmail(student_resp.body.user.email) // used to get ID
Expand All @@ -77,6 +79,7 @@ describe('Test api/lecture.js request handlers', () => {
lastName: 'Engineer',
email: 'swe@myclassroom.com',
rawPassword: 'secretpassword45',
isTeacher: true,
confirmedPassword: 'secretpassword45'
})
unrelated = await getUserFromEmail(unrelated_resp.body.user.email)
Expand Down
Loading

0 comments on commit d05c9e4

Please # to comment.