Commit 141fa910 authored by Marek Veselý's avatar Marek Veselý
Browse files

Merge branch '1038-questionnaires-feedback-and-attempts-counter-missbehaving' into 'main'

Resolve "Questionnaires feedback and attempts counter missbehaving"

Closes #1038, #1037, and #1036

See merge request inject/frontend!880
parents 4d059619 1fc36334
Loading
Loading
Loading
Loading
+29 −34
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import Questionnaire from '../../../components/Questionnaire'
import type { QuestionAndAnswer } from '../../../components/Questionnaire/types'
import { mapQuestionsAndAnswers } from '../../../components/Questionnaire/utils'
import { parseMaxAttempts } from '../../../instructor/InstructorQuestionnaire/utils'
import type { QuestionnaireFeedback } from './getQuestionnaireFeedback'
import { getQuestionnaireFeedback } from './getQuestionnaireFeedback'

interface TraineeQuestionnaireContentProps {
@@ -38,7 +37,6 @@ interface TraineeQuestionnaireContentProps {
  exerciseId: string
  getFileLink: (fileId: string) => NavigateOptions
  onClose?: () => void
  inPopup?: boolean
}

const MultipleUsersWarning = () => {
@@ -157,7 +155,6 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
  exerciseId,
  onClose,
  getFileLink,
  inPopup,
}) => {
  const { t } = useTranslationFrontend()

@@ -165,9 +162,7 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({

  const exerciseStatus = useExerciseStatus({ teamId, exerciseId })
  const [submitError, setSubmitError] = useState('')
  const [feedback, setFeedback] = useState<QuestionnaireFeedback>()
  const { beginWiggling, wiggling } = useWiggle()
  const [submittedCount, setSubmittedCount] = useState(0)

  const {
    id: teamStateId,
@@ -237,8 +232,6 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
  }, [status, t, exerciseStatus, postExerciseSubmission])

  const maxAttempts = parseMaxAttempts(questionnaire.repeatable?.maxAttempts)
  const submissionCount =
    teamState.submissions.length + (inPopup ? submittedCount : 0)

  const handleSubmit = useCallback(
    (event: FormEvent<HTMLFormElement>) => {
@@ -267,13 +260,8 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
            beginWiggling()
            return
          }

          const updatedState = result.data?.answerQuestionnaire?.updatedState

          const hasFreeForm = questionnaire.questions.some(
            question =>
              question.details.__typename === 'FreeFormQuestionDetailsType'
          )
          // last submission is the one with the highest attempt number
          // TODO: this should be sorted by attempt on the backend
          const lastSubmission = updatedState?.submissions.reduce<
@@ -283,21 +271,12 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
              !last || current.attempt > last.attempt ? current : last,
            undefined
          )
          if (lastSubmission) {
            const feedback = getQuestionnaireFeedback({
              lastSubmission,
              maxAttempts,
              submissionCount,
              t,
              hasFreeForm,
              showFeedback,
            })
            setFeedback(feedback)
            if (feedback?.intent === 'danger') {
          if (
            lastSubmission &&
            (!lastSubmission.accepted || lastSubmission.correct === 'INCORRECT')
          ) {
            beginWiggling()
          }
          }

          if (
            updatedState &&
            (updatedState.attempts === 0 ||
@@ -305,9 +284,6 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
          ) {
            onClose?.()
          }
          if (inPopup) {
            setSubmittedCount(prev => prev + 1)
          }
        })
      } else {
        beginWiggling()
@@ -319,13 +295,8 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
      questionsAndAnswers,
      questionnaireId,
      teamId,
      questionnaire.questions,
      inPopup,
      t,
      beginWiggling,
      maxAttempts,
      submissionCount,
      showFeedback,
      onClose,
    ]
  )
@@ -337,6 +308,30 @@ const TraineeQuestionnaireContent: FC<TraineeQuestionnaireContentProps> = ({
    [modifyAnswer]
  )

  const submissionCount = teamState.submissions.length
  const hasFreeForm = questionnaire.questions.some(
    question => question.details.__typename === 'FreeFormQuestionDetailsType'
  )
  // last submission is the one with the highest attempt number
  // TODO: this should be sorted by attempt on the backend
  const lastSubmission = teamState?.submissions.reduce<
    TeamQuestionnaireStateShared['submissions'][number] | undefined
  >(
    (last, current) =>
      !last || current.attempt > last.attempt ? current : last,
    undefined
  )
  const feedback = lastSubmission
    ? getQuestionnaireFeedback({
        lastSubmission,
        maxAttempts,
        submissionCount,
        t,
        hasFreeForm,
        showFeedback,
      })
    : undefined

  return (
    <Questionnaire
      getFileLink={getFileLink}
+0 −3
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@ interface ContentProps {
  inInstructor: boolean
  getFileLink: (fileId: string) => NavigateOptions
  onClose?: () => void
  inPopup?: boolean
}

export const Content: FC<ContentProps> = ({
@@ -25,7 +24,6 @@ export const Content: FC<ContentProps> = ({
  inInstructor,
  getFileLink,
  onClose,
  inPopup,
}): JSX.Element => {
  switch (actionLog.details.__typename) {
    case 'TInjectDetailsType':
@@ -87,7 +85,6 @@ export const Content: FC<ContentProps> = ({
          teamId={teamId}
          exerciseId={exerciseId}
          onClose={onClose}
          inPopup={inPopup}
        />
      )
    }
+8 −2
Original line number Diff line number Diff line
@@ -54,7 +54,14 @@ export const ActionLogOverlay: FC<ActionLogOverlayProps> = ({ actionLog }) => {
      icon={getIcon(actionLog.logType)}
      onClose={() => {}}
    >
      <DialogBody className={dialogBody}>
      <DialogBody
        className={cx(
          dialogBody,
          css`
            overflow-x: hidden;
          `
        )}
      >
        <Content
          actionLog={actionLog}
          exerciseId={actionLog.team.exercise.id}
@@ -75,7 +82,6 @@ export const ActionLogOverlay: FC<ActionLogOverlayProps> = ({ actionLog }) => {
              typename: actionLog.__typename,
            })
          }
          inPopup
        />
      </DialogBody>