Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
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