Skip to content

Commit

Permalink
enhance: add possibility to change live quiz name and displayname ind…
Browse files Browse the repository at this point in the history
…ependent of status (#4131)
  • Loading branch information
sjschlapbach committed May 24, 2024
1 parent 2d787c3 commit 525661c
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { useMutation } from '@apollo/client'
import { ChangeLiveQuizNameDocument } from '@klicker-uzh/graphql/dist/ops'
import { Button, FormikTextField, Modal, Toast } from '@uzh-bf/design-system'
import { Formik } from 'formik'
import { useTranslations } from 'next-intl'
import { useState } from 'react'
import { twMerge } from 'tailwind-merge'
import * as Yup from 'yup'

interface LiveQuizNameChangeModalProps {
quizId: string
name: string
displayName: string
open: boolean
setOpen: (value: boolean) => void
}

function LiveQuizNameChangeModal({
quizId,
name,
displayName,
open,
setOpen,
}: LiveQuizNameChangeModalProps) {
const t = useTranslations()
const [changeLiveQuizName] = useMutation(ChangeLiveQuizNameDocument)
const [successToast, setSuccessToast] = useState(false)
const [errorToast, setErrorToast] = useState(false)

const schema = Yup.object().shape({
name: Yup.string().required(t('manage.sessionForms.sessionName')),
displayName: Yup.string().required(
t('manage.sessionForms.sessionDisplayName')
),
})

return (
<>
<Modal
hideCloseButton
escapeDisabled
open={open}
onClose={(): void => setOpen(false)}
title={t('manage.sessions.changeLiveQuizName')}
className={{
content: 'w-[30rem] min-h-max h-max self-center pt-0',
title: 'text-xl',
}}
>
<Formik
initialValues={{
name: name,
displayName: displayName,
}}
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true)
const result = await changeLiveQuizName({
variables: {
id: quizId,
name: values.name,
displayName: values.displayName,
},
optimisticResponse: {
__typename: 'Mutation',
changeLiveQuizName: {
id: quizId,
name: values.name,
displayName: values.displayName,
},
},
})

if (result.data?.changeLiveQuizName?.id) {
setSuccessToast(true)
setSubmitting(false)
setOpen(false)
} else {
setErrorToast(true)
setSubmitting(false)
}
}}
validationSchema={schema}
isInitialValid={true}
>
{({ isValid, isSubmitting, submitForm }) => (
<>
<FormikTextField
required
labelType="small"
autoComplete="off"
name="name"
label={t('manage.sessionForms.name')}
tooltip={t('manage.sessionForms.liveQuizName')}
className={{
root: 'mb-2 -mt-2 w-full',
tooltip: 'z-20 w-80',
label: 'w-36',
}}
data-cy="insert-live-quiz-name"
shouldValidate={() => true}
/>
<FormikTextField
required
labelType="small"
autoComplete="off"
name="displayName"
label={t('manage.sessionForms.displayName')}
tooltip={t('manage.sessionForms.displayNameTooltip')}
className={{
root: 'w-full',
tooltip: 'z-20 w-80',
label: 'w-36',
}}
data-cy="insert-live-quiz-display-name"
/>
<div className="flex flex-row justify-between mt-3 -mb-4">
<Button
type="button"
onClick={(): void => setOpen(false)}
data={{ cy: 'live-quiz-name-change-cancel' }}
>
{t('shared.generic.cancel')}
</Button>
<Button
type="submit"
disabled={isSubmitting || !isValid}
loading={isSubmitting}
onClick={submitForm}
className={{
root: twMerge(
'bg-primary-80 font-bold text-white',
!isValid && 'bg-primary-60 cursor-not-allowed'
),
}}
data={{ cy: 'live-quiz-name-change-confirm' }}
>
{t('shared.generic.confirm')}
</Button>
</div>
</>
)}
</Formik>
</Modal>
<Toast
openExternal={successToast}
setOpenExternal={setSuccessToast}
type="success"
>
{t('manage.sessions.liveQuizNameChangeSuccess')}
</Toast>
<Toast
openExternal={errorToast}
setOpenExternal={setErrorToast}
type="error"
>
{t('manage.sessions.liveQuizNameChangeError')}
</Toast>
</>
)
}

