add logic for field types

This commit is contained in:
Michael Schramm 2020-05-30 12:59:31 +02:00
parent 34d154b4dd
commit 37f9d0b62d
22 changed files with 307 additions and 73 deletions

View File

@ -1,21 +1,26 @@
import {DatePicker, Form} from 'antd'
import {Form} from 'antd'
import moment from 'moment'
import React from 'react'
import {StyledDateInput} from '../../styled/date.input'
import {FieldTypeProps} from './type.props'
export const DateType: React.FC<FieldTypeProps> = ({field}) => {
export const DateType: React.FC<FieldTypeProps> = ({field, design}) => {
// 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 />
<StyledDateInput
size={'large'}
defaultValue={field.value ? moment(field.value) : undefined}
design={design}
autoFocus
/>
</Form.Item>
</div>
)

View File

@ -1,20 +1,24 @@
import {Form, Input} from 'antd'
import {Form} from 'antd'
import React from 'react'
import {StyledInput} from '../../styled/input'
import {FieldTypeProps} from './type.props'
export const EmailType: React.FC<FieldTypeProps> = ({field}) => {
export const EmailType: React.FC<FieldTypeProps> = ({field, design}) => {
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'} />
<StyledInput
design={design}
allowClear
size={'large'}
defaultValue={field.value}
/>
</Form.Item>
</div>
)

View File

@ -1,20 +1,24 @@
import {Form, Input} from 'antd'
import {Form} from 'antd'
import React from 'react'
import {StyledInput} from '../../styled/input'
import {FieldTypeProps} from './type.props'
export const LinkType: React.FC<FieldTypeProps> = ({field}) => {
export const LinkType: React.FC<FieldTypeProps> = ({field, design}) => {
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'} />
<StyledInput
design={design}
allowClear
size={'large'}
defaultValue={field.value}
/>
</Form.Item>
</div>
)

View File

@ -31,5 +31,30 @@ function LightenDarkenColor(col, amt) {
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}
export const transparentize = (col: string, amt: number) => {
if (col[0] == "#") {
col = col.slice(1);
}
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 `rgba(${r}, ${b}, ${g}, ${1 - amt / 100})`
}
export const lighten = (color: string, amount: number) => LightenDarkenColor(color, amount)
export const darken = (color: string, amount: number) => LightenDarkenColor(color, -amount)

View File

@ -0,0 +1,61 @@
import {DatePicker} from 'antd'
import {PickerProps} from 'antd/lib/date-picker/generatePicker'
import {Moment} from 'moment'
import React, {useEffect, useState} from 'react'
import styled from 'styled-components'
import {FormDesignFragment} from '../../graphql/fragment/form.fragment'
import {transparentize} from './color.change'
type Props = { design: FormDesignFragment } & PickerProps<Moment>
export const StyledDateInput: React.FC<Props> = ({design, children, ...props}) => {
const [Field, setField] = useState()
useEffect(() => {
setField(
styled(DatePicker)`
color: ${design.colors.answerColor};
border-color: ${design.colors.answerColor};
background: none !important;
border-right: none;
border-top: none;
border-left: none;
border-radius: 0;
width: 100%;
:hover,
:active {
border-color: ${design.colors.answerColor};
}
&.ant-picker {
box-shadow: none
}
.ant-picker-clear {
background: none;
}
input {
color: ${design.colors.answerColor};
::placeholder {
color: ${transparentize(design.colors.answerColor, 60)}
}
}
.anticon {
color: ${design.colors.answerColor};
}
`
)
}, [design])
if (!Field) {
return null
}
return (
<Field {...props}>{children}</Field>
)
}

View File

@ -3,6 +3,7 @@ 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'
import {transparentize} from './color.change'
interface Props extends InputProps{
design: FormDesignFragment
@ -38,6 +39,10 @@ export const StyledInput: React.FC<Props> = ({design, children, ...props}) => {
input {
background: none !important;
color: ${design.colors.answerColor};
::placeholder {
color: ${transparentize(design.colors.answerColor, 60)}
}
}
.anticon {

View File

@ -104,6 +104,7 @@ export const ADMIN_FORM_FRAGMENT = gql`
questionColor
answerColor
buttonColor
buttonActiveColor
buttonTextColor
}
font
@ -118,6 +119,7 @@ export const ADMIN_FORM_FRAGMENT = gql`
action
text
bgColor
activeColor
color
}
}
@ -131,6 +133,7 @@ export const ADMIN_FORM_FRAGMENT = gql`
action
text
bgColor
activeColor
color
}
}

View File

@ -10,7 +10,7 @@ export interface AdminFormCreateMutationVariables {
}
export const ADMIN_FORM_CREATE_MUTATION = gql`
mutation update($$form: FormCreateInput!) {
mutation update($form: FormCreateInput!) {
form: createForm(form: $form) {
...AdminForm
}

View File

@ -5,12 +5,12 @@ import ApolloClient from 'apollo-boost'
import 'assets/global.scss'
import 'assets/variables.scss'
import axios from 'axios'
import {authConfig} from 'components/with.auth'
import {AppProps} from 'next/app'
import getConfig from 'next/config'
import Head from 'next/head'
import React from 'react'
import {wrapper} from 'store'
import {authConfig} from '../components/with.auth'
const { publicRuntimeConfig } = getConfig()

View File

@ -1,26 +1,26 @@
import {useMutation, useQuery} from '@apollo/react-hooks'
import {Button, Form, Input, message, Tabs} from 'antd'
import {useForm} from 'antd/lib/form/Form'
import {NextPage} from 'next'
import {useRouter} from 'next/router'
import React, {useState} from 'react'
import {cleanInput} from '../../../../components/clean.input'
import {BaseDataTab} from '../../../../components/form/admin/base.data.tab'
import {DesignTab} from '../../../../components/form/admin/design.tab'
import {EndPageTab} from '../../../../components/form/admin/end.page.tab'
import {FieldsTab} from '../../../../components/form/admin/fields.tab'
import {RespondentNotificationsTab} from '../../../../components/form/admin/respondent.notifications.tab'
import {SelfNotificationsTab} from '../../../../components/form/admin/self.notifications.tab'
import {StartPageTab} from '../../../../components/form/admin/start.page.tab'
import Structure from '../../../../components/structure'
import {withAuth} from '../../../../components/with.auth'
import {AdminFormFieldFragment} from '../../../../graphql/fragment/admin.form.fragment'
import {cleanInput} from 'components/clean.input'
import {BaseDataTab} from 'components/form/admin/base.data.tab'
import {DesignTab} from 'components/form/admin/design.tab'
import {EndPageTab} from 'components/form/admin/end.page.tab'
import {FieldsTab} from 'components/form/admin/fields.tab'
import {RespondentNotificationsTab} from 'components/form/admin/respondent.notifications.tab'
import {SelfNotificationsTab} from 'components/form/admin/self.notifications.tab'
import {StartPageTab} from 'components/form/admin/start.page.tab'
import Structure from 'components/structure'
import {withAuth} from 'components/with.auth'
import {AdminFormFieldFragment} from 'graphql/fragment/admin.form.fragment'
import {
ADMIN_FORM_UPDATE_MUTATION,
AdminFormUpdateMutationData,
AdminFormUpdateMutationVariables
} from '../../../../graphql/mutation/admin.form.update.mutation'
import {ADMIN_FORM_QUERY, AdminFormQueryData, AdminFormQueryVariables} from '../../../../graphql/query/admin.form.query'
} from 'graphql/mutation/admin.form.update.mutation'
import {ADMIN_FORM_QUERY, AdminFormQueryData, AdminFormQueryVariables} from 'graphql/query/admin.form.query'
import {NextPage} from 'next'
import {useRouter} from 'next/router'
import React, {useState} from 'react'
const Index: NextPage = () => {
const router = useRouter()

View File

@ -0,0 +1,115 @@
import {useMutation} from '@apollo/react-hooks'
import {Button, Form, Input, message, Tabs} from 'antd'
import {useForm} from 'antd/lib/form/Form'
import {cleanInput} from 'components/clean.input'
import {BaseDataTab} from 'components/form/admin/base.data.tab'
import Structure from 'components/structure'
import {withAuth} from 'components/with.auth'
import {AdminFormQueryData} from 'graphql/query/admin.form.query'
import {NextPage} from 'next'
import {useRouter} from 'next/router'
import React, {useState} from 'react'
import {
ADMIN_FORM_CREATE_MUTATION,
AdminFormCreateMutationData,
AdminFormCreateMutationVariables
} from '../../../graphql/mutation/admin.form.create.mutation'
const Create: NextPage = () => {
const router = useRouter()
const [form] = useForm()
const [saving, setSaving] = useState(false)
const [create] = useMutation<AdminFormCreateMutationData, AdminFormCreateMutationVariables>(ADMIN_FORM_CREATE_MUTATION)
const save = async (formData: AdminFormQueryData) => {
setSaving(true)
console.log('try to save form!', formData)
try {
const next = (await create({
variables: cleanInput(formData),
})).data
message.success('Form Created')
router.replace('/admin/forms/[id]', `/admin/forms/${next.form.id}`)
} catch (e) {
console.error('failed to save', e)
message.error('Could not save Form')
}
setSaving(false)
}
return (
<Structure
loading={saving}
title={'Create New Form'}
selected={'forms'}
breadcrumbs={[
{ href: '/admin', name: 'Home' },
{ href: '/admin/forms', name: 'Form' },
]}
extra={[
<Button
key={'create'}
onClick={form.submit}
type={'primary'}
>
Save
</Button>,
]}
style={{paddingTop: 0}}
>
<Form
form={form}
onFinish={save}
onFinishFailed={errors => {
message.error('Required fields are missing')
}}
labelCol={{
xs: { span: 24 },
sm: { span: 6 },
}}
wrapperCol={{
xs: { span: 24 },
sm: { span: 18 },
}}
>
<Form.Item noStyle name={['form', 'id']}><Input type={'hidden'} /></Form.Item>
<Tabs>
{/*
<FieldsTab
key={'fields'}
tab={'Fields'}
fields={fields}
onChangeFields={setFields}
form={form}
/>
*/}
<BaseDataTab key={'base_data'} tab={'Base Data'} />
{/*
<DesignTab key={'design'} tab={'Design'} />
<SelfNotificationsTab
key={'self_notifications'}
tab={'Self Notifications'}
fields={fields}
form={form}
/>
<RespondentNotificationsTab
key={'respondent_notifications'}
tab={'Respondent Notifications'}
fields={fields}
form={form}
/>
<StartPageTab key={'start_page'} tab={'Start Page'} />
<EndPageTab key={'end_page'} tab={'End Page'} />
*/}
</Tabs>
</Form>
</Structure>
)
}
export default withAuth(Create, ['admin'])

View File

@ -2,20 +2,20 @@ import {DeleteOutlined, EditOutlined, GlobalOutlined} from '@ant-design/icons/li
import {useQuery} from '@apollo/react-hooks'
import {Button, Popconfirm, Space, Table, Tooltip} from 'antd'
import {PaginationProps} from 'antd/es/pagination'
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/admin/is.live'
import Structure from '../../../components/structure'
import {TimeAgo} from '../../../components/time.ago'
import {withAuth} from '../../../components/with.auth'
import {DateTime} from 'components/date.time'
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'
import {
PAGER_FORM_QUERY,
PagerFormEntryQueryData,
PagerFormQueryData,
PagerFormQueryVariables
} from '../../../graphql/query/pager.form.query'
} from 'graphql/query/pager.form.query'
import {NextPage} from 'next'
import Link from 'next/link'
import React, {useState} from 'react'
const Index: NextPage = () => {
const [pagination, setPagination] = useState<PaginationProps>({
@ -118,6 +118,18 @@ const Index: NextPage = () => {
{ href: '/admin', name: 'Home' },
]}
padded={false}
extra={[
<Link
key={'create'}
href={'/admin/forms/create'}
>
<Button
type={'primary'}
>
New Form
</Button>
</Link>,
]}
>
<Table
columns={columns}

View File

@ -1,7 +1,7 @@
import Structure from 'components/structure'
import {withAuth} from 'components/with.auth'
import {NextPage} from 'next'
import React from 'react'
import Structure from '../../components/structure'
import {withAuth} from '../../components/with.auth'
const Index: NextPage = () => {
return (

View File

@ -1,7 +1,7 @@
import Structure from 'components/structure'
import {withAuth} from 'components/with.auth'
import {NextPage} from 'next'
import React from 'react'
import Structure from '../../../../components/structure'
import {withAuth} from '../../../../components/with.auth'
const Index: NextPage = () => {
return (

View File

@ -1,7 +1,7 @@
import Structure from 'components/structure'
import {withAuth} from 'components/with.auth'
import {NextPage} from 'next'
import React from 'react'
import Structure from '../../../components/structure'
import {withAuth} from '../../../components/with.auth'
const Index: NextPage = () => {
return (

View File

@ -1,15 +1,15 @@
import {useQuery} from '@apollo/react-hooks'
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'
import {NextPage} from 'next'
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
@ -62,14 +62,14 @@ const Index: NextPage<Props> = ({id}) => {
}}>
<Swiper {...swiperConfig}>
{[
<FormPage
data.form.startPage.show ? <FormPage
key={'start'}
type={'start'}
page={data.form.startPage}
design={design}
next={goNext}
prev={goPrev}
/>,
/> : undefined,
...data.form.fields.map(field => (
<Field
key={field.id}
@ -79,15 +79,15 @@ const Index: NextPage<Props> = ({id}) => {
prev={goPrev}
/>
)),
<FormPage
data.form.endPage.show ? <FormPage
key={'end'}
type={'end'}
page={data.form.endPage}
design={design}
next={goNext}
prev={goPrev}
/>
]}
/> : undefined
].filter(e => !!e)}
</Swiper>
</div>
)

View File

@ -1,6 +1,6 @@
import {ErrorPage} from 'components/error.page'
import {NextPage} from 'next'
import React from 'react'
import {ErrorPage} from '../../components/error.page'
const Index: NextPage = () => {
return (

View File

@ -1,7 +1,7 @@
import {Layout} from 'antd'
import {AuthFooter} from 'components/auth/footer'
import {NextPage} from 'next'
import React from 'react'
import {AuthFooter} from '../components/auth/footer'
const Index: NextPage = () => {
return (

View File

@ -1,8 +1,8 @@
import {Alert} from 'antd'
import {AuthFooter} from 'components/auth/footer'
import {AuthLayout} from 'components/auth/layout'
import {NextPage} from 'next'
import React from 'react'
import {AuthFooter} from '../../../components/auth/footer'
import {AuthLayout} from '../../../components/auth/layout'
const Index: NextPage = () => {
return (

View File

@ -1,14 +1,14 @@
import {useMutation} from '@apollo/react-hooks'
import {Button, Form, Input, message} from 'antd'
import {useForm} from 'antd/lib/form/Form'
import {AuthFooter} from 'components/auth/footer'
import {AuthLayout} from 'components/auth/layout'
import {setAuth} from 'components/with.auth'
import {LOGIN_MUTATION} from 'graphql/mutation/login.mutation'
import {NextPage} from 'next'
import Link from 'next/link'
import {useRouter} from 'next/router'
import React, {useState} from 'react'
import {AuthFooter} from '../../components/auth/footer'
import {AuthLayout} from '../../components/auth/layout'
import {setAuth} from '../../components/with.auth'
import {LOGIN_MUTATION} from '../../graphql/mutation/login.mutation'
const Index: NextPage = () => {
const [form] = useForm()

View File

@ -1,8 +1,8 @@
import {Alert} from 'antd'
import {AuthFooter} from 'components/auth/footer'
import {AuthLayout} from 'components/auth/layout'
import {NextPage} from 'next'
import React from 'react'
import {AuthFooter} from '../../components/auth/footer'
import {AuthLayout} from '../../components/auth/layout'
const Recover: NextPage = () => {
return (

View File

@ -1,14 +1,14 @@
import {useMutation} from '@apollo/react-hooks'
import {Button, Form, Input, message} from 'antd'
import {useForm} from 'antd/lib/form/Form'
import {AuthFooter} from 'components/auth/footer'
import {AuthLayout} from 'components/auth/layout'
import {setAuth} from 'components/with.auth'
import {REGISTER_MUTATION} from 'graphql/mutation/register.mutation'
import {NextPage} from 'next'
import Link from 'next/link'
import {useRouter} from 'next/router'
import React, {useState} from 'react'
import {AuthFooter} from '../components/auth/footer'
import {AuthLayout} from '../components/auth/layout'
import {setAuth} from '../components/with.auth'
import {REGISTER_MUTATION} from '../graphql/mutation/register.mutation'
const Register: NextPage = () => {
const [form] = useForm()