diff --git a/src/components/questionPreviews/DateQuestionPreview/index.module.css b/src/components/questionPreviews/DateQuestionPreview/index.module.css index ec321db..cd5f931 100644 --- a/src/components/questionPreviews/DateQuestionPreview/index.module.css +++ b/src/components/questionPreviews/DateQuestionPreview/index.module.css @@ -1,6 +1,5 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); } diff --git a/src/components/questionPreviews/FileQuestionPreview/index.module.css b/src/components/questionPreviews/FileQuestionPreview/index.module.css index 23548fe..3f0555a 100644 --- a/src/components/questionPreviews/FileQuestionPreview/index.module.css +++ b/src/components/questionPreviews/FileQuestionPreview/index.module.css @@ -1,7 +1,6 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); .upload-preview-wrapper { diff --git a/src/components/questionPreviews/ImageQuestionPreview/index.module.css b/src/components/questionPreviews/ImageQuestionPreview/index.module.css index 23548fe..3f0555a 100644 --- a/src/components/questionPreviews/ImageQuestionPreview/index.module.css +++ b/src/components/questionPreviews/ImageQuestionPreview/index.module.css @@ -1,7 +1,6 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); .upload-preview-wrapper { diff --git a/src/components/questionPreviews/IntegerQuestionPreview/index.module.css b/src/components/questionPreviews/IntegerQuestionPreview/index.module.css index ec321db..cd5f931 100644 --- a/src/components/questionPreviews/IntegerQuestionPreview/index.module.css +++ b/src/components/questionPreviews/IntegerQuestionPreview/index.module.css @@ -1,6 +1,5 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); } diff --git a/src/components/questionPreviews/NoteQuestionPreview/index.module.css b/src/components/questionPreviews/NoteQuestionPreview/index.module.css index ec321db..cd5f931 100644 --- a/src/components/questionPreviews/NoteQuestionPreview/index.module.css +++ b/src/components/questionPreviews/NoteQuestionPreview/index.module.css @@ -1,6 +1,5 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); } diff --git a/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.module.css b/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.module.css new file mode 100644 index 0000000..e25ef0c --- /dev/null +++ b/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.module.css @@ -0,0 +1,13 @@ +.item-wrapper { + display: flex; + border: var(--dui-width-separator-thin) solid var(--dui-color-separator); + border-radius: var(--dui-border-radius-card); + + .icon { + background-color: var(--color-gray2); + padding: var(--dui-spacing-small); + } + .item { + padding: var(--dui-spacing-small); + } +} diff --git a/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.tsx b/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.tsx new file mode 100644 index 0000000..b82c322 --- /dev/null +++ b/src/components/questionPreviews/RankQuestionPreview/RankQuestionItem/index.tsx @@ -0,0 +1,31 @@ +import { + GrDrag, +} from 'react-icons/gr'; +import { + Element, +} from '@the-deep/deep-ui'; + +import styles from './index.module.css'; + +interface Props { + title: string; +} + +function RankQuestionItem(props: Props) { + const { + title, + } = props; + + return ( + } + iconsContainerClassName={styles.icon} + childrenContainerClassName={styles.item} + > + {title} + + ); +} + +export default RankQuestionItem; diff --git a/src/components/questionPreviews/RankQuestionPreview/index.module.css b/src/components/questionPreviews/RankQuestionPreview/index.module.css index ec321db..a9a2b4c 100644 --- a/src/components/questionPreviews/RankQuestionPreview/index.module.css +++ b/src/components/questionPreviews/RankQuestionPreview/index.module.css @@ -1,6 +1,22 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); + + .choices-preview { + align-items: flex-start; + gap: var(--dui-spacing-large); + + .icon { + color: var(--dui-color-primary); + font-size: var(--dui-font-size-extra-large); + } + + .choices { + display: flex; + flex-grow: 1; + flex-direction: column; + gap: var(--dui-spacing-small); + } + } } diff --git a/src/components/questionPreviews/RankQuestionPreview/index.tsx b/src/components/questionPreviews/RankQuestionPreview/index.tsx index c8741ca..19e972e 100644 --- a/src/components/questionPreviews/RankQuestionPreview/index.tsx +++ b/src/components/questionPreviews/RankQuestionPreview/index.tsx @@ -1,16 +1,60 @@ +import { useMemo, useCallback } from 'react'; +import { + IoSwapVertical, +} from 'react-icons/io5'; import { _cs, + isNotDefined, } from '@togglecorp/fujs'; import { + gql, + useQuery, +} from '@apollo/client'; +import { + Element, + ListView, TextOutput, } from '@the-deep/deep-ui'; +import { + RankChoicesQuery, + RankChoicesQueryVariables, +} from '#generated/types'; + +import RankQuestionItem from './RankQuestionItem'; import styles from './index.module.css'; +const RANK_CHOICES = gql` + query RankChoices ( + $projectId: ID!, + $choiceCollectionId: ID!, + ) { + private { + projectScope(pk: $projectId) { + choiceCollection(pk: $choiceCollectionId) { + id + name + label + choices { + id + label + name + } + } + } + } + } +`; + +type ChoiceType = NonNullable['projectScope']>['choiceCollection']>['choices']>[number]; +const rankChoiceKeySelector = (c: ChoiceType) => c.id; + interface Props { className?: string; label?: string; hint?: string | null; + choiceCollectionId: string | undefined | null; + projectId: string; } function RankQuestionPreview(props: Props) { @@ -18,8 +62,39 @@ function RankQuestionPreview(props: Props) { className, label, hint, + choiceCollectionId, + projectId, } = props; + const rankChoicesVariables = useMemo(() => { + if (isNotDefined(projectId) || isNotDefined(choiceCollectionId)) { + return undefined; + } + return ({ + projectId, + choiceCollectionId, + }); + }, [ + projectId, + choiceCollectionId, + ]); + + const { + data: optionsListResponse, + } = useQuery( + RANK_CHOICES, + { + skip: isNotDefined(rankChoicesVariables), + variables: rankChoicesVariables, + }, + ); + + const choices = optionsListResponse?.private?.projectScope?.choiceCollection?.choices ?? []; + + const rankChoiceRendererParams = useCallback((_: string, datum: ChoiceType) => ({ + title: datum.label, + }), []); + return (
+ } + iconsContainerClassName={styles.icon} + > + +
); } diff --git a/src/components/questionPreviews/SelectMultipleQuestionPreview/index.module.css b/src/components/questionPreviews/SelectMultipleQuestionPreview/index.module.css index 2f92235..dd06007 100644 --- a/src/components/questionPreviews/SelectMultipleQuestionPreview/index.module.css +++ b/src/components/questionPreviews/SelectMultipleQuestionPreview/index.module.css @@ -1,7 +1,6 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); .checkbox-list { diff --git a/src/components/questionPreviews/SelectOneQuestionPreview/index.module.css b/src/components/questionPreviews/SelectOneQuestionPreview/index.module.css index 8a243df..8ab04d5 100644 --- a/src/components/questionPreviews/SelectOneQuestionPreview/index.module.css +++ b/src/components/questionPreviews/SelectOneQuestionPreview/index.module.css @@ -1,7 +1,6 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); .question-list { diff --git a/src/components/questionPreviews/TextQuestionPreview/index.module.css b/src/components/questionPreviews/TextQuestionPreview/index.module.css index ec321db..cd5f931 100644 --- a/src/components/questionPreviews/TextQuestionPreview/index.module.css +++ b/src/components/questionPreviews/TextQuestionPreview/index.module.css @@ -1,6 +1,5 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); } diff --git a/src/components/questionPreviews/TimeQuestionPreview/index.module.css b/src/components/questionPreviews/TimeQuestionPreview/index.module.css index ec321db..cd5f931 100644 --- a/src/components/questionPreviews/TimeQuestionPreview/index.module.css +++ b/src/components/questionPreviews/TimeQuestionPreview/index.module.css @@ -1,6 +1,5 @@ .preview { display: flex; flex-direction: column; - padding: var(--dui-spacing-extra-large) var(--dui-spacing-large); gap: var(--dui-spacing-medium); } diff --git a/src/views/QuestionnaireEdit/DateQuestionForm/index.module.css b/src/views/QuestionnaireEdit/DateQuestionForm/index.module.css index 77597e1..249c579 100644 --- a/src/views/QuestionnaireEdit/DateQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/DateQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { display: flex; diff --git a/src/views/QuestionnaireEdit/FileQuestionForm/index.module.css b/src/views/QuestionnaireEdit/FileQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/FileQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/FileQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/ImageQuestionForm/index.module.css b/src/views/QuestionnaireEdit/ImageQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/ImageQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/ImageQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/IntegerQuestionForm/index.module.css b/src/views/QuestionnaireEdit/IntegerQuestionForm/index.module.css index 77597e1..249c579 100644 --- a/src/views/QuestionnaireEdit/IntegerQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/IntegerQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { display: flex; diff --git a/src/views/QuestionnaireEdit/NoteQuestionForm/index.module.css b/src/views/QuestionnaireEdit/NoteQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/NoteQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/NoteQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/QuestionPreview/index.module.css b/src/views/QuestionnaireEdit/QuestionPreview/index.module.css index c8f3629..e9520e4 100644 --- a/src/views/QuestionnaireEdit/QuestionPreview/index.module.css +++ b/src/views/QuestionnaireEdit/QuestionPreview/index.module.css @@ -1,15 +1,18 @@ .preview { + --input-width: 35rem; border: none !important; background-color: var(--dui-color-background); overflow-y: auto; gap: var(--dui-spacing-large); .question-wrapper { - padding: var(--dui-spacing-medium); + align-items: flex-start; + padding: var(--dui-spacing-extra-large); + gap: var(--dui-spacing-extra-large); } .question-item { flex-grow: 1; - padding: var(--dui-spacing-extra-large); + max-width: var(--input-width); } } diff --git a/src/views/QuestionnaireEdit/QuestionPreview/index.tsx b/src/views/QuestionnaireEdit/QuestionPreview/index.tsx index 8f78eb7..3fc08dc 100644 --- a/src/views/QuestionnaireEdit/QuestionPreview/index.tsx +++ b/src/views/QuestionnaireEdit/QuestionPreview/index.tsx @@ -5,10 +5,12 @@ import { import { isNotDefined, isDefined, + noOp, } from '@togglecorp/fujs'; import { TabPanel, Element, + Checkbox, QuickActionDropdownMenu, DropdownMenuItem, } from '@the-deep/deep-ui'; @@ -70,6 +72,14 @@ function QuestionPreview(props: QuestionProps) { > + )} actions={( } @@ -98,11 +108,13 @@ function QuestionPreview(props: QuestionProps) { hint={question.hint} /> )} - {(question.type === 'RANK') && ( + {(question.type === 'RANK') && isDefined(projectId) && ( )} {(question.type === 'DATE') && ( diff --git a/src/views/QuestionnaireEdit/RankQuestionForm/index.module.css b/src/views/QuestionnaireEdit/RankQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/RankQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/RankQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/RankQuestionForm/index.tsx b/src/views/QuestionnaireEdit/RankQuestionForm/index.tsx index fa3e42e..d6550c5 100644 --- a/src/views/QuestionnaireEdit/RankQuestionForm/index.tsx +++ b/src/views/QuestionnaireEdit/RankQuestionForm/index.tsx @@ -33,8 +33,9 @@ import { QuestionUpdateInput, QuestionTypeEnum, } from '#generated/types'; -import TextQuestionPreview from '#components/questionPreviews/TextQuestionPreview'; +import RankQuestionPreview from '#components/questionPreviews/RankQuestionPreview'; import PillarSelectInput from '#components/PillarSelectInput'; +import ChoiceCollectionSelectInput from '#components/ChoiceCollectionSelectInput'; import { QUESTION_FRAGMENT, @@ -110,6 +111,10 @@ const schema: FormSchema = { required: true, requiredValidation: requiredStringCondition, }, + choiceCollection: { + required: true, + requiredValidation: requiredStringCondition, + }, group: { required: true, requiredValidation: requiredStringCondition, @@ -179,6 +184,7 @@ function RankQuestionForm(props: Props) { label: questionResponse?.label, group: questionResponse?.groupId, hint: questionResponse?.hint, + choiceCollection: questionResponse?.choiceCollection?.id, }); }, }, @@ -284,10 +290,12 @@ function RankQuestionForm(props: Props) { return (
-
+ ; type FormSchema = ObjectSchema; type FormSchemaFields = ReturnType; @@ -93,6 +125,7 @@ const schema: FormSchema = { interface Props { projectId: string; questionnaireId: string; + questionId?: string; onSuccess: (questionId: string | undefined) => void; } @@ -100,11 +133,62 @@ function SelectMultipleQuestionForm(props: Props) { const { projectId, questionnaireId, + questionId, onSuccess, } = props; const alert = useAlert(); + const initialFormValue: FormType = { + type: 'SELECT_MULTIPLE' as QuestionTypeEnum, + questionnaire: questionnaireId, + }; + + const { + pristine, + validate, + value: formValue, + error: formError, + setFieldValue, + setValue, + setError, + } = useForm(schema, { value: initialFormValue }); + + const fieldError = getErrorObject(formError); + + const questionInfoVariables = useMemo(() => { + if (isNotDefined(projectId) || isNotDefined(questionId)) { + return undefined; + } + return ({ + projectId, + questionId, + }); + }, [ + projectId, + questionId, + ]); + + useQuery( + QUESTION_INFO, + { + skip: isNotDefined(questionInfoVariables), + variables: questionInfoVariables, + onCompleted: (response) => { + const questionResponse = response.private.projectScope?.question; + setValue({ + name: questionResponse?.name, + type: questionResponse?.type, + questionnaire: questionResponse?.questionnaireId, + label: questionResponse?.label, + group: questionResponse?.groupId, + hint: questionResponse?.hint, + choiceCollection: questionResponse?.choiceCollection?.id, + }); + }, + }, + ); + const [ triggerQuestionCreate, { loading: createQuestionPending }, @@ -140,39 +224,71 @@ function SelectMultipleQuestionForm(props: Props) { }, }, ); - const initialFormValue: FormType = { - type: 'SELECT_MULTIPLE' as QuestionTypeEnum, - questionnaire: questionnaireId, - name: randomString(), - }; - - const { - pristine, - validate, - value: formValue, - error: formError, - setFieldValue, - setError, - } = useForm(schema, { value: initialFormValue }); - const fieldError = getErrorObject(formError); + const [ + triggerQuestionUpdate, + { loading: updateQuestionPending }, + ] = useMutation< + UpdateMultipleSelectionQuestionMutation, + UpdateMultipleSelectionQuestionMutationVariables + >( + UPDATE_MULTIPLE_SELECTION_QUESTION, + { + onCompleted: (questionResponse) => { + const response = questionResponse?.private?.projectScope?.updateQuestion; + if (!response) { + return; + } + if (response.ok) { + onSuccess(response.result?.id); + alert.show( + 'Question updated successfully.', + { variant: 'success' }, + ); + } else { + alert.show( + 'Failed to update question.', + { variant: 'error' }, + ); + } + }, + onError: () => { + alert.show( + 'Failed to update question.', + { variant: 'error' }, + ); + }, + }, + ); const handleQuestionSubmit = useCallback(() => { const handler = createSubmitHandler( validate, setError, (valueFromForm) => { - triggerQuestionCreate({ - variables: { - projectId, - input: valueFromForm as QuestionCreateInput, - }, - }); + if (isDefined(questionId)) { + triggerQuestionUpdate({ + variables: { + projectId, + questionId, + input: valueFromForm as QuestionUpdateInput, + }, + }); + } else { + triggerQuestionCreate({ + variables: { + projectId, + input: valueFromForm as QuestionCreateInput, + }, + }); + } }, ); handler(); }, [ triggerQuestionCreate, + triggerQuestionUpdate, + questionId, projectId, setError, validate, @@ -202,6 +318,13 @@ function SelectMultipleQuestionForm(props: Props) { error={fieldError?.hint} onChange={setFieldValue} /> + Apply diff --git a/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.module.css b/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.tsx b/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.tsx index 4eea940..14047ac 100644 --- a/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.tsx +++ b/src/views/QuestionnaireEdit/SelectOneQuestionForm/index.tsx @@ -1,10 +1,12 @@ -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { - randomString, + isDefined, + isNotDefined, } from '@togglecorp/fujs'; import { gql, useMutation, + useQuery, } from '@apollo/client'; import { Button, @@ -21,10 +23,15 @@ import { } from '@togglecorp/toggle-form'; import { - QuestionCreateInput, - QuestionTypeEnum, CreateSingleSelectionQuestionMutation, CreateSingleSelectionQuestionMutationVariables, + UpdateSingleSelectionQuestionMutation, + UpdateSingleSelectionQuestionMutationVariables, + QuestionInfoQuery, + QuestionInfoQueryVariables, + QuestionCreateInput, + QuestionUpdateInput, + QuestionTypeEnum, } from '#generated/types'; import SelectOneQuestionPreview from '#components/questionPreviews/SelectOneQuestionPreview'; import PillarSelectInput from '#components/PillarSelectInput'; @@ -32,6 +39,7 @@ import ChoiceCollectionSelectInput from '#components/ChoiceCollectionSelectInput import { QUESTION_FRAGMENT, + QUESTION_INFO, } from '../queries.ts'; import styles from './index.module.css'; @@ -57,6 +65,30 @@ const CREATE_SINGLE_SELECTION_QUESTION = gql` } `; +const UPDATE_SINGLE_SELECTION_QUESTION = gql` + ${QUESTION_FRAGMENT} + mutation UpdateSingleSelectionQuestion( + $projectId: ID!, + $questionId: ID!, + $input: QuestionUpdateInput!, + ) { + private { + projectScope(pk: $projectId) { + updateQuestion ( + data: $input + id: $questionId, + ) { + ok + errors + result { + ...QuestionResponse + } + } + } + } + } +`; + type FormType = PartialForm; type FormSchema = ObjectSchema; type FormSchemaFields = ReturnType; @@ -94,6 +126,7 @@ const schema: FormSchema = { interface Props { projectId: string; questionnaireId: string; + questionId?: string; onSuccess: (questionId: string | undefined) => void; } @@ -101,10 +134,62 @@ function SelectOneQuestionForm(props: Props) { const { projectId, questionnaireId, + questionId, onSuccess, } = props; const alert = useAlert(); + + const initialFormValue: FormType = { + type: 'SELECT_ONE' as QuestionTypeEnum, + questionnaire: questionnaireId, + }; + + const { + pristine, + validate, + value: formValue, + error: formError, + setFieldValue, + setValue, + setError, + } = useForm(schema, { value: initialFormValue }); + + const fieldError = getErrorObject(formError); + + const questionInfoVariables = useMemo(() => { + if (isNotDefined(projectId) || isNotDefined(questionId)) { + return undefined; + } + return ({ + projectId, + questionId, + }); + }, [ + projectId, + questionId, + ]); + + useQuery( + QUESTION_INFO, + { + skip: isNotDefined(questionInfoVariables), + variables: questionInfoVariables, + onCompleted: (response) => { + const questionResponse = response.private.projectScope?.question; + setValue({ + name: questionResponse?.name, + type: questionResponse?.type, + questionnaire: questionResponse?.questionnaireId, + label: questionResponse?.label, + group: questionResponse?.groupId, + hint: questionResponse?.hint, + choiceCollection: questionResponse?.choiceCollection?.id, + }); + }, + }, + ); + const [ triggerQuestionCreate, { loading: createQuestionPending }, @@ -140,39 +225,71 @@ function SelectOneQuestionForm(props: Props) { }, }, ); - const initialFormValue: FormType = { - type: 'SELECT_ONE' as QuestionTypeEnum, - questionnaire: questionnaireId, - name: randomString(), - }; - - const { - pristine, - validate, - value: formValue, - error: formError, - setFieldValue, - setError, - } = useForm(schema, { value: initialFormValue }); - const fieldError = getErrorObject(formError); + const [ + triggerQuestionUpdate, + { loading: updateQuestionPending }, + ] = useMutation< + UpdateSingleSelectionQuestionMutation, + UpdateSingleSelectionQuestionMutationVariables + >( + UPDATE_SINGLE_SELECTION_QUESTION, + { + onCompleted: (questionResponse) => { + const response = questionResponse?.private?.projectScope?.updateQuestion; + if (!response) { + return; + } + if (response.ok) { + onSuccess(response.result?.id); + alert.show( + 'Question updated successfully.', + { variant: 'success' }, + ); + } else { + alert.show( + 'Failed to update question.', + { variant: 'error' }, + ); + } + }, + onError: () => { + alert.show( + 'Failed to update question.', + { variant: 'error' }, + ); + }, + }, + ); const handleQuestionSubmit = useCallback(() => { const handler = createSubmitHandler( validate, setError, (valueFromForm) => { - triggerQuestionCreate({ - variables: { - projectId, - input: valueFromForm as QuestionCreateInput, - }, - }); + if (isDefined(questionId)) { + triggerQuestionUpdate({ + variables: { + projectId, + questionId, + input: valueFromForm as QuestionUpdateInput, + }, + }); + } else { + triggerQuestionCreate({ + variables: { + projectId, + input: valueFromForm as QuestionCreateInput, + }, + }); + } }, ); handler(); }, [ triggerQuestionCreate, + triggerQuestionUpdate, + questionId, projectId, setError, validate, @@ -202,6 +319,13 @@ function SelectOneQuestionForm(props: Props) { error={fieldError?.hint} onChange={setFieldValue} /> + Apply diff --git a/src/views/QuestionnaireEdit/TextQuestionForm/index.module.css b/src/views/QuestionnaireEdit/TextQuestionForm/index.module.css index 88a597a..97261c0 100644 --- a/src/views/QuestionnaireEdit/TextQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/TextQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { diff --git a/src/views/QuestionnaireEdit/TimeQuestionForm/index.module.css b/src/views/QuestionnaireEdit/TimeQuestionForm/index.module.css index 77597e1..249c579 100644 --- a/src/views/QuestionnaireEdit/TimeQuestionForm/index.module.css +++ b/src/views/QuestionnaireEdit/TimeQuestionForm/index.module.css @@ -6,6 +6,7 @@ .preview { border: var(--dui-width-separator-thin) solid var(--dui-color-separator); border-radius: var(--dui-border-radius-card); + padding: var(--dui-spacing-extra-large); } .edit-section { display: flex; diff --git a/src/views/QuestionnaireEdit/index.tsx b/src/views/QuestionnaireEdit/index.tsx index eb678f6..80cd02a 100644 --- a/src/views/QuestionnaireEdit/index.tsx +++ b/src/views/QuestionnaireEdit/index.tsx @@ -8,6 +8,7 @@ import { IoCloseOutline, IoDocumentTextOutline, IoRadioButtonOn, + IoSwapVertical, } from 'react-icons/io5'; import { MdOutline123, @@ -165,7 +166,7 @@ const questionTypes: QuestionType[] = [ { key: 'RANK', name: 'Rank', - icon: , + icon: , }, { key: 'DATE', @@ -340,6 +341,13 @@ export function Component() { projectId, ]); + const handleQuestionAdd = useCallback(() => { + showAddQuestionPane(); + setActiveQuestionId(undefined); + }, [ + showAddQuestionPane, + ]); + const groupTabRenderParams = useCallback((_: string, datum: QuestionGroup) => ({ children: datum.label, name: datum.id, @@ -387,7 +395,7 @@ export function Component() { actions={(