Skip to content

Commit

Permalink
[JN-1453] Add freetext editor to survey question designer (#1349)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewBemis authored Jan 8, 2025
1 parent d4e9108 commit ee2e4e1
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 11 deletions.
34 changes: 34 additions & 0 deletions ui-admin/src/forms/designer/split/FormElementFreetextEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Question, QuestionType } from '@juniper/ui-core'
import React, { useState } from 'react'
import { Textarea } from 'components/forms/Textarea'
import { questionFromRawText } from '../../../util/juniperSurveyUtils'

export const FormElementFreetextEditor = ({ question, onChange }: {
question: Question, onChange: (newQuestion: Question) => void
}) => {
const [freetext, setFreetext] = useState<string>('')

return <Textarea
className="form-control mb-3 p-2"
value={freetext}
rows={15}
onChange={value => {
setFreetext(value)
const newQuestionObj = questionFromRawText(value)
const newType = newQuestionObj.type as QuestionType
//questionFromRawText can only reasonably predict the type of question, it's choices, and it's text.
//We'll pick those three fields out and allow the user to decide the rest of the fields explicitly.
onChange({
...question,
type: newType,
title: newQuestionObj.title || '',
choices: newQuestionObj.choices
} as Question)
}}
label={'Freetext'}
labelClassname={'mb-0'}
infoContent={`Paste in question text to automatically generate a survey question. For text questions,
simply paste in the text. For radio and dropdown questions, paste the question text followed by
a new option on each line.`}
/>
}
34 changes: 25 additions & 9 deletions ui-admin/src/forms/designer/split/SplitFormElementDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { isEqual } from 'lodash'
import { FormElementEditor } from './FormElementEditor'
import { FormElementJsonEditor } from './FormElementJsonEditor'
import { FormElementOptions } from './controls/FormElementOptions'
import { FormElementFreetextEditor } from './FormElementFreetextEditor'

/* Note that this component is memoized using React.memo
* Since survey pages can contain many elements, we need to be mindful of
Expand All @@ -31,6 +32,7 @@ export const SplitFormElementDesigner = memo(({
editedContent: FormContent, onChange: (newContent: FormContent) => void
}) => {
const [showJsonEditor, setShowJsonEditor] = useState(false)
const [showFreetextMode, setShowFreetextMode] = useState(false)

// Chop the survey down to just the specific question that we're editing, so we can display
// a preview using the SurveyJS survey component.
Expand All @@ -51,13 +53,35 @@ export const SplitFormElementDesigner = memo(({
<FormElementOptions
showJsonEditor={showJsonEditor}
setShowJsonEditor={setShowJsonEditor}
showFreetextMode={showFreetextMode}
setShowFreetextMode={setShowFreetextMode}
elementIndex={elementIndex}
element={element}
currentPageNo={currentPageNo}
editedContent={editedContent}
onChange={onChange}
/>
{ !showJsonEditor ?
{ showFreetextMode &&
<FormElementFreetextEditor
question={element as Question}
onChange={newQuestion => {
const newContent = { ...editedContent }
newContent.pages[currentPageNo].elements[elementIndex] = newQuestion
onChange(newContent)
}}
/>
}
{ showJsonEditor &&
<FormElementJsonEditor
question={element as Question}
onChange={newQuestion => {
const newContent = { ...editedContent }
newContent.pages[currentPageNo].elements[elementIndex] = newQuestion
onChange(newContent)
}}
/>
}
{ !showJsonEditor && !showFreetextMode &&
<FormElementEditor
element={element}
elementIndex={elementIndex}
Expand All @@ -66,14 +90,6 @@ export const SplitFormElementDesigner = memo(({
onChange={onChange}
currentLanguage={currentLanguage}
supportedLanguages={supportedLanguages}
/> :
<FormElementJsonEditor
question={element as Question}
onChange={newQuestion => {
const newContent = { ...editedContent }
newContent.pages[currentPageNo].elements[elementIndex] = newQuestion
onChange(newContent)
}}
/>
}
</div>
Expand Down
19 changes: 17 additions & 2 deletions ui-admin/src/forms/designer/split/controls/FormElementOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react'
import { IconButton } from 'components/forms/Button'
import { faClone, faCode } from '@fortawesome/free-solid-svg-icons'
import { faClone, faCode, faKeyboard, faWandMagicSparkles } from '@fortawesome/free-solid-svg-icons'
import { ListElementController } from 'portal/siteContent/designer/components/ListElementController'
import { FormContent, FormElement } from '@juniper/ui-core'

type FormElementOptionsProps = {
showJsonEditor: boolean,
setShowJsonEditor: (show: boolean) => void,
showFreetextMode: boolean,
setShowFreetextMode: (show: boolean) => void,
elementIndex: number,
element: FormElement,
currentPageNo: number,
Expand All @@ -17,6 +19,8 @@ type FormElementOptionsProps = {
export const FormElementOptions = ({
showJsonEditor,
setShowJsonEditor,
showFreetextMode,
setShowFreetextMode,
elementIndex,
element,
currentPageNo,
Expand All @@ -27,9 +31,20 @@ export const FormElementOptions = ({
<div className="d-flex justify-content-end">
<div className="d-flex border rounded-3 rounded-top-0 border-top-0 bg-light">
<IconButton icon={faCode}
aria-label={showJsonEditor ? 'Switch to designer' : 'Switch to JSON editor'}
disabled={showFreetextMode}
aria-label={
showJsonEditor ?
'Switch to designer' :
showFreetextMode ? 'You must exit the freetext editor to switch to JSON editor' :
'Switch to JSON editor'
}
onClick={() => setShowJsonEditor(!showJsonEditor)}
/>
<IconButton icon={showFreetextMode ? faKeyboard : faWandMagicSparkles}
disabled={showJsonEditor}
aria-label={showFreetextMode ? 'Switch to designer' : 'Switch to freetext editor'}
onClick={() => setShowFreetextMode(!showFreetextMode)}
/>
<IconButton icon={faClone}
aria-label={'Clone'}
onClick={() => {
Expand Down

0 comments on commit ee2e4e1

Please sign in to comment.