Skip to content

Commit

Permalink
Merge cc21db4 into 8ca6946
Browse files Browse the repository at this point in the history
  • Loading branch information
sjschlapbach authored Oct 4, 2024
2 parents 8ca6946 + cc21db4 commit 08c72d3
Show file tree
Hide file tree
Showing 18 changed files with 513 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Button } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import { twMerge } from 'tailwind-merge'

function CourseDeletionItem({
function DeletionItem({
label,
confirmed,
notApplicable,
Expand All @@ -24,7 +24,7 @@ function CourseDeletionItem({
const t = useTranslations()

return (
<div className="flex flex-row items-center justify-between border-b pb-2 pl-2">
<div className="flex min-h-10 flex-row items-center justify-between border-b pb-2 pl-2">
<div className="flex flex-row items-center gap-3.5">
<FontAwesomeIcon
icon={notApplicable ? faInfoCircle : faExclamationCircle}
Expand Down Expand Up @@ -60,4 +60,4 @@ function CourseDeletionItem({
)
}

export default CourseDeletionItem
export default DeletionItem
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CourseSummary } from '@klicker-uzh/graphql/dist/ops'
import { UserNotification } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import { Dispatch, SetStateAction } from 'react'
import CourseDeletionItem from './CourseDeletionItem'
import DeletionItem from '../../common/DeletionItem'
import { CourseDeletionConfirmationType } from './CourseDeletionModal'

interface CourseDeletionConfirmationsProps {
Expand All @@ -25,7 +25,7 @@ function CourseDeletionConfirmations({
message={t('manage.courseList.courseDeletionMessage')}
className={{ root: 'mb-1 text-base' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfParticipations === 0
? t('manage.courseList.noParticipationsToDelete')
Expand All @@ -43,7 +43,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfParticipations === 0}
data={{ cy: 'course-deletion-participations-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfLiveQuizzes === 0
? t('manage.courseList.noLiveQuizzesDisconnected')
Expand All @@ -61,7 +61,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfLiveQuizzes === 0}
data={{ cy: 'course-deletion-live-quiz-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfPracticeQuizzes === 0
? t('manage.courseList.noPracticeQuizzesToDelete')
Expand All @@ -79,7 +79,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfPracticeQuizzes === 0}
data={{ cy: 'course-deletion-practice-quiz-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfMicroLearnings === 0
? t('manage.courseList.noMicroLearningsToDelete')
Expand All @@ -97,7 +97,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfMicroLearnings === 0}
data={{ cy: 'course-deletion-micro-learning-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfGroupActivities === 0
? t('manage.courseList.noGroupActivitiesToDelete')
Expand All @@ -115,7 +115,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfGroupActivities === 0}
data={{ cy: 'course-deletion-group-activity-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfParticipantGroups === 0
? t('manage.courseList.noParticipantGroupsToDelete')
Expand All @@ -133,7 +133,7 @@ function CourseDeletionConfirmations({
notApplicable={summary.numOfParticipantGroups === 0}
data={{ cy: 'course-deletion-participant-group-confirm' }}
/>
<CourseDeletionItem
<DeletionItem
label={
summary.numOfLeaderboardEntries === 0
? t('manage.courseList.noLeaderboardEntriesToDelete')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,92 +1,151 @@
import { useMutation } from '@apollo/client'
import { useMutation, useQuery } from '@apollo/client'
import {
CancelSessionDocument,
GetLiveQuizSummaryDocument,
GetUserRunningSessionsDocument,
GetUserSessionsDocument,
} from '@klicker-uzh/graphql/dist/ops'
import { Button, H2, Modal, TextField } from '@uzh-bf/design-system'
import { Button, Modal } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import { useRouter } from 'next/router'
import { useState } from 'react'
import { twMerge } from 'tailwind-merge'
import { useEffect, useState } from 'react'
import SessionAbortionConfirmations from './SessionAbortionConfirmations'

export interface SessionAbortionConfirmationType {
deleteResponses: boolean
deleteFeedbacks: boolean
deleteConfusionFeedbacks: boolean
deleteLeaderboardEntries: boolean
}

interface CancelSessionModalProps {
sessionId: string
title: string
isCancellationModalOpen: boolean
setIsCancellationModalOpen: (value: boolean) => void
open: boolean
setOpen: (value: boolean) => void
}

function CancelSessionModal({
sessionId,
title,
isCancellationModalOpen,
setIsCancellationModalOpen,
open,
setOpen,
}: CancelSessionModalProps) {
const router = useRouter()
const t = useTranslations()
const [enteredName, setEnteredName] = useState('')

const [cancelSession] = useMutation(CancelSessionDocument, {
variables: { id: sessionId },
refetchQueries: [
{
query: GetUserRunningSessionsDocument,
},
{
query: GetUserSessionsDocument,
},
],
const initialConfirmations: SessionAbortionConfirmationType = {
deleteResponses: false,
deleteFeedbacks: false,
deleteConfusionFeedbacks: false,
deleteLeaderboardEntries: false,
}

const [confirmations, setConfirmations] =
useState<SessionAbortionConfirmationType>({
...initialConfirmations,
})

// fetch course information
const {
data,
loading: queryLoading,
refetch,
} = useQuery(GetLiveQuizSummaryDocument, {
variables: { quizId: sessionId },
skip: !open,
})

const [cancelSession, { loading: sessionDeleting }] = useMutation(
CancelSessionDocument,
{
variables: { id: sessionId },
refetchQueries: [
{
query: GetUserRunningSessionsDocument,
},
{
query: GetUserSessionsDocument,
},
],
}
)

// manually re-trigger the query when the modal is opened
useEffect(() => {
if (open) {
refetch()
}
}, [open])

useEffect(() => {
if (!data?.getLiveQuizSummary) {
return
}

setConfirmations({
deleteResponses: data.getLiveQuizSummary.numOfResponses === 0,
deleteFeedbacks: data.getLiveQuizSummary.numOfFeedbacks === 0,
deleteConfusionFeedbacks:
data.getLiveQuizSummary.numOfConfusionFeedbacks === 0,
deleteLeaderboardEntries:
data.getLiveQuizSummary.numOfLeaderboardEntries === 0,
})
}, [data?.getLiveQuizSummary])

if (!data?.getLiveQuizSummary) {
return null
}

const summary = data.getLiveQuizSummary

return (
<Modal
open={open}
onClose={() => {
setOpen(false)
setConfirmations({ ...initialConfirmations })
}}
className={{ content: '!w-full max-w-[60rem]' }}
title={t('manage.cockpit.confirmAbortSession', { title: title })}
onPrimaryAction={
<Button
loading={sessionDeleting}
disabled={
queryLoading ||
Object.values(confirmations).some((confirmation) => !confirmation)
}
onClick={async () => {
await cancelSession()
router.push('/sessions')
setOpen(false)
setConfirmations({ ...initialConfirmations })
}}
className={{
root: twMerge(
'bg-red-600 font-bold text-white',
enteredName !== title && 'cursor-not-allowed opacity-60'
),
root: 'bg-red-700 text-white hover:bg-red-800 hover:text-white disabled:bg-opacity-50 disabled:hover:cursor-not-allowed',
}}
data={{ cy: 'confirm-cancel-session' }}
disabled={enteredName !== title}
>
{t('shared.generic.confirm')}
</Button>
}
onSecondaryAction={
<Button
onClick={(): void => setIsCancellationModalOpen(false)}
onClick={() => {
setOpen(false)
setConfirmations({ ...initialConfirmations })
}}
data={{ cy: 'abort-cancel-session' }}
>
{t('shared.generic.cancel')}
{t('shared.generic.close')}
</Button>
}
onClose={(): void => setIsCancellationModalOpen(false)}
open={isCancellationModalOpen}
hideCloseButton={true}
className={{ content: 'h-max min-h-max w-[48rem] self-center !pt-0' }}
>
<div>
<H2>{t('manage.cockpit.confirmAbortSession', { title: title })}</H2>
<div className="my-2 italic">
{t('manage.cockpit.abortSessionHint')}
</div>
<div>
<div className="font-bold">{t('manage.cockpit.abortEnterName')}</div>
<TextField
value={enteredName}
onChange={(newValue) => setEnteredName(newValue)}
className={{ input: '!w-80' }}
data={{ cy: 'abort-enter-name' }}
/>
</div>
</div>
<SessionAbortionConfirmations
summary={summary}
confirmations={confirmations}
setConfirmations={setConfirmations}
/>
</Modal>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import DeletionItem from '@components/common/DeletionItem'
import { RunningLiveQuizSummary } from '@klicker-uzh/graphql/dist/ops'
import { UserNotification } from '@uzh-bf/design-system'
import { useTranslations } from 'next-intl'
import { Dispatch, SetStateAction } from 'react'
import { SessionAbortionConfirmationType } from './CancelSessionModal'

interface SessionAbortionConfirmationsProps {
summary: RunningLiveQuizSummary
confirmations: SessionAbortionConfirmationType
setConfirmations: Dispatch<SetStateAction<SessionAbortionConfirmationType>>
}

function SessionAbortionConfirmations({
summary,
confirmations,
setConfirmations,
}: SessionAbortionConfirmationsProps) {
const t = useTranslations()

return (
<div className="flex flex-col gap-2">
<UserNotification
type="warning"
message={t('manage.cockpit.cancelLiveQuizMessage')}
className={{ root: 'mb-1 text-base' }}
/>
<DeletionItem
label={
summary.numOfResponses === 0
? t('manage.cockpit.noResponsesToDelete')
: t('manage.cockpit.deleteResponses', {
number: summary.numOfResponses,
})
}
onClick={() => {
setConfirmations((prev) => ({
...prev,
deleteResponses: true,
}))
}}
confirmed={confirmations.deleteResponses}
notApplicable={summary.numOfResponses === 0}
data={{ cy: 'lq-deletion-responses-confirm' }}
/>
<DeletionItem
label={
summary.numOfFeedbacks === 0
? t('manage.cockpit.noFeedbacksToDelete')
: t('manage.cockpit.deleteFeedbacks', {
number: summary.numOfFeedbacks,
})
}
onClick={() => {
setConfirmations((prev) => ({
...prev,
deleteFeedbacks: true,
}))
}}
confirmed={confirmations.deleteFeedbacks}
notApplicable={summary.numOfFeedbacks === 0}
data={{ cy: 'lq-deletion-feedbacks-confirm' }}
/>
<DeletionItem
label={
summary.numOfConfusionFeedbacks === 0
? t('manage.cockpit.noConfusionFeedbacksToDelete')
: t('manage.cockpit.deleteConfusionFeedbacks', {
number: summary.numOfConfusionFeedbacks,
})
}
onClick={() => {
setConfirmations((prev) => ({
...prev,
deleteConfusionFeedbacks: true,
}))
}}
confirmed={confirmations.deleteConfusionFeedbacks}
notApplicable={summary.numOfConfusionFeedbacks === 0}
data={{ cy: 'lq-deletion-confusion-feedbacks-confirm' }}
/>
<DeletionItem
label={
summary.numOfLeaderboardEntries === 0
? t('manage.cockpit.noLeaderboardEntriesToDelete')
: t('manage.cockpit.deleteLeaderboardEntries', {
number: summary.numOfLeaderboardEntries,
})
}
onClick={() => {
setConfirmations((prev) => ({
...prev,
deleteLeaderboardEntries: true,
}))
}}
confirmed={confirmations.deleteLeaderboardEntries}
notApplicable={summary.numOfLeaderboardEntries === 0}
data={{ cy: 'lq-deletion-leaderboard-entries-confirm' }}
/>
</div>
)
}

export default SessionAbortionConfirmations
Loading

0 comments on commit 08c72d3

Please sign in to comment.