import React, { useState, useEffect, useRef } from 'react'; import { Link, useParams } from 'react-router-dom'; import ReactToPrint from 'react-to-print'; import * as Datetime from 'react-datetime'; import 'react-datetime/css/react-datetime.css'; import moment from 'moment-timezone'; import './light.css'; import { Button, Checkbox, Form, Grid, Header, Icon, Label, Message, Table } from 'semantic-ui-react'; import { requester, randomString } from './utils.js'; import { MembersDropdown } from './Members.js'; class AttendanceSheet extends React.Component { render() { const clazz = this.props.clazz; const num = clazz.students.filter(x => x.attendance_status !== 'Withdrawn').length; return (
{clazz.course_data.name} Attendance

{moment.utc(clazz.datetime).tz('America/Edmonton').format('llll')} {num >= 2 ? ', '+num+' students sorted by registration time.' : '.'}

{clazz.students .filter(x => x.attendance_status !== 'Withdrawn') .slice(0, 15) .map(x => {x.student_name} ) }
{clazz.students .filter(x => x.attendance_status !== 'Withdrawn') .slice(15) .map(x => {x.student_name} ) }
); } } function AttendanceRow(props) { const { student, token, refreshClass } = props; const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const handleMark = (newStatus) => { if (loading) return; if (student.attendance_status === newStatus) return; setLoading(newStatus); const data = { ...student, attendance_status: newStatus }; requester('/training/'+student.id+'/', 'PATCH', token, data) .then(res => { refreshClass(); setError(false); }) .catch(err => { console.log(err); setError(true); }); }; const makeProps = (name) => ({ onClick: () => handleMark(name), toggle: true, active: student.attendance_status === name, loading: loading === name, }); useEffect(() => { setLoading(false); }, [student.attendance_status]); return (

{student.student_name} {student.attendance_status === 'Waiting for payment' && ' (Waiting for payment)'}:

{error &&

Error: something went wrong!

}
); } let attendanceOpenCache = false; export function InstructorClassAttendance(props) { const { clazz, token, refreshClass, user } = props; const [open, setOpen] = useState(attendanceOpenCache); const [input, setInput] = useState({}); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const printRef = useRef(); const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleSubmit = (e) => { if (loading) return; setLoading(true); const data = { ...input, attendance_status: 'Attended', session: clazz.id }; requester('/training/', 'POST', token, data) .then(res => { setLoading(false); setError(false); refreshClass(); }) .catch(err => { setLoading(false); console.log(err); setError(err.data); }); }; return (
Instructor Panel
{open || clazz.instructor === user.id ?
Student Emails
{clazz.students.length ? clazz.students .filter(x => x.attendance_status !== 'Withdrawn') .map(x => x.student_email) .join('; ') :

No students yet.

}
Mark Attendance
{!!clazz.students.length &&
} content={() => printRef.current} />
} {clazz.students.length ? clazz.students.map(x => ) :

No students yet.

}
Add Student
Submit
: }
); }; function InstructorClassEditor(props) { const { input, setInput, error, editing, token } = props; const [editInstructor, setEditInstructor] = useState(false); const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleChange = (e) => handleValues(e, e.currentTarget); const handleCheck = (e, v) => setInput({ ...input, [v.name]: v.checked }); const handleDatetime = (v) => setInput({ ...input, datetime: v.utc().format() }); const makeProps = (name) => ({ name: name, onChange: handleChange, value: input[name] || '', error: error[name], }); return (
{editing && (editInstructor ? <> {error.instructor_id && } Are you sure?

Only the new instructor will be able to edit this class.

: ) }

{error.datetime && } {editing && }

); } export function InstructorClassDetail(props) { const { clazz, setClass, token } = props; const [open, setOpen] = useState(false); const [input, setInput] = useState(clazz); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const { id } = useParams(); const handleSubmit = (e) => { if (loading) return; setLoading(true); setSuccess(false); requester('/sessions/'+id+'/', 'PUT', token, input) .then(res => { setSuccess(true); setLoading(false); setError(false); setOpen(false); setClass(res); }) .catch(err => { setLoading(false); console.log(err); setError(err.data); }); }; return (
Instructor Panel
{!open && success &&

Saved!

} {open ?
Edit Class
Submit : }
); }; export function InstructorClassList(props) { const { course, setCourse, token } = props; const [open, setOpen] = useState(false); const [input, setInput] = useState({ max_students: null }); const [error, setError] = useState(false); const [progress, setProgress] = useState([]); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(false); const [classes, setClasses] = useState([]); const [sameClasses, setSameClasses] = useState(false); const handleSubmit = (e) => { if (loading) return; setLoading(true); setSuccess(false); const request_id = randomString(); const getStatus = () => { requester('/stats/progress/?request_id='+request_id, 'GET') .then(res => { setProgress(res); }) .catch(err => { console.log(err); }); }; const interval = setInterval(getStatus, 500); const data = { ...input, course: course.id, request_id: request_id }; requester('/sessions/', 'POST', token, data) .then(res => { clearInterval(interval); setSuccess(res.id); setInput({ max_students: null }); setLoading(false); setError(false); setOpen(false); setCourse({ ...course, sessions: [ res, ...course.sessions ] }); }) .catch(err => { clearInterval(interval); setLoading(false); console.log(err); setError(err.data); }); }; useEffect(() => { requester('/sessions/', 'GET', token) .then(res => { setClasses(res.results.filter(x => !x.is_cancelled)); }) .catch(err => { console.log(err); }); }, []); useEffect(() => { setSameClasses(classes.filter(x => moment.utc(x.datetime).tz('America/Edmonton').isSame(input.datetime, 'day') ).sort((a, b) => a.datetime > b.datetime ? 1 : -1)); }, [input.datetime]); const fillSuggestion = (e) => { e.preventDefault(); setInput({ ...input, ...course.suggestion }); }; return (
Instructor Panel
{!open && success &&

Added! View the class.

} {open ?
Add a Class

Documentation: https://wiki.protospace.ca/Be_a_Course_Instructor

{course.suggestion &&

based off previous classes.

}

{progress.map(x => <>{x}
)}

Submit
{!!input.datetime &&
Upcoming Classes That Day
{sameClasses.length ? sameClasses.map(x =>

{moment.utc(x.datetime).tz('America/Edmonton').format('LT')} — {x.course_data.name}

) :

None

}
}
: }
); };