mirror of
https://github.com/IT4Change/ohmyform-ui.git
synced 2025-12-13 01:35:51 +00:00
add license and more frontend field types
This commit is contained in:
parent
ec0f6e9572
commit
34d154b4dd
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
## License
|
||||
(The MIT License)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@ -1,4 +1,5 @@
|
||||
@import "variables";
|
||||
@import "node_modules/swiper/swiper.scss";
|
||||
|
||||
:root {
|
||||
--backgroundColor: #{$background-color};
|
||||
@ -26,3 +27,11 @@
|
||||
.ant-spin-nested-loading > div > .ant-spin {
|
||||
max-height: unset;
|
||||
}
|
||||
|
||||
.swiper-container {
|
||||
height: 100vh;
|
||||
|
||||
.swiper-wrapper {
|
||||
position: fixed
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ export const DesignTab: React.FC<TabPaneProps> = props => {
|
||||
{name: 'questionColor', label: 'Question Color'},
|
||||
{name: 'answerColor', label: 'Answer Color'},
|
||||
{name: 'buttonColor', label: 'Button Color'},
|
||||
{name: 'buttonActiveColor', label: 'Button Active Color'},
|
||||
{name: 'buttonTextColor', label: 'Button Text Color'},
|
||||
].map(({label, name}) => (
|
||||
<Form.Item key={name} label={label} name={['form', 'design', 'colors', name]}>
|
||||
|
||||
@ -55,7 +55,14 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
<DeleteOutlined key={'delete'} onClick={() => remove(index)} />
|
||||
]}
|
||||
>
|
||||
<Form.Item label={'Url'} name={[field.key, 'url']} labelCol={{ span: 6 }}>
|
||||
<Form.Item
|
||||
label={'Url'}
|
||||
name={[field.key, 'url']}
|
||||
rules={[
|
||||
{type: 'url', message: 'Must be a valid url'}
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Action'} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
@ -67,6 +74,9 @@ export const EndPageTab: React.FC<TabPaneProps> = props => {
|
||||
<Form.Item label={'Background Color'} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Active Color'} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Color'} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
|
||||
@ -4,31 +4,8 @@ import {FormInstance} from 'antd/lib/form'
|
||||
import {FieldData} from 'rc-field-form/lib/interface'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
import {DateType} from './types/date.type'
|
||||
import {DropdownType} from './types/dropdown.type'
|
||||
import {EmailType} from './types/email.type'
|
||||
import {HiddenType} from './types/hidden.type'
|
||||
import {LinkType} from './types/link.type'
|
||||
import {NumberType} from './types/number.type'
|
||||
import {RadioType} from './types/radio.type'
|
||||
import {RatingType} from './types/rating.type'
|
||||
import {adminTypes} from './types'
|
||||
import {TextType} from './types/text.type'
|
||||
import {TextareaType} from './types/textarea.type'
|
||||
import {YesNoType} from './types/yes_no.type'
|
||||
|
||||
export const availableTypes = {
|
||||
'textfield': TextType,
|
||||
'date': DateType,
|
||||
'email': EmailType,
|
||||
'textarea': TextareaType,
|
||||
'link': LinkType,
|
||||
'dropdown': DropdownType,
|
||||
'rating': RatingType,
|
||||
'radio': RadioType,
|
||||
'hidden': HiddenType,
|
||||
'yes_no': YesNoType,
|
||||
'number': NumberType,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
form: FormInstance
|
||||
@ -50,7 +27,7 @@ export const FieldCard: React.FC<Props> = props => {
|
||||
} = props
|
||||
|
||||
const type = form.getFieldValue(['form', 'fields', field.name as string, 'type'])
|
||||
const TypeComponent: React.FC<any> = availableTypes[type] || TextType
|
||||
const TypeComponent = adminTypes[type] || TextType
|
||||
|
||||
const [nextTitle, setNextTitle] = useState(form.getFieldValue(['form', 'fields', field.name as string, 'title']))
|
||||
|
||||
@ -120,6 +97,7 @@ export const FieldCard: React.FC<Props> = props => {
|
||||
name={[field.name as string, 'required']}
|
||||
labelCol={{ span: 6 }}
|
||||
valuePropName={'checked'}
|
||||
extra={type === 'hidden' && 'If required, default value must be set to enable users to submit form!'}
|
||||
>
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
|
||||
@ -4,7 +4,8 @@ import {FormInstance} from 'antd/lib/form'
|
||||
import {TabPaneProps} from 'antd/lib/tabs'
|
||||
import React, {useCallback, useState} from 'react'
|
||||
import {AdminFormFieldFragment} from '../../../graphql/fragment/admin.form.fragment'
|
||||
import {availableTypes, FieldCard} from './field.card'
|
||||
import {FieldCard} from './field.card'
|
||||
import {adminTypes} from './types'
|
||||
|
||||
interface Props extends TabPaneProps {
|
||||
form: FormInstance
|
||||
@ -40,7 +41,7 @@ export const FieldsTab: React.FC<Props> = props => {
|
||||
}}
|
||||
>
|
||||
<Select value={nextType} onChange={e => setNextType(e)} style={{ minWidth: 200 }}>
|
||||
{Object.keys(availableTypes).map(type => <Select.Option value={type} key={type}>{type}</Select.Option> )}
|
||||
{Object.keys(adminTypes).map(type => <Select.Option value={type} key={type}>{type}</Select.Option> )}
|
||||
</Select>
|
||||
<Button
|
||||
type="dashed"
|
||||
|
||||
@ -55,7 +55,14 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
<DeleteOutlined key={'delete'} onClick={() => remove(index)} />
|
||||
]}
|
||||
>
|
||||
<Form.Item label={'Url'} name={[field.key, 'url']} labelCol={{ span: 6 }}>
|
||||
<Form.Item
|
||||
label={'Url'}
|
||||
name={[field.key, 'url']}
|
||||
rules={[
|
||||
{type: 'url', message: 'Must be a valid url'}
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Action'} name={[field.key, 'action']} labelCol={{ span: 6 }}>
|
||||
@ -67,6 +74,9 @@ export const StartPageTab: React.FC<TabPaneProps> = props => {
|
||||
<Form.Item label={'Background Color'} name={[field.key, 'bgColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Active Color'} name={[field.key, 'activeColor']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
<Form.Item label={'Color'} name={[field.key, 'color']} labelCol={{ span: 6 }}>
|
||||
<InputColor />
|
||||
</Form.Item>
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import {DatePicker, Form} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const DateType: React.FC<Props> = props => {
|
||||
export const DateType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
@ -13,21 +10,21 @@ export const DateType: React.FC<Props> = props => {
|
||||
name={[props.field.name, 'value']}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input type={'date'} />
|
||||
<DatePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'Min Date'}
|
||||
name={[props.field.name, 'value']}
|
||||
name={[props.field.name, 'min']}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
<DatePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'Max Date'}
|
||||
name={[props.field.name, 'value']}
|
||||
name={[props.field.name, 'max']}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
<DatePicker />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const DropdownType: React.FC<Props> = props => {
|
||||
export const DropdownType: React.FC<AdminFieldTypeProps> = props => {
|
||||
// TODO add dropdown options
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const EmailType: React.FC<Props> = props => {
|
||||
export const EmailType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const HiddenType: React.FC<Props> = props => {
|
||||
export const HiddenType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
29
components/form/admin/types/index.ts
Normal file
29
components/form/admin/types/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import {DateType} from './date.type'
|
||||
import {DropdownType} from './dropdown.type'
|
||||
import {EmailType} from './email.type'
|
||||
import {HiddenType} from './hidden.type'
|
||||
import {LinkType} from './link.type'
|
||||
import {NumberType} from './number.type'
|
||||
import {RadioType} from './radio.type'
|
||||
import {RatingType} from './rating.type'
|
||||
import {TextType} from './text.type'
|
||||
import {TextareaType} from './textarea.type'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
import {YesNoType} from './yes_no.type'
|
||||
|
||||
export const adminTypes: {
|
||||
[key: string]: React.FC<AdminFieldTypeProps>
|
||||
} = {
|
||||
'textfield': TextType,
|
||||
'date': DateType,
|
||||
'email': EmailType,
|
||||
'textarea': TextareaType,
|
||||
'link': LinkType,
|
||||
'dropdown': DropdownType,
|
||||
'rating': RatingType,
|
||||
'radio': RadioType,
|
||||
'hidden': HiddenType,
|
||||
'yes_no': YesNoType,
|
||||
'number': NumberType,
|
||||
}
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const LinkType: React.FC<Props> = props => {
|
||||
export const LinkType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, InputNumber} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const NumberType: React.FC<Props> = props => {
|
||||
export const NumberType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const RadioType: React.FC<Props> = props => {
|
||||
export const RadioType: React.FC<AdminFieldTypeProps> = props => {
|
||||
// TODO Add radio support
|
||||
|
||||
return (
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const RatingType: React.FC<Props> = props => {
|
||||
export const RatingType: React.FC<AdminFieldTypeProps> = props => {
|
||||
// TODO add ratings
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const TextType: React.FC<Props> = props => {
|
||||
export const TextType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const TextareaType: React.FC<Props> = props => {
|
||||
export const TextareaType: React.FC<AdminFieldTypeProps> = props => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
|
||||
3
components/form/admin/types/type.props.ts
Normal file
3
components/form/admin/types/type.props.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface AdminFieldTypeProps {
|
||||
field: any
|
||||
}
|
||||
@ -1,11 +1,8 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {AdminFieldTypeProps} from './type.props'
|
||||
|
||||
interface Props {
|
||||
field: any
|
||||
}
|
||||
|
||||
export const YesNoType: React.FC<Props> = props => {
|
||||
export const YesNoType: React.FC<AdminFieldTypeProps> = props => {
|
||||
// TODO add switch
|
||||
return (
|
||||
<div>
|
||||
|
||||
88
components/form/field.tsx
Normal file
88
components/form/field.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import {Form, message} from 'antd'
|
||||
import {useForm} from 'antd/lib/form/Form'
|
||||
import React from 'react'
|
||||
import {FormDesignFragment, FormFieldFragment} from '../../graphql/fragment/form.fragment'
|
||||
import {StyledButton} from '../styled/button'
|
||||
import {StyledH1} from '../styled/h1'
|
||||
import {StyledP} from '../styled/p'
|
||||
import {fieldTypes} from './types'
|
||||
import {TextType} from './types/text.type'
|
||||
import {FieldTypeProps} from './types/type.props'
|
||||
|
||||
interface Props {
|
||||
field: FormFieldFragment
|
||||
design: FormDesignFragment
|
||||
|
||||
next: () => any
|
||||
prev: () => any
|
||||
}
|
||||
|
||||
export const Field: React.FC<Props> = ({field, design, children, next, prev, ...props}) => {
|
||||
const [form] = useForm()
|
||||
|
||||
const FieldInput: React.FC<FieldTypeProps> = fieldTypes[field.type] || TextType
|
||||
|
||||
const finish = (data) => {
|
||||
console.log('received field data', data)
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
const error = () => {
|
||||
message.error('Check inputs!')
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={finish}
|
||||
onFinishFailed={error}
|
||||
{...props}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<div style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: 32,
|
||||
justifyContent: 'flex-end',
|
||||
}}>
|
||||
<pre style={{
|
||||
opacity: 0.3
|
||||
}}>{JSON.stringify(field, null, 2)}</pre>
|
||||
|
||||
<StyledH1 design={design} type={'question'}>{field.title}</StyledH1>
|
||||
{field.description && <StyledP design={design} type={'question'}>{field.description}</StyledP>}
|
||||
|
||||
<FieldInput
|
||||
design={design}
|
||||
field={field}
|
||||
/>
|
||||
</div>
|
||||
<div style={{
|
||||
padding: 32,
|
||||
display: 'flex',
|
||||
}}>
|
||||
<StyledButton
|
||||
background={design.colors.buttonColor}
|
||||
color={design.colors.buttonTextColor}
|
||||
highlight={design.colors.buttonActiveColor}
|
||||
onClick={prev}
|
||||
>{'Previous'}</StyledButton>
|
||||
|
||||
<div style={{flex: 1}} />
|
||||
|
||||
<StyledButton
|
||||
background={design.colors.buttonColor}
|
||||
color={design.colors.buttonTextColor}
|
||||
highlight={design.colors.buttonActiveColor}
|
||||
size={'large'}
|
||||
onClick={form.submit}
|
||||
>{'Next'}</StyledButton>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
70
components/form/page.tsx
Normal file
70
components/form/page.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import {Space} from 'antd'
|
||||
import React from 'react'
|
||||
import {FormDesignFragment, FormPageFragment} from '../../graphql/fragment/form.fragment'
|
||||
import {StyledButton} from '../styled/button'
|
||||
import {StyledH1} from '../styled/h1'
|
||||
import {StyledP} from '../styled/p'
|
||||
|
||||
interface Props {
|
||||
type: 'start' | 'end'
|
||||
page: FormPageFragment
|
||||
design: FormDesignFragment
|
||||
|
||||
next: () => any
|
||||
prev: () => any
|
||||
}
|
||||
|
||||
export const FormPage: React.FC<Props> = ({page, design, next, prev, type, children, ...props}) => {
|
||||
if (!page.show) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}} {...props}>
|
||||
<div style={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
}}>
|
||||
<StyledH1 design={design} type={'question'}>{page.title}</StyledH1>
|
||||
<StyledP design={design} type={'question'}>{page.paragraph}</StyledP>
|
||||
</div>
|
||||
<div style={{
|
||||
padding: 32,
|
||||
display: 'flex',
|
||||
}}>
|
||||
{page.buttons.length > 0 && (
|
||||
<Space>
|
||||
{page.buttons.map((button, key) => {
|
||||
return (
|
||||
<StyledButton
|
||||
background={button.bgColor}
|
||||
color={button.color}
|
||||
highlight={button.activeColor}
|
||||
key={key}
|
||||
href={button.url}
|
||||
target={'_blank'}
|
||||
>{button.text}</StyledButton>
|
||||
)
|
||||
})}
|
||||
</Space>
|
||||
)}
|
||||
|
||||
<div style={{flex: 1}} />
|
||||
|
||||
<StyledButton
|
||||
background={design.colors.buttonColor}
|
||||
color={design.colors.buttonTextColor}
|
||||
highlight={design.colors.buttonActiveColor}
|
||||
size={'large'}
|
||||
onClick={next}
|
||||
>{page.buttonText || 'Continue'}</StyledButton>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
22
components/form/types/date.type.tsx
Normal file
22
components/form/types/date.type.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import {DatePicker, Form} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const DateType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
// TODO check min and max
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Date'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<DatePicker autoFocus />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
components/form/types/dropdown.type.tsx
Normal file
21
components/form/types/dropdown.type.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const DropdownType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
// TODO add dropdown options
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
components/form/types/email.type.tsx
Normal file
21
components/form/types/email.type.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const EmailType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Email'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
{ type: 'email', message: 'Must be a valid email' }
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input type={'email'} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
20
components/form/types/hidden.type.tsx
Normal file
20
components/form/types/hidden.type.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const HiddenType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
29
components/form/types/index.ts
Normal file
29
components/form/types/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import {DateType} from './date.type'
|
||||
import {DropdownType} from './dropdown.type'
|
||||
import {EmailType} from './email.type'
|
||||
import {HiddenType} from './hidden.type'
|
||||
import {LinkType} from './link.type'
|
||||
import {NumberType} from './number.type'
|
||||
import {RadioType} from './radio.type'
|
||||
import {RatingType} from './rating.type'
|
||||
import {TextType} from './text.type'
|
||||
import {TextareaType} from './textarea.type'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
import {YesNoType} from './yes_no.type'
|
||||
|
||||
export const fieldTypes: {
|
||||
[key: string]: React.FC<FieldTypeProps>
|
||||
} = {
|
||||
'textfield': TextType,
|
||||
'date': DateType,
|
||||
'email': EmailType,
|
||||
'textarea': TextareaType,
|
||||
'link': LinkType,
|
||||
'dropdown': DropdownType,
|
||||
'rating': RatingType,
|
||||
'radio': RadioType,
|
||||
'hidden': HiddenType,
|
||||
'yes_no': YesNoType,
|
||||
'number': NumberType,
|
||||
}
|
||||
21
components/form/types/link.type.tsx
Normal file
21
components/form/types/link.type.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const LinkType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Link'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
{ type: 'url', message: 'Must be a valid URL' }
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input type={'url'} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
components/form/types/number.type.tsx
Normal file
21
components/form/types/number.type.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {Form, InputNumber} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const NumberType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Number'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ type: 'number', message: 'Must be a valid URL' },
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
22
components/form/types/radio.type.tsx
Normal file
22
components/form/types/radio.type.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const RadioType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
// TODO Add radio support
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
22
components/form/types/rating.type.tsx
Normal file
22
components/form/types/rating.type.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const RatingType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
// TODO add ratings
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
28
components/form/types/text.type.tsx
Normal file
28
components/form/types/text.type.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import {Form} from 'antd'
|
||||
import React from 'react'
|
||||
import {StyledInput} from '../../styled/input'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const TextType: React.FC<FieldTypeProps> = ({field, design}) => {
|
||||
// TODO focus when becomes visible
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' }
|
||||
]}
|
||||
>
|
||||
<StyledInput
|
||||
design={design}
|
||||
allowClear
|
||||
size={'large'}
|
||||
defaultValue={field.value}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
20
components/form/types/textarea.type.tsx
Normal file
20
components/form/types/textarea.type.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const TextareaType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
6
components/form/types/type.props.ts
Normal file
6
components/form/types/type.props.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {FormDesignFragment, FormFieldFragment} from '../../../graphql/fragment/form.fragment'
|
||||
|
||||
export interface FieldTypeProps {
|
||||
field: FormFieldFragment
|
||||
design: FormDesignFragment
|
||||
}
|
||||
21
components/form/types/yes_no.type.tsx
Normal file
21
components/form/types/yes_no.type.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {Form, Input} from 'antd'
|
||||
import React from 'react'
|
||||
import {FieldTypeProps} from './type.props'
|
||||
|
||||
export const YesNoType: React.FC<FieldTypeProps> = ({field}) => {
|
||||
// TODO add switch
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={'Default Value'}
|
||||
name={[field.id, 'value']}
|
||||
rules={[
|
||||
{ required: field.required, message: 'Please provide Information' },
|
||||
]}
|
||||
labelCol={{ span: 6 }}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
29
components/styled/button.tsx
Normal file
29
components/styled/button.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import {Button} from 'antd'
|
||||
import {ButtonProps} from 'antd/lib/button/button'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {darken, lighten} from './color.change'
|
||||
|
||||
interface Props extends ButtonProps {
|
||||
background: any
|
||||
highlight: any
|
||||
color: any
|
||||
}
|
||||
|
||||
export const StyledButton: React.FC<Props> = ({background, highlight, color, children, ...props}) => {
|
||||
const StyledButton = styled(Button)`
|
||||
background: ${background};
|
||||
color: ${color};
|
||||
border-color: ${darken(background, 10)};
|
||||
|
||||
:hover {
|
||||
color: ${highlight};
|
||||
background-color: ${lighten(background, 10)};
|
||||
border-color: ${darken(highlight, 10)};
|
||||
}
|
||||
`
|
||||
|
||||
return (
|
||||
<StyledButton {...props}>{children}</StyledButton>
|
||||
)
|
||||
}
|
||||
35
components/styled/color.change.ts
Normal file
35
components/styled/color.change.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @link https://css-tricks.com/snippets/javascript/lighten-darken-color/
|
||||
*
|
||||
* @author Chris Coyier
|
||||
*/
|
||||
function LightenDarkenColor(col, amt) {
|
||||
let usePound = false;
|
||||
|
||||
if (col[0] == "#") {
|
||||
col = col.slice(1);
|
||||
usePound = true;
|
||||
}
|
||||
|
||||
const num = parseInt(col, 16)
|
||||
|
||||
let r = (num >> 16) + amt;
|
||||
|
||||
if (r > 255) r = 255;
|
||||
else if (r < 0) r = 0;
|
||||
|
||||
let b = ((num >> 8) & 0x00FF) + amt;
|
||||
|
||||
if (b > 255) b = 255;
|
||||
else if (b < 0) b = 0;
|
||||
|
||||
let g = (num & 0x0000FF) + amt;
|
||||
|
||||
if (g > 255) g = 255;
|
||||
else if (g < 0) g = 0;
|
||||
|
||||
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
|
||||
}
|
||||
|
||||
export const lighten = (color: string, amount: number) => LightenDarkenColor(color, amount)
|
||||
export const darken = (color: string, amount: number) => LightenDarkenColor(color, -amount)
|
||||
18
components/styled/h1.tsx
Normal file
18
components/styled/h1.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {FormDesignFragment} from '../../graphql/fragment/form.fragment'
|
||||
|
||||
interface Props {
|
||||
type: 'question' | 'answer'
|
||||
design: FormDesignFragment
|
||||
}
|
||||
|
||||
export const StyledH1: React.FC<Props> = ({design, type, children, ...props}) => {
|
||||
const Header = styled.h1`
|
||||
color: ${type === 'question' ? design.colors.questionColor : design.colors.answerColor}
|
||||
`
|
||||
|
||||
return (
|
||||
<Header {...props}>{children}</Header>
|
||||
)
|
||||
}
|
||||
18
components/styled/h2.tsx
Normal file
18
components/styled/h2.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {FormDesignFragment} from '../../graphql/fragment/form.fragment'
|
||||
|
||||
interface Props {
|
||||
type: 'question' | 'answer'
|
||||
design: FormDesignFragment
|
||||
}
|
||||
|
||||
export const StyledH2: React.FC<Props> = ({design, type, children, ...props}) => {
|
||||
const Header = styled.h2`
|
||||
color: ${type === 'question' ? design.colors.questionColor : design.colors.answerColor}
|
||||
`
|
||||
|
||||
return (
|
||||
<Header {...props}>{children}</Header>
|
||||
)
|
||||
}
|
||||
57
components/styled/input.tsx
Normal file
57
components/styled/input.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import {Input} from 'antd'
|
||||
import {InputProps} from 'antd/lib/input/Input'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {FormDesignFragment} from '../../graphql/fragment/form.fragment'
|
||||
|
||||
interface Props extends InputProps{
|
||||
design: FormDesignFragment
|
||||
}
|
||||
|
||||
export const StyledInput: React.FC<Props> = ({design, children, ...props}) => {
|
||||
const [Field, setField] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
setField(
|
||||
styled(Input)`
|
||||
color: ${design.colors.answerColor};
|
||||
border-color: ${design.colors.answerColor};
|
||||
background: none !important;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-radius: 0;
|
||||
|
||||
:focus {
|
||||
outline: ${design.colors.answerColor} auto 5px
|
||||
}
|
||||
|
||||
:hover,
|
||||
:active {
|
||||
border-color: ${design.colors.answerColor};
|
||||
}
|
||||
|
||||
&.ant-input-affix-wrapper {
|
||||
box-shadow: none
|
||||
}
|
||||
|
||||
input {
|
||||
background: none !important;
|
||||
color: ${design.colors.answerColor};
|
||||
}
|
||||
|
||||
.anticon {
|
||||
color: ${design.colors.answerColor};
|
||||
}
|
||||
`
|
||||
)
|
||||
}, [design])
|
||||
|
||||
if (!Field) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Field {...props}>{children}</Field>
|
||||
)
|
||||
}
|
||||
18
components/styled/p.tsx
Normal file
18
components/styled/p.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {FormDesignFragment} from '../../graphql/fragment/form.fragment'
|
||||
|
||||
interface Props {
|
||||
type: 'question' | 'answer'
|
||||
design: FormDesignFragment
|
||||
}
|
||||
|
||||
export const StyledP: React.FC<Props> = ({design, type, children, ...props}) => {
|
||||
const Paragraph = styled.p`
|
||||
color: ${type === 'question' ? design.colors.questionColor : design.colors.answerColor}
|
||||
`
|
||||
|
||||
return (
|
||||
<Paragraph {...props}>{children}</Paragraph>
|
||||
)
|
||||
}
|
||||
0
graphql/fragment/admin.user.fragment.ts
Normal file
0
graphql/fragment/admin.user.fragment.ts
Normal file
109
graphql/fragment/form.fragment.ts
Normal file
109
graphql/fragment/form.fragment.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import {gql} from 'apollo-boost'
|
||||
|
||||
export interface FormPageFragment {
|
||||
show: boolean
|
||||
title?: string
|
||||
paragraph?: string
|
||||
buttonText?: string
|
||||
buttons: {
|
||||
url?: string
|
||||
action?: string
|
||||
text?: string
|
||||
bgColor?: string
|
||||
activeColor?: string
|
||||
color?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface FormFieldFragment {
|
||||
id: string
|
||||
title: string
|
||||
type: string
|
||||
description: string
|
||||
required: boolean
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface FormDesignFragment {
|
||||
colors: {
|
||||
backgroundColor: string
|
||||
questionColor: string
|
||||
answerColor: string
|
||||
buttonColor: string
|
||||
buttonActiveColor: string
|
||||
buttonTextColor: string
|
||||
}
|
||||
font?: string
|
||||
}
|
||||
|
||||
export interface FormFragment {
|
||||
id?: string
|
||||
title: string
|
||||
created: string
|
||||
language: string
|
||||
showFooter: boolean
|
||||
fields: FormFieldFragment[]
|
||||
design: FormDesignFragment
|
||||
startPage: FormPageFragment
|
||||
endPage: FormPageFragment
|
||||
}
|
||||
|
||||
export const FORM_FRAGMENT = gql`
|
||||
fragment Form on Form {
|
||||
id
|
||||
title
|
||||
language
|
||||
showFooter
|
||||
|
||||
fields {
|
||||
id
|
||||
title
|
||||
type
|
||||
description
|
||||
required
|
||||
value
|
||||
}
|
||||
|
||||
design {
|
||||
colors {
|
||||
backgroundColor
|
||||
questionColor
|
||||
answerColor
|
||||
buttonColor
|
||||
buttonActiveColor
|
||||
buttonTextColor
|
||||
}
|
||||
font
|
||||
}
|
||||
|
||||
startPage {
|
||||
show
|
||||
title
|
||||
paragraph
|
||||
buttonText
|
||||
buttons {
|
||||
url
|
||||
action
|
||||
text
|
||||
bgColor
|
||||
activeColor
|
||||
color
|
||||
}
|
||||
}
|
||||
|
||||
endPage {
|
||||
show
|
||||
title
|
||||
paragraph
|
||||
buttonText
|
||||
buttons {
|
||||
url
|
||||
action
|
||||
text
|
||||
bgColor
|
||||
activeColor
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
20
graphql/query/form.query.ts
Normal file
20
graphql/query/form.query.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {gql} from 'apollo-boost'
|
||||
import {FORM_FRAGMENT, FormFragment} from '../fragment/form.fragment'
|
||||
|
||||
export interface FormQueryData {
|
||||
form: FormFragment
|
||||
}
|
||||
|
||||
export interface FormQueryVariables {
|
||||
id: string
|
||||
}
|
||||
|
||||
export const FORM_QUERY = gql`
|
||||
query form($id: ID!){
|
||||
form:getFormById(id: $id) {
|
||||
...Form
|
||||
}
|
||||
}
|
||||
|
||||
${FORM_FRAGMENT}
|
||||
`
|
||||
@ -13,6 +13,7 @@
|
||||
"@ant-design/icons": "^4.1.0",
|
||||
"@apollo/react-hooks": "^3.1.5",
|
||||
"@lifeomic/axios-fetch": "^1.4.2",
|
||||
"@types/swiper": "^5.3.1",
|
||||
"antd": "^4.2.2",
|
||||
"apollo-boost": "^0.4.9",
|
||||
"axios": "^0.19.2",
|
||||
@ -27,11 +28,14 @@
|
||||
"react-color": "^2.18.1",
|
||||
"react-dom": "16.13.1",
|
||||
"react-icons": "^3.10.0",
|
||||
"react-id-swiper": "^3.0.0",
|
||||
"react-redux": "^7.2.0",
|
||||
"redux": "^4.0.5",
|
||||
"redux-devtools-extension": "^2.13.8",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"sass": "^1.26.5"
|
||||
"sass": "^1.26.5",
|
||||
"styled-components": "^5.1.1",
|
||||
"swiper": "^5.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.1",
|
||||
|
||||
@ -6,7 +6,7 @@ import {NextPage} from 'next'
|
||||
import Link from 'next/link'
|
||||
import React, {useState} from 'react'
|
||||
import {DateTime} from '../../../components/date.time'
|
||||
import {FormIsLive} from '../../../components/form/is.live'
|
||||
import {FormIsLive} from '../../../components/form/admin/is.live'
|
||||
import Structure from '../../../components/structure'
|
||||
import {TimeAgo} from '../../../components/time.ago'
|
||||
import {withAuth} from '../../../components/with.auth'
|
||||
|
||||
3
pages/form/[id]/index.module.scss
Normal file
3
pages/form/[id]/index.module.scss
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
.page {
|
||||
}
|
||||
@ -1,11 +1,102 @@
|
||||
import {useQuery} from '@apollo/react-hooks'
|
||||
import {NextPage} from 'next'
|
||||
import React from 'react'
|
||||
import React, {useState} from 'react'
|
||||
import Swiper from 'react-id-swiper'
|
||||
import {ReactIdSwiperProps} from 'react-id-swiper/lib/types'
|
||||
import * as OriginalSwiper from 'swiper'
|
||||
import {ErrorPage} from '../../../components/error.page'
|
||||
import {Field} from '../../../components/form/field'
|
||||
import {FormPage} from '../../../components/form/page'
|
||||
import {LoadingPage} from '../../../components/loading.page'
|
||||
import {useWindowSize} from '../../../components/use.window.size'
|
||||
import {FORM_QUERY, FormQueryData, FormQueryVariables} from '../../../graphql/query/form.query'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
}
|
||||
|
||||
const Index: NextPage<Props> = ({id}) => {
|
||||
const windowSize = useWindowSize()
|
||||
const [swiper, setSwiper] = useState<OriginalSwiper.default>(null)
|
||||
|
||||
const {loading, data, error} = useQuery<FormQueryData, FormQueryVariables>(FORM_QUERY, {
|
||||
variables: {
|
||||
id,
|
||||
}
|
||||
})
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<LoadingPage message={'Building Form'} />
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorPage/>
|
||||
)
|
||||
}
|
||||
|
||||
const design = data.form.design
|
||||
|
||||
const goNext = () => {
|
||||
if (!swiper) return
|
||||
|
||||
swiper.allowSlideNext = true
|
||||
swiper.slideNext()
|
||||
swiper.allowSlideNext = false
|
||||
}
|
||||
const goPrev = () => swiper && swiper.slidePrev()
|
||||
|
||||
const swiperConfig: ReactIdSwiperProps = {
|
||||
getSwiper: setSwiper,
|
||||
direction: 'vertical',
|
||||
allowSlideNext: false,
|
||||
allowSlidePrev: true,
|
||||
updateOnWindowResize: true,
|
||||
}
|
||||
|
||||
const Index: NextPage = () => {
|
||||
return (
|
||||
<ErrorPage />
|
||||
<div style={{
|
||||
background: design.colors.backgroundColor,
|
||||
}}>
|
||||
<Swiper {...swiperConfig}>
|
||||
{[
|
||||
<FormPage
|
||||
key={'start'}
|
||||
type={'start'}
|
||||
page={data.form.startPage}
|
||||
design={design}
|
||||
next={goNext}
|
||||
prev={goPrev}
|
||||
/>,
|
||||
...data.form.fields.map(field => (
|
||||
<Field
|
||||
key={field.id}
|
||||
field={field}
|
||||
design={design}
|
||||
next={goNext}
|
||||
prev={goPrev}
|
||||
/>
|
||||
)),
|
||||
<FormPage
|
||||
key={'end'}
|
||||
type={'end'}
|
||||
page={data.form.endPage}
|
||||
design={design}
|
||||
next={goNext}
|
||||
prev={goPrev}
|
||||
/>
|
||||
]}
|
||||
</Swiper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Index.getInitialProps = async ({query}) => {
|
||||
return {
|
||||
id: query.id as string
|
||||
}
|
||||
}
|
||||
|
||||
export default Index
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user