Commit fdd488ce authored by Marek Veselý's avatar Marek Veselý
Browse files

Make instructor milestones persistent, refactor exercise panel forms

parent 3a0fe6f5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ const ExerciseCard: FC<ExerciseCardProps> = ({
            title={
              exercise.running ? 'Cannot delete a running exercise' : undefined
            }
            active={alertOpen}
          >
            Delete
          </Button>
@@ -111,6 +112,7 @@ const ExerciseCard: FC<ExerciseCardProps> = ({
        </>
      ),
    [
      alertOpen,
      details,
      exercise.exerciseStart,
      exercise.finished,
+16 −8
Original line number Diff line number Diff line
import { useModals } from '@/router'
import {
  Button,
  Classes,
@@ -19,14 +18,24 @@ import {
import { dialog } from '@inject/shared/css/dialog'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import csrfFetch from '@inject/shared/utils/csrfFetch'
import type { ChangeEvent } from 'react'
import type { ChangeEvent, Dispatch, FC, SetStateAction } from 'react'
import { useCallback, useMemo, useState } from 'react'

const DefinitionUploader = () => {
  const [open, setOpen] = useState<boolean>(true)
  const { close } = useModals()
interface DefinitionUploaderProps {
  open: boolean
  setOpen: Dispatch<SetStateAction<boolean>>
}

const DefinitionUploader: FC<DefinitionUploaderProps> = ({ open, setOpen }) => {
  const [name, setName] = useState<string>('')
  const [file, setFile] = useState<File | undefined>()

  const reset = useCallback(() => {
    setOpen(false)
    setName('')
    setFile(undefined)
  }, [setOpen])

  const { notify } = useNotifyContext()
  const host = useHost()
  const client = useApolloClient()
@@ -63,7 +72,7 @@ const DefinitionUploader = () => {
          notify(res.detail, { intent: 'danger' })
          return
        }
        setOpen(false)
        reset()
        client.refetchQueries({ include: [GetDefinitionsDocument] })
      })
      .finally(() => setLoadingSubmit(false))
@@ -103,8 +112,7 @@ const DefinitionUploader = () => {
    <Dialog
      className={dialog}
      isOpen={open}
      onClose={() => setOpen(false)}
      onClosed={() => close()}
      onClose={reset}
      icon='upload'
      title='Upload a definition'
    >
+6 −1
Original line number Diff line number Diff line
@@ -54,7 +54,12 @@ const DefinitionComp: FC<DefinitionProps> = ({ definition }) => {
          alignText='left'
          style={{ marginTop: '1rem', alignSelf: 'end' }}
        >
          <Button type='button' onClick={() => setAlertOpen(true)} icon='trash'>
          <Button
            type='button'
            active={alertOpen}
            onClick={() => setAlertOpen(true)}
            icon='trash'
          >
            Delete
          </Button>
          <LinkButton
+41 −37
Original line number Diff line number Diff line
import { useModals } from '@/router'
import {
  Button,
  ButtonGroup,
@@ -10,7 +9,8 @@ import Reloader from '@inject/graphql/components/Reloader'
import { useGetDefinitions } from '@inject/graphql/queries/GetDefinitions.generated'
import CardList from '@inject/shared/components/CardList'
import notEmpty from '@inject/shared/utils/notEmpty'
import type { FC } from 'react'
import { useState, type FC } from 'react'
import DefinitionUploader from './DefinitionUploader'
import Definition from './components/Definition'

interface DefinitionManagerProps {
@@ -19,18 +19,20 @@ interface DefinitionManagerProps {

const DefinitionManager: FC<DefinitionManagerProps> = ({ className }) => {
  const { data, refetch } = useGetDefinitions()
  const { open } = useModals()

  const [uploadOpen, setUploadOpen] = useState(false)

  const definitions = (data?.definitions || []).filter(notEmpty)
  return (
    <>
      <Section
        title='Definitions'
        rightElement={
          <ButtonGroup onClick={e => e.stopPropagation()}>
          {/* TODO: set as active when uploader is open */}
            <Button
              active={uploadOpen}
              onClick={() => {
              open('/instructor/definitionUploader')
                setUploadOpen(true)
              }}
              icon='upload'
            >
@@ -39,7 +41,6 @@ const DefinitionManager: FC<DefinitionManagerProps> = ({ className }) => {
            <Reloader onRefetch={refetch} />
          </ButtonGroup>
        }
      collapsible
      >
        <SectionCard>
          {definitions.length === 0 ? (
@@ -57,6 +58,9 @@ const DefinitionManager: FC<DefinitionManagerProps> = ({ className }) => {
          )}
        </SectionCard>
      </Section>

      <DefinitionUploader open={uploadOpen} setOpen={setUploadOpen} />
    </>
  )
}

+20 −12
Original line number Diff line number Diff line
import { useModals } from '@/router'
import {
  Button,
  Classes,
@@ -18,19 +17,31 @@ import { GetExercisesDocument } from '@inject/graphql/queries/GetExercises.gener
import { dialog } from '@inject/shared/css/dialog'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import notEmpty from '@inject/shared/utils/notEmpty'
import type { Dispatch, FC, SetStateAction } from 'react'
import { useCallback, useState } from 'react'

const TEAMS_MAX = 20

const ExerciseCreator = () => {
  const [open, setOpen] = useState<boolean>(true)
interface ExerciseCreatorProps {
  open: boolean
  setOpen: Dispatch<SetStateAction<boolean>>
}

const ExerciseCreator: FC<ExerciseCreatorProps> = ({ open, setOpen }) => {
  const [name, setName] = useState<string>('')
  const { close } = useModals()
  const [definition, setDefinition] = useState<Definition>()
  const [count, setCount] = useState<undefined | number>()

  const reset = useCallback(() => {
    setName('')
    setDefinition(undefined)
    setCount(undefined)
    setOpen(false)
  }, [setOpen])

  const [addExercise, { loading }] = useCreateExercises()
  const { data: definitionData } = useGetDefinitions()
  const { notify } = useNotifyContext()
  const [definition, setDefinition] = useState<Definition>()
  const [count, setCount] = useState<undefined | number>()

  const handleSubmit = useCallback(() => {
    if (!definition || !count) return
@@ -42,23 +53,20 @@ const ExerciseCreator = () => {
        name,
      },
      refetchQueries: [GetExercisesDocument],
      onCompleted: () => {
        setOpen(false)
      },
      onCompleted: reset,
      onError: err => {
        notify(err.message, {
          intent: 'danger',
        })
      },
    })
  }, [definition, count, addExercise, name, notify])
  }, [definition, count, addExercise, name, reset, notify])

  return (
    <Dialog
      className={dialog}
      isOpen={open}
      onClose={() => setOpen(false)}
      onClosed={() => close()}
      onClose={reset}
      icon='add'
      title='Create an exercise'
    >
Loading