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 { useUser } from '../hooks'
|
||||
import Authorize from './Authorize'
|
||||
import CreateForm from './CreateForm'
|
||||
import DoForm from './DoForm'
|
||||
import Login from './Login'
|
||||
import UserPage from './UserPage'
|
||||
@ -23,6 +24,7 @@ const App: React.FC = () => {
|
||||
<Route path="/authorize" component={Authorize} />
|
||||
<Route path="/user" component={UserPage} />
|
||||
<Route path="/form/:id" component={DoForm} />
|
||||
<Route path="/create" component={CreateForm} />
|
||||
</Switch>
|
||||
</Router>
|
||||
</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