Added form creation component and useFormCreator hook
This commit is contained in:
parent
4b84cb15e8
commit
95ec7daaef
@ -55,4 +55,12 @@ const FORMSUBMIT = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export { LOGIN, FORM, USER, FORMSUBMIT }
|
const CREATEFORM = gql`
|
||||||
|
mutation CreateForm($title: String!, $questions: String!) {
|
||||||
|
createForm(title: $title, questions: $questions) {
|
||||||
|
success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export { LOGIN, FORM, USER, FORMSUBMIT, CREATEFORM }
|
||||||
|
@ -6,6 +6,7 @@ import client from '../apollo'
|
|||||||
import Context from '../context'
|
import Context from '../context'
|
||||||
import { useUser } from '../hooks'
|
import { useUser } from '../hooks'
|
||||||
import Authorize from './Authorize'
|
import Authorize from './Authorize'
|
||||||
|
import CreateForm from './CreateForm'
|
||||||
import DoForm from './DoForm'
|
import DoForm from './DoForm'
|
||||||
import Login from './Login'
|
import Login from './Login'
|
||||||
import UserPage from './UserPage'
|
import UserPage from './UserPage'
|
||||||
@ -23,6 +24,7 @@ const App: React.FC = () => {
|
|||||||
<Route path="/authorize" component={Authorize} />
|
<Route path="/authorize" component={Authorize} />
|
||||||
<Route path="/user" component={UserPage} />
|
<Route path="/user" component={UserPage} />
|
||||||
<Route path="/form/:id" component={DoForm} />
|
<Route path="/form/:id" component={DoForm} />
|
||||||
|
<Route path="/create" component={CreateForm} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
</Router>
|
||||||
</Context.Provider>
|
</Context.Provider>
|
||||||
|
156
src/components/CreateForm/hooks.ts
Normal file
156
src/components/CreateForm/hooks.ts
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import { ApolloError, useMutation } from '@apollo/client'
|
||||||
|
import { ChangeEvent, FormEvent, useState } from 'react'
|
||||||
|
import { CREATEFORM } from '../../apollo'
|
||||||
|
import { MutationCreateFormArgs, ServerAnswer } from '../../apollo/typeDefs.gen'
|
||||||
|
|
||||||
|
type FormQuestion<T extends string> = {
|
||||||
|
title: string
|
||||||
|
type: T
|
||||||
|
variants: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Form<T extends string> = {
|
||||||
|
title: string
|
||||||
|
questions: FormQuestion<T>[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormatQuestionsToSubmitType = <T extends string>(
|
||||||
|
questions: FormQuestion<T>[]
|
||||||
|
) => string
|
||||||
|
|
||||||
|
interface ICreateFormMutation {
|
||||||
|
createForm: ServerAnswer
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormSubmitType = (e: FormEvent<HTMLFormElement>) => void
|
||||||
|
|
||||||
|
type HandleFormTitleChangeType = (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
|
||||||
|
type CreateQuestionType<T extends string> = (type: T) => void
|
||||||
|
|
||||||
|
type HandleQuestionTitleChangeType = (
|
||||||
|
questionNumber: number,
|
||||||
|
e: ChangeEvent<HTMLInputElement>
|
||||||
|
) => void
|
||||||
|
|
||||||
|
type AddVariantType = (questionNumber: number) => void
|
||||||
|
|
||||||
|
type HandleAnswerVariantChangeType = (
|
||||||
|
questionNumber: number,
|
||||||
|
variantNumber: number,
|
||||||
|
e: ChangeEvent<HTMLInputElement>
|
||||||
|
) => void
|
||||||
|
|
||||||
|
type UseFormCreatorHookTurple<T extends string> = [
|
||||||
|
Form<T>,
|
||||||
|
[
|
||||||
|
FormSubmitType,
|
||||||
|
{
|
||||||
|
submitData: ICreateFormMutation | null | undefined
|
||||||
|
submitError: ApolloError | undefined
|
||||||
|
submitLoading: boolean
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{
|
||||||
|
handleFormTitleChange: HandleFormTitleChangeType
|
||||||
|
addQuestion: CreateQuestionType<T>
|
||||||
|
handleQuestionTitleChange: HandleQuestionTitleChangeType
|
||||||
|
handleAnswerVariantChange: HandleAnswerVariantChangeType
|
||||||
|
addVariant: AddVariantType
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const useFormCreator = <T extends string>(
|
||||||
|
formatQuestionsToSubmit: FormatQuestionsToSubmitType
|
||||||
|
): UseFormCreatorHookTurple<T> => {
|
||||||
|
const [form, setState] = useState<Form<T>>({ title: '', questions: [] })
|
||||||
|
|
||||||
|
const [
|
||||||
|
doFormCreation,
|
||||||
|
{ error: submitError, data: submitData, loading: submitLoading },
|
||||||
|
] = useMutation<ICreateFormMutation, MutationCreateFormArgs>(CREATEFORM, {
|
||||||
|
variables: {
|
||||||
|
title: form.title,
|
||||||
|
questions: formatQuestionsToSubmit<T>(form.questions),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const formSubmit: FormSubmitType = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
console.log({
|
||||||
|
title: form.title,
|
||||||
|
questions: formatQuestionsToSubmit<T>(form.questions),
|
||||||
|
})
|
||||||
|
doFormCreation()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFormTitleChange: HandleFormTitleChangeType = (e) => {
|
||||||
|
const title = e.currentTarget.value
|
||||||
|
setState((prev) => ({ ...prev, title }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const createQuestion: CreateQuestionType<T> = (type) => {
|
||||||
|
setState(({ title, questions }) => ({
|
||||||
|
title,
|
||||||
|
questions: questions.concat({ title: '', type, variants: [] }),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQuestionTitleChange: HandleQuestionTitleChangeType = (
|
||||||
|
questionNumber,
|
||||||
|
e
|
||||||
|
) => {
|
||||||
|
const questionTitle = e.currentTarget.value
|
||||||
|
setState(({ title, questions }) => ({
|
||||||
|
title,
|
||||||
|
questions: questions.map((el, index) =>
|
||||||
|
index === questionNumber ? { ...el, title: questionTitle } : el
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAnswerVariantChange: HandleAnswerVariantChangeType = (
|
||||||
|
questionNumber,
|
||||||
|
variantNumber,
|
||||||
|
e
|
||||||
|
) => {
|
||||||
|
const variantText = e.currentTarget.value
|
||||||
|
setState(({ title, questions }) => ({
|
||||||
|
title,
|
||||||
|
questions: questions.map((question, questionIndex) =>
|
||||||
|
questionIndex === questionNumber
|
||||||
|
? {
|
||||||
|
...question,
|
||||||
|
variants: question.variants.map((variant, variantIndex) =>
|
||||||
|
variantIndex === variantNumber ? variantText : variant
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: question
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const addVariant: AddVariantType = (questionNumber) => {
|
||||||
|
console.log()
|
||||||
|
setState(({ title, questions }) => ({
|
||||||
|
title,
|
||||||
|
questions: questions.map((el, index) => ({
|
||||||
|
...el,
|
||||||
|
variants:
|
||||||
|
index === questionNumber ? el.variants.concat('') : el.variants,
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
form,
|
||||||
|
[formSubmit, { submitData, submitError, submitLoading }],
|
||||||
|
{
|
||||||
|
handleFormTitleChange,
|
||||||
|
addQuestion: createQuestion,
|
||||||
|
handleQuestionTitleChange,
|
||||||
|
handleAnswerVariantChange,
|
||||||
|
addVariant,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
129
src/components/CreateForm/index.tsx
Normal file
129
src/components/CreateForm/index.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { FormatQuestionsToSubmitType, useFormCreator } from './hooks'
|
||||||
|
|
||||||
|
const creationsArray = [
|
||||||
|
{ title: 'Check', type: 'CHECK', enabled: false },
|
||||||
|
{ title: 'Input', type: 'INPUT', enabled: true },
|
||||||
|
{ title: 'Choose', type: 'CHOOSE', enabled: true },
|
||||||
|
{ title: 'Select', type: 'SELECT', enabled: true },
|
||||||
|
] as const
|
||||||
|
|
||||||
|
type QuestionTypes = 'CHECK' | 'INPUT' | 'CHOOSE' | 'SELECT'
|
||||||
|
|
||||||
|
const formatQuestionsToSubmit: FormatQuestionsToSubmitType = (questions) => {
|
||||||
|
return JSON.stringify(
|
||||||
|
questions.map((question) =>
|
||||||
|
question.type === 'INPUT'
|
||||||
|
? { title: question.title }
|
||||||
|
: {
|
||||||
|
...question,
|
||||||
|
variants: question.variants.map((variant) => ({
|
||||||
|
text: variant,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateForm: React.FC = () => {
|
||||||
|
const [
|
||||||
|
form,
|
||||||
|
[formSubmit, { submitData, submitError, submitLoading }],
|
||||||
|
{
|
||||||
|
addQuestion,
|
||||||
|
handleFormTitleChange,
|
||||||
|
handleQuestionTitleChange,
|
||||||
|
handleAnswerVariantChange,
|
||||||
|
addVariant,
|
||||||
|
},
|
||||||
|
] = useFormCreator<QuestionTypes>(formatQuestionsToSubmit)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<form onSubmit={formSubmit}>
|
||||||
|
<label>
|
||||||
|
Title:
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="Title"
|
||||||
|
value={form.title}
|
||||||
|
onChange={handleFormTitleChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Content</legend>
|
||||||
|
<ul>
|
||||||
|
{creationsArray.flatMap((questionType, index) =>
|
||||||
|
questionType.enabled
|
||||||
|
? [
|
||||||
|
<li key={index}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => addQuestion(questionType.type)}
|
||||||
|
>
|
||||||
|
{questionType.title}
|
||||||
|
</button>
|
||||||
|
</li>,
|
||||||
|
]
|
||||||
|
: []
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
{form.questions.map((quesstion, questionIndex) => (
|
||||||
|
<li key={questionIndex}>
|
||||||
|
<p>{quesstion.type} question:</p>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="questionTitle"
|
||||||
|
placeholder="Title"
|
||||||
|
value={quesstion.title}
|
||||||
|
onChange={(e) => handleQuestionTitleChange(questionIndex, e)}
|
||||||
|
/>
|
||||||
|
{(quesstion.type === 'CHECK' ||
|
||||||
|
quesstion.type === 'CHOOSE' ||
|
||||||
|
quesstion.type === 'SELECT') && (
|
||||||
|
<>
|
||||||
|
<ul>
|
||||||
|
{quesstion.variants.map((variant, variantIndex) => (
|
||||||
|
<li key={variantIndex}>
|
||||||
|
<input
|
||||||
|
placeholder="Variant"
|
||||||
|
type="text"
|
||||||
|
value={variant}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleAnswerVariantChange(
|
||||||
|
questionIndex,
|
||||||
|
variantIndex,
|
||||||
|
e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => addVariant(questionIndex)}
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</fieldset>
|
||||||
|
{submitLoading ? 'Loading...' : <input type="submit" value="Submit" />}
|
||||||
|
</form>
|
||||||
|
{submitData &&
|
||||||
|
submitData.createForm &&
|
||||||
|
submitData.createForm.success &&
|
||||||
|
'Successfully uploaded'}
|
||||||
|
{submitError && submitError.message}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateForm
|
Loading…
x
Reference in New Issue
Block a user