Commit 72bafc48 authored by Filip Šenk's avatar Filip Šenk
Browse files

Fixed move time

parent 3db0f1f2
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -8,9 +8,9 @@ import {
  NumericInput,
} from '@blueprintjs/core'
import { css, cx } from '@emotion/css'
import type { ExerciseState } from '@inject/graphql'
import {
  MoveTime,
  useLoopStatus,
  useTypedMutation,
  type CustomOperationContext,
} from '@inject/graphql'
@@ -30,7 +30,7 @@ interface MoveTimeButtonProps {
  hideLabel: boolean
  exerciseId?: string
  disabledTitle?: string
  teamId?: string
  status?: ExerciseState['status'] | 'onDemand' | undefined
}

// TODO: only allow for non-on-demand exercises
@@ -39,14 +39,13 @@ export const MoveTimeButton: FC<MoveTimeButtonProps> = ({
  hideLabel,
  exerciseId,
  disabledTitle,
  teamId,
  status,
}) => {
  const [open, setOpen] = useState(false)
  const [minutesText, setMinutesText] = useState('')
  const [minutes, setMinutes] = useState<number | undefined>(undefined)
  const [error, setError] = useState('')
  const [{ fetching: loading }, moveTime] = useTypedMutation(MoveTime)
  const { running } = useLoopStatus({ teamId })
  const { beginWiggling, wiggling } = useWiggle()

  const handleSubmit = useCallback(
@@ -89,11 +88,13 @@ export const MoveTimeButton: FC<MoveTimeButtonProps> = ({
        active={open}
        style={{ whiteSpace: 'nowrap' }}
        title={
          exerciseId && running
          status === 'onDemand'
            ? 'Cannot move time of on-demand exercise'
            : exerciseId && status === 'RUNNING'
              ? 'Move time'
              : disabledTitle || 'The exercise has to be running to move time'
        }
        disabled={!exerciseId || !running}
        disabled={!exerciseId || status !== 'RUNNING'}
      />

      <Dialog
@@ -158,8 +159,10 @@ export const MoveTimeButton: FC<MoveTimeButtonProps> = ({
              <Button
                type='submit'
                intent='primary'
                disabled={!exerciseId || !running || wiggling}
                title={exerciseId && running ? 'Move time' : undefined}
                disabled={!exerciseId || status !== 'RUNNING' || wiggling}
                title={
                  exerciseId && status !== 'RUNNING' ? 'Move time' : undefined
                }
                loading={loading}
                className={cx({
                  [wiggleClass]: wiggling,
+68 −46
Original line number Diff line number Diff line
@@ -25,11 +25,7 @@ const header = css`

const vertical = css`
  flex-direction: column;
  row-gap: 0.5rem;
  & > #second {
    flex-direction: column;
    row-gap: 0.5rem;
  }
  row-gap: 0.2rem;
`

interface StatusProps {
@@ -39,6 +35,7 @@ interface StatusProps {
  hideLabel?: boolean
  getStatus?: () => ExerciseState['status']
  onDemand?: boolean
  teamId?: string
}

export const ExerciseStatus: FC<StatusProps> = ({
@@ -47,7 +44,11 @@ export const ExerciseStatus: FC<StatusProps> = ({
  hideLabel,
  onDemand,
  getStatus,
}) => (
  teamId,
}) => {
  const localTeamId = teamId ? teamId : team?.id

  return (
    <div className={wrapper}>
      <div
        className={cx({
@@ -74,7 +75,18 @@ export const ExerciseStatus: FC<StatusProps> = ({
        </div>

        <div
        id='second'
          className={cx(
            css`
              display: flex;
              align-items: center;
              column-gap: 0.4rem;
            `,
            {
              [vertical]: !!showTime && !onDemand && !!localTeamId,
            }
          )}
        >
          <div
            className={css`
              display: flex;
              align-items: center;
@@ -85,11 +97,21 @@ export const ExerciseStatus: FC<StatusProps> = ({
            {getStatus && (
              <ExerciseTags getStatus={getStatus} onDemand={onDemand} />
            )}
        {showTime && team?.id && getStatus?.() === 'RUNNING' && (
          <TimeLeft teamId={team.id} />
        )}
            <ColorModeMini fill={hideLabel} />
          </div>

          <div
            className={css`
              display: flex;
              align-items: center;
            `}
          >
            {showTime && !onDemand && localTeamId && (
              <TimeLeft teamId={localTeamId} />
            )}
          </div>
        </div>
      </div>
    </div>
  )
}
+8 −1
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ export const InstructorView: FC<InstructorViewProps> = ({
                ? () => synchronousExerciseState(exerciseStatus).status
                : undefined
            }
            teamId={exerciseStatus?.states[0].teams[0].id}
            onDemand={exerciseStatus?.onDemand}
          />
        </div>
@@ -112,7 +113,13 @@ export const InstructorView: FC<InstructorViewProps> = ({
            disabledTitle={
              exerciseId ? undefined : 'A team has to be selected to move time'
            }
            teamId={teamId}
            status={
              exerciseStatus
                ? exerciseStatus.onDemand
                  ? 'onDemand'
                  : synchronousExerciseState(exerciseStatus).status
                : undefined
            }
          />
          {exerciseId && !teamId && (
            <MilestonesButton
+6 −2
Original line number Diff line number Diff line
@@ -533,8 +533,12 @@ const cache: Exchange = offlineExchange<GraphCacheConfig>({
          cache.link(...params, [...link, cache.keyOfEntity(newTag)])
        }
      },
      moveTime(_, __, cache) {
        cache.invalidate('Query', 'exerciseTimeLeft')
      moveTime(parent, __, cache) {
        if (parent.moveTime?.exercise) {
          parent.moveTime?.exercise.teams.forEach(team =>
            cache.invalidate('Query', 'exerciseTimeLeft', { teamId: team.id })
          )
        }
      },
      modifyMilestone() {
        // TODO: should return the updated milestone state (backend) => then, proper invalidation can be done of the state, LA, LO, and team (score, achieved)