Skip to content

Commit

Permalink
Add quiz in progress to stats view (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
Derstilon committed May 25, 2021
1 parent d6ce46c commit b64f53a
Show file tree
Hide file tree
Showing 10 changed files with 2,223 additions and 2,133 deletions.
34 changes: 25 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-spring": "^9.1.2",
"react-use-websocket": "^2.5.0",
"typescript": "^4.2.3",
"use-interval": "^1.3.0",
"web-vitals": "^0.2.4",
"workbox-background-sync": "^5.1.4",
"workbox-broadcast-update": "^5.1.4",
Expand Down
4 changes: 3 additions & 1 deletion src/@types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ interface StudentQuestion{
interface ScheduledQuiz {
quiz?: FrontQuiz;
students: string[];
timeInSec?: number;
timeInSec: number;
questionStats: QuestionStat[];
alreadyShowedResults: boolean;
inProgress?: boolean;
timeToEnd?: number;
}

interface AnswerStat {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function CreateSessionView() {

store.sessionId = lecture.id;
store.sendQuizStep = 0;
store.timeToNextQuiz = 0;
store.sendQuiz.timeToEnd = 0;
backEnd.getLectureLink(lecture.id)
.then((link) => {
store.link = link;
Expand Down
97 changes: 52 additions & 45 deletions src/lecturer/components/quizStatsView/QuizStatsView.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
import {
Paper,
List,
ListItem,
ListItemIcon,
ListItemText,
ListItemSecondaryAction,
IconButton,
Fab
} from "@material-ui/core";
import AssignmentIcon from "@material-ui/icons/Assignment";
import BackspaceIcon from '@material-ui/icons/Backspace';
import { makeStyles, useTheme } from "@material-ui/core";
import SendIcon from '@material-ui/icons/Send';
import React, { useContext, useEffect } from "react";
import { useContext, useEffect, useState } from "react";
import { StoreContext } from "../../services/StoreService";
import { green } from "@material-ui/core/colors";
import DoneIcon from '@material-ui/icons/Done';
import { QuestionBlock } from "./QuestionBlock";
import { StatsListItem } from "./StatsListItem";
import { ImportExport } from "../importExport/ImportExport";

export function QuizStatsView() {
const store = useContext(StoreContext);
const [selectedQuizStats, setQuizStats] = React.useState<ScheduledQuiz | undefined>(
store.endedQuizzes.length > 0 ? store.endedQuizzes[0] : undefined
const [selectedQuizStats, setQuizStats] = useState<ScheduledQuiz | undefined>(
store.scheduledQuizzes.length > 0 ? store.scheduledQuizzes[0] : undefined
);

const theme = useTheme();

useEffect(() => {
setQuizStats((prev) => prev && store.endedQuizzes.indexOf(prev) !== -1 ? prev : undefined);
}, [store.endedQuizzes]);
setQuizStats((prev) => prev && store.scheduledQuizzes.indexOf(prev) !== -1 ? prev : undefined);
}, [store.scheduledQuizzes]);

const theme = useTheme();
const classes = makeStyles({
root: {
background: theme.palette.primary.light,
Expand Down Expand Up @@ -79,10 +72,6 @@ export function QuizStatsView() {
content: '""',
},
},
quizStatRow: {
paddingTop: 16,
paddingBottom: 16,
},
answer: {
width: "100%",
height: "100%",
Expand Down Expand Up @@ -122,26 +111,49 @@ export function QuizStatsView() {
})();

const handleQuiz = (quizIndex: number) => {
setQuizStats(store.endedQuizzes[quizIndex]);
setQuizStats(store.scheduledQuizzes[quizIndex]);
};

// const refreshClock = useCallback((timeToWait) => {
// if (timeToWait - Date.now() < 0) {
// if (timerWait)
// clearTimeout(timerWait);
// setClock(0);
// } else
// setClock(timeToWait - Date.now());
// }, [timerWait])

// useEffect(() => {
// if (store.sendQuiz.timeToEnd - Date.now() > 0 && !timerWait) {
// setClock(store.sendQuiz.timeToEnd - Date.now());
// setTimerWait(setInterval(() => { refreshClock(store.sendQuiz.timeToEnd) }, 1000));
// }
// }, [store.sendQuiz.timeToEnd, refreshClock, timerWait, store])


const handleDeleteStats = (quizIndex: number) => {
let statsToBeDeleted = store.endedQuizzes[quizIndex];
store.endedQuizzes = store.endedQuizzes.filter(storeQuiz => storeQuiz !== statsToBeDeleted);
let statsToBeDeleted = store.scheduledQuizzes[quizIndex];
store.scheduledQuizzes = store.scheduledQuizzes.filter(storeQuiz => storeQuiz !== statsToBeDeleted);
}

const handleEnded = (quizIndex: number) => {
let scheduledQuizzes = store.scheduledQuizzes;
scheduledQuizzes[quizIndex].inProgress = false;
store.scheduledQuizzes = scheduledQuizzes;
}

const handleShowResults = () => {
let tmpQuizzes = store.endedQuizzes;
let tmpQuizzes = store.scheduledQuizzes;
tmpQuizzes.forEach(
(element: ScheduledQuiz) => (element === selectedQuizStats) ? (element.alreadyShowedResults = true) : (null)
)
store.endedQuizzes = tmpQuizzes;
store.scheduledQuizzes = tmpQuizzes;
}

const onImport = (e: ProgressEvent<FileReader>) => {
if (e.target?.result != null) {
let jsonString = e.target.result as string;
store.endedQuizzes = [...store.endedQuizzes, ...JSON.parse(jsonString)];
store.scheduledQuizzes = [...store.scheduledQuizzes, ...JSON.parse(jsonString)];
}
}

Expand All @@ -150,26 +162,21 @@ export function QuizStatsView() {
<div className={classes.root}>
<Paper variant="outlined" square className={classes.quizColumn}>
<List component="nav">
{store.endedQuizzes.map((quizStats, i) => (
<ListItem
button
selected={quizStats === selectedQuizStats}
onClick={(event) => handleQuiz(i)}
className={classes.quizStatRow}
>
<ListItemIcon>
{quizStats === selectedQuizStats && (
<AssignmentIcon />
)}
</ListItemIcon>
<ListItemText primary={quizStats.quiz?.title} />
<ListItemSecondaryAction>
<IconButton edge="end" onClick={(event) => handleDeleteStats(i)}>
<BackspaceIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
))}
{store.scheduledQuizzes.map((quizStats, i) => {
return (
<StatsListItem
index={i}
isSelected={quizStats === selectedQuizStats}
onSelect={() => handleQuiz(i)}
onDelete={() => handleDeleteStats(i)}
onEnded={() => handleEnded(i)}
timeToEnd={quizStats.timeToEnd ?? 0}
inProgress={!!quizStats.inProgress} // !! changes (boolean | undefined) to boolean
title={quizStats.quiz?.title ?? ""}
/>
)
}
)}
</List>
</Paper>
<Paper
Expand All @@ -190,7 +197,7 @@ export function QuizStatsView() {
</Paper>
<div className={classes.action}>

<ImportExport onImport={onImport} objectToExport={store.endedQuizzes} fileName="endedQuizzes" />
<ImportExport onImport={onImport} objectToExport={store.scheduledQuizzes} fileName="scheduledQuizzes" />

<Fab
variant="extended"
Expand Down
62 changes: 62 additions & 0 deletions src/lecturer/components/quizStatsView/StatsListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IconButton, ListItem, ListItemIcon, ListItemSecondaryAction, ListItemText, makeStyles, useTheme } from "@material-ui/core";
import React, { useCallback, useContext, useEffect } from "react";
import { useState } from "react";
import { StoreContext } from "../../services/StoreService";
import { formatTime } from "../../util/time";
import AssignmentIcon from "@material-ui/icons/Assignment";
import BackspaceIcon from '@material-ui/icons/Backspace';
import useInterval from 'use-interval'

interface StatsListProps {
isSelected: boolean;
onSelect: () => void;
onDelete: () => void;
onEnded: () => void;
inProgress: boolean;
timeToEnd: number;
title: string;
index: number;
}

export function StatsListItem(props: StatsListProps) {
const [clock, setClock] = useState(props.timeToEnd - Date.now());

const theme = useTheme();
const classes = makeStyles({
quizStatRow: {
paddingTop: 16,
paddingBottom: 16,
},
})();

useInterval(() => {
if (props.timeToEnd - Date.now() > 0)
setClock(props.timeToEnd - Date.now());
else {
setClock(0);
props.onEnded();
}
}, props.inProgress ? 1000 : null);

return (<ListItem
button
selected={props.isSelected}
onClick={(event) => props.onSelect()}
className={classes.quizStatRow}
divider
disabled={props.inProgress}
>
<ListItemIcon>
{props.isSelected && (
<AssignmentIcon />
)}
</ListItemIcon>
<ListItemText primary={props.title} secondary={props.inProgress ? formatTime(clock) : ""} />
{!props.inProgress && (<ListItemSecondaryAction>
<IconButton edge="end" onClick={(event) => props.onDelete()}>
<BackspaceIcon />
</IconButton>
</ListItemSecondaryAction>)}
</ListItem>);

}
22 changes: 16 additions & 6 deletions src/lecturer/components/sendQuizView/SendQuizView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export function SendQuizView(props: SendQuizViewProps) {
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setChecked(event.target.checked);
let tmpQuiz: ScheduledQuiz = store.sendQuiz;
delete tmpQuiz.timeInSec;
tmpQuiz.timeInSec = 0;
store.sendQuiz = tmpQuiz;
setTime(0);
};
Expand All @@ -270,6 +270,14 @@ export function SendQuizView(props: SendQuizViewProps) {
if (timerWait)
clearTimeout(timerWait);
setClock(0);
store.sendQuiz = {
students: [],
questionStats: [],
alreadyShowedResults: false,
timeInSec: 0,
inProgress: true,
timeToEnd: 0,
}
} else
setClock(timeToWait - Date.now());
}, [timerWait])
Expand All @@ -278,8 +286,9 @@ export function SendQuizView(props: SendQuizViewProps) {
if (store.sendQuizStep === steps.length - 1) {
console.log("scheduled quiz", store.sendQuiz);
let timeToWait = Date.now() + 60000 * (time ?? 0);
store.timeToNextQuiz = timeToWait;
store.sendQuiz.timeToEnd = timeToWait;
setClock(timeToWait - Date.now());
store.scheduledQuizzes.push(store.sendQuiz);
setTimerWait(setInterval(() => { refreshClock(timeToWait) }, 1000));
}
store.sendQuizStep = store.sendQuizStep + 1;
Expand All @@ -293,12 +302,13 @@ export function SendQuizView(props: SendQuizViewProps) {
}, [timerWait])

useEffect(() => {
if (store.timeToNextQuiz - Date.now() > 0 && !timerWait) {
setClock(store.timeToNextQuiz - Date.now());
setTimerWait(setInterval(() => { refreshClock(store.timeToNextQuiz) }, 1000));
let timeToEnd = store.sendQuiz.timeToEnd ?? 0;
if (timeToEnd > 0 && timeToEnd - Date.now() > 0 && !timerWait) {
setClock(store.sendQuiz.timeToEnd ?? 0 - Date.now());
setTimerWait(setInterval(() => { refreshClock(store.sendQuiz.timeToEnd) }, 1000));
store.sendQuizStep = 4;
}
}, [store.timeToNextQuiz, refreshClock, timerWait, store])
}, [store.sendQuiz.timeToEnd, refreshClock, timerWait, store])


const handleBack = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export function ShareSessionView(props: ShareSessionViewProps) {
const handleClickEnd = () => {
store.link = "";
store.sessionId = "";
store.timeToNextQuiz = 0;
store.sendQuiz.timeToEnd = 0;
store.sendQuizStep = 0;

let event: Payload = {
Expand Down
Loading

0 comments on commit b64f53a

Please sign in to comment.