export default LiveQuizNameChangeModal
20 changes: 19 additions & 1 deletion apps/frontend-manage/src/components/sessions/Session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useRouter } from 'next/router'
import { useState } from 'react'
import DeletionModal from '../courses/modals/DeletionModal'
import EmbeddingModal from './EmbeddingModal'
import LiveQuizNameChangeModal from './LiveQuizNameChangeModal'
import { WizardMode } from './creation/SessionCreation'

interface SessionProps {
Expand Down Expand Up @@ -98,6 +99,7 @@ function Session({ session }: SessionProps) {
const [embedModalOpen, setEmbedModalOpen] = useState<boolean>(false)
const [deletionModal, setDeletionModal] = useState<boolean>(false)
const [softDeletionModal, setSoftDeletionModal] = useState<boolean>(false)
const [changeName, setChangeName] = useState<boolean>(false)

const timeIcon: Record<SessionStatus, IconDefinition> = {
[SessionStatus.Prepared]: faCalendarDays,
Expand Down Expand Up @@ -134,7 +136,16 @@ function Session({ session }: SessionProps) {
className="flex flex-row justify-between"
data-cy="session-block"
>
<H3 className={{ root: 'mb-0' }}>{session.name}</H3>
<div className="flex flex-row items-center gap-3">
<H3 className={{ root: 'mb-0' }}>{session.name}</H3>
<FontAwesomeIcon
icon={faPencil}
size="sm"
onClick={() => setChangeName(true)}
className="hover:cursor-pointer"
data-cy={`change-liveQuiz-name-${session.name}`}
/>
</div>
<div className="flex flex-row gap-5">
{session.blocks?.length !== 0 && (
<>
Expand Down Expand Up @@ -366,6 +377,13 @@ function Session({ session }: SessionProps) {
primaryData={{ cy: 'confirm-delete-live-quiz' }}
secondaryData={{ cy: 'cancel-delete-live-quiz' }}
/>
<LiveQuizNameChangeModal
quizId={session.id}
name={session.name}
displayName={session.displayName}
open={changeName}
setOpen={setChangeName}
/>
</>
)
}
Expand Down
24 changes: 20 additions & 4 deletions cypress/cypress/e2e/F-live-quiz-workflow.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,29 @@ describe('Different live-quiz workflows', () => {
cy.get('[data-cy="load-session-list"]').click()
cy.contains('[data-cy="session-block"]', sessionName)

// delete this session again
// rename the session
const newSessionName = uuid()
const newSessionDisplayName = uuid()
cy.findByText(sessionName).should('exist')
cy.get(`[data-cy="delete-session-${sessionName}"]`).click()
cy.get(`[data-cy="change-liveQuiz-name-${sessionName}"]`).click()
cy.get('[data-cy="live-quiz-name-change-confirm"]').should(
'not.be.disabled'
)
cy.get('[data-cy="live-quiz-name-change-cancel"]').click()
cy.get(`[data-cy="change-liveQuiz-name-${sessionName}"]`).click()
cy.get('[data-cy="insert-live-quiz-name"]').clear().type(newSessionName)
cy.get('[data-cy="insert-live-quiz-display-name"]')
.clear()
.type(newSessionDisplayName)
cy.get('[data-cy="live-quiz-name-change-confirm"]').click()

// delete this session again
cy.findByText(newSessionName).should('exist')
cy.get(`[data-cy="delete-session-${newSessionName}"]`).click()
cy.get(`[data-cy="cancel-delete-live-quiz"]`).click()
cy.get(`[data-cy="delete-session-${sessionName}"]`).click()
cy.get(`[data-cy="delete-session-${newSessionName}"]`).click()
cy.get(`[data-cy="confirm-delete-live-quiz"]`).click()
cy.findByText(sessionName).should('not.exist')
cy.findByText(newSessionName).should('not.exist')
})

it('creates a session, starts it and aborts it and then restarts it', () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/graphql/src/graphql/ops/MChangeLiveQuizName.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mutation ChangeLiveQuizName(
$id: String!
$name: String!
$displayName: String!
) {
changeLiveQuizName(id: $id, name: $name, displayName: $displayName) {
id
name
displayName
}
}
61 changes: 61 additions & 0 deletions packages/graphql/src/ops.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6212,6 +6212,67 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "changeLiveQuizName",
"description": null,
"args": [
{
"name": "displayName",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "name",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "OBJECT",
"name": "Session",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "changeParticipantLocale",
"description": null,
Expand Down

0 comments on commit 525661c

Please sign in to comment.