import React, { useState, useEffect, useRef } from 'react'; import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } 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, Container, Checkbox, Divider, Dropdown, Form, Grid, Header, Icon, Image, Label, Menu, Message, Segment, Table } from 'semantic-ui-react'; import { BasicTable, staticUrl, requester } from './utils.js'; import { MembersDropdown } from './Members.js'; class AttendanceSheet extends React.Component { render() { const clazz = this.props.clazz; const num = clazz.students.length; return (
{clazz.course_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 } = props; const handleValues = (e, v) => setInput({ ...input, [v.name]: v.value }); const handleUpload = (e, v) => setInput({ ...input, [v.name]: e.target.files[0] }); 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 (
{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 [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 data = { ...input, course: course.id }; requester('/sessions/', 'POST', token, data) .then(res => { setSuccess(res.id); setInput({}); setLoading(false); setError(false); setOpen(false); setCourse({ ...course, sessions: [ res, ...course.sessions ] }); }) .catch(err => { 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]); return (
Instructor Panel
{!open && success &&

Added! View the class.

} {open ?
Add a Class
Submit
{!!input.datetime &&
Upcoming Classes That Day
{sameClasses.length ? sameClasses.map(x =>

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

) :

None

}
}
: }
); };