Skip to content

Commit

Permalink
feat: implement frontcover with basic assessment status handling
Browse files Browse the repository at this point in the history
  • Loading branch information
procaconsul committed Jun 5, 2024
1 parent aba7be9 commit 87766af
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'

import ExamRoot from './ExamRoot'
import Frontcover from './Frontcover'
import FrontCover from './FrontCover'
import QuestionPage from './QuestionPage'

const router = createBrowserRouter([
Expand All @@ -12,7 +12,7 @@ const router = createBrowserRouter([
children: [
{
path: 'frontcover',
element: <Frontcover />,
element: <FrontCover />,
},
{
path: 'questions/:questionId',
Expand Down
70 changes: 70 additions & 0 deletions src/FrontCover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ClockIcon } from '@radix-ui/react-icons'
import { Callout, Strong, Text } from '@radix-ui/themes'
import { addMinutes, format, isAfter, isBefore } from 'date-fns'
import React, { FC } from 'react'

import FormattedCard from './components/FormattedCard'
import Markdown from './components/Markdown'
import Body from './components/pageStructure/Body'
import Header from './components/pageStructure/Header'
import { useAssessmentSummary } from './hooks/assessmentSummary'

const FrontCover: FC = () => {
const { summary, summaryIsLoaded } = useAssessmentSummary()

if (!summaryIsLoaded) return <div>Loading...</div>
if (summary === undefined) return <div>Error</div>

function bannerColour(start: Date, end: Date) {
if (isBefore(new Date(), start)) return 'blue'
if (isAfter(new Date(), end)) return 'red'
return 'amber'
}

function bannerText(start: Date, end: Date) {
const FMT = "'on' cccc d MMMM Y 'at' hh:mma"
if (isBefore(new Date(), start))
return (
<Text>
This assessment<Strong>begins {format(start, FMT)} (UK time)</Strong>, when the questions
will be released
</Text>
)
if (isAfter(new Date(), end))
return (
<Text>
This assessment <Strong>ended {format(end, FMT)} (UK time).</Strong> Submissions are no
longer accepted.
</Text>
)
return (
<Text>
This assessment <Strong>ends {format(end, FMT)} (UK time)</Strong>, after which submissions
will not be accepted.
</Text>
)
}

return (
<>
<Header primaryText={summary.courseCode} secondaryText={summary.courseName} />
<Body>
<FormattedCard title="Instructions">
<Markdown>{summary.rubric.instructions}</Markdown>
<Callout.Root
color={bannerColour(summary.begins, addMinutes(summary.begins, summary.duration))}
>
<Callout.Icon>
<ClockIcon />
</Callout.Icon>
<Callout.Text>
{bannerText(summary.begins, addMinutes(summary.begins, summary.duration))}
</Callout.Text>
</Callout.Root>
</FormattedCard>
</Body>
</>
)
}

export default FrontCover
18 changes: 0 additions & 18 deletions src/Frontcover.tsx

This file was deleted.

18 changes: 18 additions & 0 deletions src/hooks/assessmentSummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { plainToInstance } from 'class-transformer'
import { useEffect, useState } from 'react'

import axiosInstance from '../api/axiosInstance'
import routes from '../api/routes'
import { Summary } from '../types/exam'

export const useAssessmentSummary = () => {
const [summary, setSummary] = useState<Summary>()
const [summaryIsLoaded, setSummaryIsLoaded] = useState(false)
useEffect(() => {
axiosInstance
.get(routes.summary)
.then(({ data }) => setSummary(plainToInstance(Summary, data)))
.finally(() => setSummaryIsLoaded(true))
}, [])
return { summary, summaryIsLoaded }
}
17 changes: 17 additions & 0 deletions src/types/exam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,20 @@ export class Question {
showPartWeights: boolean
parts: Record<number, Part>
}

export class Rubric {
instructions: string
questionsToAnswer: number
}

export class Summary {
courseCode: string
courseName: string
duration: number

@Type(() => Date)
begins: Date

@Type(() => Rubric)
rubric: Rubric
}

0 comments on commit 87766af

Please sign in to comment.