mirror of
https://github.com/IT4Change/ohmyform-ui.git
synced 2025-12-13 09:45:50 +00:00
- ability to change user passwords
- add default page background - add environment list in [doc](doc/environment.md) - combined notificationts to become more versatile - use exported hooks for graphql - links at the bottom for new users - fixes for hide contrib setting - upgrad all packages
This commit is contained in:
parent
dfbad77d7e
commit
8713c0a8c6
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,7 @@ yarn-error.log*
|
|||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
|
.env
|
||||||
|
|
||||||
# development environments
|
# development environments
|
||||||
/.idea
|
/.idea
|
||||||
|
|||||||
13
CHANGELOG.md
13
CHANGELOG.md
@ -9,12 +9,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- ability to change user passwords
|
||||||
|
- add default page background
|
||||||
|
- add environment list in [doc](doc/environment.md)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- combined notificationts to become more versatile
|
||||||
|
- use exported hooks for graphql
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- links at the bottom for new users
|
||||||
|
- fixes for hide contrib setting
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
- upgrad all packages
|
||||||
|
|
||||||
## [0.9.9] - 2021-02-14
|
## [0.9.9] - 2021-02-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
.footer {
|
.footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
padding-left: 16px;
|
||||||
|
margin-bottom: 4px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|||||||
@ -1,26 +1,30 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, Select } from 'antd'
|
import { Button, Select } from 'antd'
|
||||||
|
import getConfig from 'next/config'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import GitHubButton from 'react-github-button'
|
import GitHubButton from 'react-github-button'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { SETTINGS_QUERY, SettingsQueryData } from '../../graphql/query/settings.query'
|
import { useSettingsQuery } from '../../graphql/query/settings.query'
|
||||||
import { languages } from '../../i18n'
|
import { languages } from '../../i18n'
|
||||||
|
import { NextConfigType } from '../../next.config.type'
|
||||||
import { clearAuth, withAuth } from '../with.auth'
|
import { clearAuth, withAuth } from '../with.auth'
|
||||||
import scss from './footer.module.scss'
|
import scss from './footer.module.scss'
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig() as NextConfigType
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
me?: {
|
me?: {
|
||||||
id: string
|
id: string
|
||||||
username: string
|
username: string
|
||||||
|
roles: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthFooterInner: React.FC<Props> = (props) => {
|
const AuthFooterInner: React.FC<Props> = (props) => {
|
||||||
const { t, i18n } = useTranslation()
|
const { t, i18n } = useTranslation()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { data } = useQuery<SettingsQueryData>(SETTINGS_QUERY)
|
const { data, loading } = useSettingsQuery()
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
clearAuth()
|
clearAuth()
|
||||||
@ -29,7 +33,13 @@ const AuthFooterInner: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={scss.footer}>
|
<footer className={scss.footer}>
|
||||||
<Link href={'/admin'}>
|
{props.me
|
||||||
|
? [
|
||||||
|
<span style={{ color: '#FFF' }} key={'user'}>
|
||||||
|
Hi, {props.me.username}
|
||||||
|
</span>,
|
||||||
|
props.me.roles.includes('admin') && (
|
||||||
|
<Link key={'admin'} href={'/admin'}>
|
||||||
<Button
|
<Button
|
||||||
type={'link'}
|
type={'link'}
|
||||||
ghost
|
ghost
|
||||||
@ -40,11 +50,18 @@ const AuthFooterInner: React.FC<Props> = (props) => {
|
|||||||
{t('admin')}
|
{t('admin')}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{props.me
|
),
|
||||||
? [
|
<Link key={'profile'} href={'/admin/profile'}>
|
||||||
<span style={{ color: '#FFF' }} key={'user'}>
|
<Button
|
||||||
Hi, {props.me.username}
|
type={'link'}
|
||||||
</span>,
|
ghost
|
||||||
|
style={{
|
||||||
|
color: '#FFF',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('profile')}
|
||||||
|
</Button>
|
||||||
|
</Link>,
|
||||||
<Button
|
<Button
|
||||||
key={'logout'}
|
key={'logout'}
|
||||||
type={'link'}
|
type={'link'}
|
||||||
@ -69,18 +86,19 @@ const AuthFooterInner: React.FC<Props> = (props) => {
|
|||||||
{t('login')}
|
{t('login')}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>,
|
</Link>,
|
||||||
|
!loading && !data?.disabledSignUp.value && (
|
||||||
<Link href={'/register'} key={'register'}>
|
<Link href={'/register'} key={'register'}>
|
||||||
<Button
|
<Button
|
||||||
type={'link'}
|
type={'link'}
|
||||||
ghost
|
ghost
|
||||||
disabled={data ? data.disabledSignUp.value : false}
|
|
||||||
style={{
|
style={{
|
||||||
color: '#FFF',
|
color: '#FFF',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('register')}
|
{t('register')}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>,
|
</Link>
|
||||||
|
),
|
||||||
]}
|
]}
|
||||||
<div style={{ flex: 1 }} />
|
<div style={{ flex: 1 }} />
|
||||||
<Select
|
<Select
|
||||||
@ -99,6 +117,8 @@ const AuthFooterInner: React.FC<Props> = (props) => {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
{!loading && !data?.hideContrib.value && (
|
||||||
|
<>
|
||||||
<GitHubButton type="stargazers" namespace="ohmyform" repo="ohmyform" />
|
<GitHubButton type="stargazers" namespace="ohmyform" repo="ohmyform" />
|
||||||
<Button
|
<Button
|
||||||
type={'link'}
|
type={'link'}
|
||||||
@ -124,6 +144,8 @@ const AuthFooterInner: React.FC<Props> = (props) => {
|
|||||||
>
|
>
|
||||||
translated with Lokalize
|
translated with Lokalize
|
||||||
</Button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import { Layout, Spin } from 'antd'
|
import { Layout, Spin } from 'antd'
|
||||||
|
import getConfig from 'next/config'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { NextConfigType } from '../../next.config.type'
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig() as NextConfigType
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
@ -11,7 +15,7 @@ export const AuthLayout: React.FC<Props> = (props) => {
|
|||||||
<Layout
|
<Layout
|
||||||
style={{
|
style={{
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
background: '#437fdc',
|
background: publicRuntimeConfig.mainBackground,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|||||||
@ -13,17 +13,10 @@ export const DesignTab: React.FC<TabPaneProps> = (props) => {
|
|||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{[
|
{['background', 'question', 'answer', 'button', 'buttonActive', 'buttonText'].map((name) => (
|
||||||
'backgroundColor',
|
|
||||||
'questionColor',
|
|
||||||
'answerColor',
|
|
||||||
'buttonColor',
|
|
||||||
'buttonActiveColor',
|
|
||||||
'buttonTextColor',
|
|
||||||
].map((name) => (
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
key={name}
|
key={name}
|
||||||
label={t(`form:design.${name}`)}
|
label={t(`form:design.color.${name}`)}
|
||||||
name={['form', 'design', 'colors', name]}
|
name={['form', 'design', 'colors', name]}
|
||||||
>
|
>
|
||||||
<InputColor />
|
<InputColor />
|
||||||
|
|||||||
@ -1,19 +1,9 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import { message } from 'antd'
|
import { message } from 'antd'
|
||||||
import { useCallback, useState } from 'react'
|
|
||||||
import ExcelJS from 'exceljs'
|
import ExcelJS from 'exceljs'
|
||||||
import {
|
import { useCallback, useState } from 'react'
|
||||||
ADMIN_FORM_QUERY,
|
import { SubmissionFragment } from '../../../graphql/fragment/submission.fragment'
|
||||||
AdminFormQueryData,
|
import { useFormQuery } from '../../../graphql/query/form.query'
|
||||||
AdminFormQueryVariables,
|
import { useSubmissionPagerImperativeQuery } from '../../../graphql/query/submission.pager.query'
|
||||||
} from '../../../graphql/query/admin.form.query'
|
|
||||||
import {
|
|
||||||
ADMIN_PAGER_SUBMISSION_QUERY,
|
|
||||||
AdminPagerSubmissionEntryQueryData,
|
|
||||||
AdminPagerSubmissionQueryData,
|
|
||||||
AdminPagerSubmissionQueryVariables,
|
|
||||||
} from '../../../graphql/query/admin.pager.submission.query'
|
|
||||||
import { useImperativeQuery } from '../../use.imerative.query'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: string
|
form: string
|
||||||
@ -23,16 +13,13 @@ interface Props {
|
|||||||
export const ExportSubmissionAction: React.FC<Props> = (props) => {
|
export const ExportSubmissionAction: React.FC<Props> = (props) => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
const form = useQuery<AdminFormQueryData, AdminFormQueryVariables>(ADMIN_FORM_QUERY, {
|
const form = useFormQuery({
|
||||||
variables: {
|
variables: {
|
||||||
id: props.form,
|
id: props.form,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const getSubmissions = useImperativeQuery<
|
const getSubmissions = useSubmissionPagerImperativeQuery()
|
||||||
AdminPagerSubmissionQueryData,
|
|
||||||
AdminPagerSubmissionQueryVariables
|
|
||||||
>(ADMIN_PAGER_SUBMISSION_QUERY)
|
|
||||||
|
|
||||||
const exportSubmissions = useCallback(async () => {
|
const exportSubmissions = useCallback(async () => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
@ -66,7 +53,7 @@ export const ExportSubmissionAction: React.FC<Props> = (props) => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const buildRow = (data: AdminPagerSubmissionEntryQueryData): any[] => {
|
const buildRow = (data: SubmissionFragment): any[] => {
|
||||||
const row = [
|
const row = [
|
||||||
data.id,
|
data.id,
|
||||||
data.created,
|
data.created,
|
||||||
|
|||||||
@ -4,14 +4,14 @@ import { FormInstance } from 'antd/lib/form'
|
|||||||
import { FieldData } from 'rc-field-form/lib/interface'
|
import { FieldData } from 'rc-field-form/lib/interface'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { AdminFormFieldFragment } from '../../../graphql/fragment/admin.form.fragment'
|
import { FormFieldFragment } from '../../../graphql/fragment/form.fragment'
|
||||||
import { adminTypes } from './types'
|
import { adminTypes } from './types'
|
||||||
import { TextType } from './types/text.type'
|
import { TextType } from './types/text.type'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: FormInstance
|
form: FormInstance
|
||||||
fields: AdminFormFieldFragment[]
|
fields: FormFieldFragment[]
|
||||||
onChangeFields: (fields: AdminFormFieldFragment[]) => void
|
onChangeFields: (fields: FormFieldFragment[]) => void
|
||||||
field: FieldData
|
field: FieldData
|
||||||
remove: (index: number) => void
|
remove: (index: number) => void
|
||||||
index: number
|
index: number
|
||||||
|
|||||||
@ -5,14 +5,14 @@ import { TabPaneProps } from 'antd/lib/tabs'
|
|||||||
import { FieldData } from 'rc-field-form/lib/interface'
|
import { FieldData } from 'rc-field-form/lib/interface'
|
||||||
import React, { useCallback, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { AdminFormFieldFragment } from '../../../graphql/fragment/admin.form.fragment'
|
import { FormFieldFragment } from '../../../graphql/fragment/form.fragment'
|
||||||
import { FieldCard } from './field.card'
|
import { FieldCard } from './field.card'
|
||||||
import { adminTypes } from './types'
|
import { adminTypes } from './types'
|
||||||
|
|
||||||
interface Props extends TabPaneProps {
|
interface Props extends TabPaneProps {
|
||||||
form: FormInstance
|
form: FormInstance
|
||||||
fields: AdminFormFieldFragment[]
|
fields: FormFieldFragment[]
|
||||||
onChangeFields: (fields: AdminFormFieldFragment[]) => void
|
onChangeFields: (fields: FormFieldFragment[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FieldsTab: React.FC<Props> = (props) => {
|
export const FieldsTab: React.FC<Props> = (props) => {
|
||||||
@ -55,10 +55,8 @@ export const FieldsTab: React.FC<Props> = (props) => {
|
|||||||
<Button
|
<Button
|
||||||
type="dashed"
|
type="dashed"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const defaults: AdminFormFieldFragment = {
|
const defaults: FormFieldFragment = {
|
||||||
logicJump: {
|
logic: [],
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
options: [],
|
options: [],
|
||||||
id: `NEW-${Date.now()}`,
|
id: `NEW-${Date.now()}`,
|
||||||
type: nextType,
|
type: nextType,
|
||||||
|
|||||||
231
components/form/admin/notification.card.tsx
Normal file
231
components/form/admin/notification.card.tsx
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import { DeleteOutlined, InfoCircleOutlined } from '@ant-design/icons/lib'
|
||||||
|
import { Button, Card, Form, Input, Popconfirm, Select, Switch } from 'antd'
|
||||||
|
import { FormInstance } from 'antd/lib/form'
|
||||||
|
import { FieldData } from 'rc-field-form/lib/interface'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
|
import { FormFieldFragment } from '../../../graphql/fragment/form.fragment'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
form: FormInstance
|
||||||
|
field: FieldData
|
||||||
|
groups: {
|
||||||
|
[key: string]: FormFieldFragment[]
|
||||||
|
}
|
||||||
|
remove: (index: number) => void
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NotificationCard: React.FC<Props> = (props) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { form, field, remove, index, groups } = props
|
||||||
|
|
||||||
|
const [enabled, setEnabled] = useState<boolean>()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={'Notification'}
|
||||||
|
type={'inner'}
|
||||||
|
extra={
|
||||||
|
<div>
|
||||||
|
<Popconfirm
|
||||||
|
placement={'left'}
|
||||||
|
title={t('type:confirmDelete')}
|
||||||
|
okText={t('type:deleteNow')}
|
||||||
|
okButtonProps={{ danger: true }}
|
||||||
|
onConfirm={() => {
|
||||||
|
remove(index)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button danger>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
actions={[<DeleteOutlined key={'delete'} onClick={() => remove(index)} />]}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.enabled')}
|
||||||
|
name={[field.name as string, 'enabled']}
|
||||||
|
valuePropName={'checked'}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
>
|
||||||
|
<Switch onChange={(e) => setEnabled(e.valueOf())} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.subject')}
|
||||||
|
name={[field.name as string, 'subject']}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled'])
|
||||||
|
),
|
||||||
|
message: t('validation:subjectRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.htmlTemplate')}
|
||||||
|
name={[field.name as string, 'htmlTemplate']}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled'])
|
||||||
|
),
|
||||||
|
message: t('validation:templateRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
extra={
|
||||||
|
<div>
|
||||||
|
<Trans>form:notifications.htmlTemplateInfo</Trans>
|
||||||
|
<a
|
||||||
|
href={'https://mjml.io/try-it-live'}
|
||||||
|
target={'_blank'}
|
||||||
|
rel={'noreferrer'}
|
||||||
|
style={{
|
||||||
|
marginLeft: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
>
|
||||||
|
<Input.TextArea autoSize />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.fromField')}
|
||||||
|
name={[field.name as string, 'fromField']}
|
||||||
|
extra={t('form:notifications.fromFieldInfo')}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled']) &&
|
||||||
|
!form.getFieldValue([
|
||||||
|
'form',
|
||||||
|
'notifications',
|
||||||
|
field.name as string,
|
||||||
|
'fromEmail',
|
||||||
|
])
|
||||||
|
),
|
||||||
|
message: t('validation:emailFieldRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
{Object.keys(groups).map((key) => (
|
||||||
|
<Select.OptGroup label={key.toUpperCase()} key={key}>
|
||||||
|
{groups[key].map((element) => (
|
||||||
|
<Select.Option value={element.id} key={element.id}>
|
||||||
|
{element.title}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select.OptGroup>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.fromEmail')}
|
||||||
|
name={[field.name as string, 'fromEmail']}
|
||||||
|
extra={t('form:notifications.fromEmailInfo')}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled']) &&
|
||||||
|
!form.getFieldValue([
|
||||||
|
'form',
|
||||||
|
'notifications',
|
||||||
|
field.name as string,
|
||||||
|
'fromField',
|
||||||
|
])
|
||||||
|
),
|
||||||
|
message: t('validation:emailFieldRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.toField')}
|
||||||
|
name={[field.name as string, 'toField']}
|
||||||
|
extra={t('form:notifications.toFieldInfo')}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled']) &&
|
||||||
|
!form.getFieldValue(['form', 'notifications', field.name as string, 'toEmail'])
|
||||||
|
),
|
||||||
|
message: t('validation:emailFieldRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
{Object.keys(groups).map((key) => (
|
||||||
|
<Select.OptGroup label={key.toUpperCase()} key={key}>
|
||||||
|
{groups[key].map((field) => (
|
||||||
|
<Select.Option value={field.id} key={field.id}>
|
||||||
|
{field.title}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select.OptGroup>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t('form:notifications.toEmail')}
|
||||||
|
name={[field.name as string, 'toEmail']}
|
||||||
|
extra={t('form:notifications.toEmailInfo')}
|
||||||
|
labelCol={{ span: 6 }}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(
|
||||||
|
form.getFieldValue(['form', 'notifications', field.name as string, 'enabled']) &&
|
||||||
|
!form.getFieldValue(['form', 'notifications', field.name as string, 'toField'])
|
||||||
|
),
|
||||||
|
message: t('validation:emailFieldRequired'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
93
components/form/admin/notifications.tab.tsx
Normal file
93
components/form/admin/notifications.tab.tsx
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { PlusOutlined } from '@ant-design/icons/lib'
|
||||||
|
import { Button, Form, Space, Tabs } from 'antd'
|
||||||
|
import { FormInstance } from 'antd/lib/form'
|
||||||
|
import { TabPaneProps } from 'antd/lib/tabs'
|
||||||
|
import React, { useCallback } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import {
|
||||||
|
FormFieldFragment,
|
||||||
|
FormNotificationFragment,
|
||||||
|
} from '../../../graphql/fragment/form.fragment'
|
||||||
|
import { NotificationCard } from './notification.card'
|
||||||
|
|
||||||
|
interface Props extends TabPaneProps {
|
||||||
|
form: FormInstance
|
||||||
|
fields: FormFieldFragment[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NotificationsTab: React.FC<Props> = (props) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const groups: {
|
||||||
|
[key: string]: FormFieldFragment[]
|
||||||
|
} = {}
|
||||||
|
props.fields.forEach((field) => {
|
||||||
|
if (!groups[field.type]) {
|
||||||
|
groups[field.type] = []
|
||||||
|
}
|
||||||
|
groups[field.type].push(field)
|
||||||
|
})
|
||||||
|
|
||||||
|
const addField = useCallback(
|
||||||
|
(add: (defaults: unknown) => void, index: number) => {
|
||||||
|
return (
|
||||||
|
<Form.Item wrapperCol={{ span: 24 }}>
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
onClick={() => {
|
||||||
|
const defaults: FormNotificationFragment = {
|
||||||
|
id: Math.random().toString(),
|
||||||
|
enabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
add(defaults)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlusOutlined /> {t('form:notifications.add')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form.Item>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[props.fields]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs.TabPane {...props}>
|
||||||
|
<Form.List name={['form', 'notifications']}>
|
||||||
|
{(fields, { add, remove, move }) => {
|
||||||
|
const addAndMove = (index) => (defaults) => {
|
||||||
|
add(defaults)
|
||||||
|
move(fields.length, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{addField(addAndMove(0), 0)}
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<div key={field.key}>
|
||||||
|
<Form.Item wrapperCol={{ span: 24 }}>
|
||||||
|
<NotificationCard
|
||||||
|
form={props.form}
|
||||||
|
field={field}
|
||||||
|
index={index}
|
||||||
|
remove={remove}
|
||||||
|
groups={groups}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{addField(addAndMove(index + 1), index + 1)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
</Tabs.TabPane>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,131 +0,0 @@
|
|||||||
import { InfoCircleOutlined } from '@ant-design/icons/lib'
|
|
||||||
import { Form, Input, Select, Switch, Tabs } from 'antd'
|
|
||||||
import { FormInstance } from 'antd/lib/form'
|
|
||||||
import { TabPaneProps } from 'antd/lib/tabs'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
|
||||||
import { AdminFormFieldFragment } from '../../../graphql/fragment/admin.form.fragment'
|
|
||||||
|
|
||||||
interface Props extends TabPaneProps {
|
|
||||||
form: FormInstance
|
|
||||||
fields: AdminFormFieldFragment[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RespondentNotificationsTab: React.FC<Props> = (props) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [enabled, setEnabled] = useState<boolean>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const next = props.form.getFieldValue(['form', 'respondentNotifications', 'enabled']) as boolean
|
|
||||||
|
|
||||||
if (next !== enabled) {
|
|
||||||
setEnabled(next)
|
|
||||||
}
|
|
||||||
}, [props.form.getFieldValue(['form', 'respondentNotifications', 'enabled'])])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
props.form
|
|
||||||
.validateFields([
|
|
||||||
['form', 'respondentNotifications', 'subject'],
|
|
||||||
['form', 'respondentNotifications', 'htmlTemplate'],
|
|
||||||
['form', 'respondentNotifications', 'toField'],
|
|
||||||
])
|
|
||||||
.catch((e: Error) => console.error('failed to validate fields', e))
|
|
||||||
}, [enabled])
|
|
||||||
|
|
||||||
const groups: {
|
|
||||||
[key: string]: AdminFormFieldFragment[]
|
|
||||||
} = {}
|
|
||||||
|
|
||||||
props.fields.forEach((field) => {
|
|
||||||
if (!groups[field.type]) {
|
|
||||||
groups[field.type] = []
|
|
||||||
}
|
|
||||||
groups[field.type].push(field)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs.TabPane {...props}>
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:respondentNotifications.enabled')}
|
|
||||||
name={['form', 'respondentNotifications', 'enabled']}
|
|
||||||
valuePropName={'checked'}
|
|
||||||
>
|
|
||||||
<Switch onChange={(e) => setEnabled(e.valueOf())} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:respondentNotifications.subject')}
|
|
||||||
name={['form', 'respondentNotifications', 'subject']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: enabled,
|
|
||||||
message: t('validation:subjectRequired'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:respondentNotifications.htmlTemplate')}
|
|
||||||
name={['form', 'respondentNotifications', 'htmlTemplate']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: enabled,
|
|
||||||
message: t('validation:templateRequired'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
extra={
|
|
||||||
<div>
|
|
||||||
<Trans>form:respondentNotifications.htmlTemplateInfo</Trans>
|
|
||||||
<a
|
|
||||||
href={'https://mjml.io/try-it-live'}
|
|
||||||
target={'_blank'}
|
|
||||||
rel={'noreferrer'}
|
|
||||||
style={{
|
|
||||||
marginLeft: 16,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input.TextArea autoSize />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:respondentNotifications.toField')}
|
|
||||||
name={['form', 'respondentNotifications', 'toField']}
|
|
||||||
extra={t('form:respondentNotifications.toFieldInfo')}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: enabled,
|
|
||||||
message: t('validation:emailFieldRequired'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select>
|
|
||||||
{Object.keys(groups).map((key) => (
|
|
||||||
<Select.OptGroup label={key.toUpperCase()} key={key}>
|
|
||||||
{groups[key].map((field) => (
|
|
||||||
<Select.Option value={field.id} key={field.id}>
|
|
||||||
{field.title}
|
|
||||||
</Select.Option>
|
|
||||||
))}
|
|
||||||
</Select.OptGroup>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:respondentNotifications.fromEmail')}
|
|
||||||
name={['form', 'respondentNotifications', 'fromEmail']}
|
|
||||||
extra={t('form:respondentNotifications.fromEmailInfo')}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
</Tabs.TabPane>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
import { InfoCircleOutlined } from '@ant-design/icons/lib'
|
|
||||||
import { Form, Input, Select, Switch, Tabs } from 'antd'
|
|
||||||
import { FormInstance } from 'antd/lib/form'
|
|
||||||
import { TabPaneProps } from 'antd/lib/tabs'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
|
||||||
import { AdminFormFieldFragment } from '../../../graphql/fragment/admin.form.fragment'
|
|
||||||
|
|
||||||
interface Props extends TabPaneProps {
|
|
||||||
form: FormInstance
|
|
||||||
fields: AdminFormFieldFragment[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SelfNotificationsTab: React.FC<Props> = (props) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [enabled, setEnabled] = useState<boolean>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const next = props.form.getFieldValue(['form', 'selfNotifications', 'enabled']) as boolean
|
|
||||||
|
|
||||||
if (next !== enabled) {
|
|
||||||
setEnabled(next)
|
|
||||||
}
|
|
||||||
}, [props.form.getFieldValue(['form', 'selfNotifications', 'enabled'])])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
props.form
|
|
||||||
.validateFields([
|
|
||||||
['form', 'selfNotifications', 'subject'],
|
|
||||||
['form', 'selfNotifications', 'htmlTemplate'],
|
|
||||||
])
|
|
||||||
.catch((e: Error) => console.error('failed to validate', e))
|
|
||||||
}, [enabled])
|
|
||||||
|
|
||||||
const groups: {
|
|
||||||
[key: string]: AdminFormFieldFragment[]
|
|
||||||
} = {}
|
|
||||||
props.fields.forEach((field) => {
|
|
||||||
if (!groups[field.type]) {
|
|
||||||
groups[field.type] = []
|
|
||||||
}
|
|
||||||
groups[field.type].push(field)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs.TabPane {...props}>
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:selfNotifications.enabled')}
|
|
||||||
name={['form', 'selfNotifications', 'enabled']}
|
|
||||||
valuePropName={'checked'}
|
|
||||||
>
|
|
||||||
<Switch onChange={(e) => setEnabled(e.valueOf())} />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:selfNotifications.subject')}
|
|
||||||
name={['form', 'selfNotifications', 'subject']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: enabled,
|
|
||||||
message: t('validation:subjectRequired'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:selfNotifications.htmlTemplate')}
|
|
||||||
name={['form', 'selfNotifications', 'htmlTemplate']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: enabled,
|
|
||||||
message: t('validation:templateRequired'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
extra={
|
|
||||||
<div>
|
|
||||||
<Trans>form:selfNotifications.htmlTemplateInfo</Trans>
|
|
||||||
<a
|
|
||||||
href={'https://mjml.io/try-it-live'}
|
|
||||||
target={'_blank'}
|
|
||||||
rel={'noreferrer'}
|
|
||||||
style={{
|
|
||||||
marginLeft: 16,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input.TextArea autoSize />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:selfNotifications.fromField')}
|
|
||||||
name={['form', 'selfNotifications', 'fromField']}
|
|
||||||
extra={t('form:selfNotifications.fromFieldInfo')}
|
|
||||||
>
|
|
||||||
<Select>
|
|
||||||
{Object.keys(groups).map((key) => (
|
|
||||||
<Select.OptGroup label={key.toUpperCase()} key={key}>
|
|
||||||
{groups[key].map((field) => (
|
|
||||||
<Select.Option value={field.id} key={field.id}>
|
|
||||||
{field.title}
|
|
||||||
</Select.Option>
|
|
||||||
))}
|
|
||||||
</Select.OptGroup>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t('form:selfNotifications.toEmail')}
|
|
||||||
name={['form', 'selfNotifications', 'toEmail']}
|
|
||||||
extra={t('form:selfNotifications.toEmailInfo')}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
</Tabs.TabPane>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -2,24 +2,24 @@ import { Descriptions, Table } from 'antd'
|
|||||||
import { ColumnsType } from 'antd/lib/table/interface'
|
import { ColumnsType } from 'antd/lib/table/interface'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { FormPagerFragment } from '../../../graphql/fragment/form.pager.fragment'
|
||||||
import {
|
import {
|
||||||
AdminPagerSubmissionEntryFieldQueryData,
|
SubmissionFragment,
|
||||||
AdminPagerSubmissionEntryQueryData,
|
SubmissionFragmentField,
|
||||||
AdminPagerSubmissionFormQueryData,
|
} from '../../../graphql/fragment/submission.fragment'
|
||||||
} from '../../../graphql/query/admin.pager.submission.query'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
form: AdminPagerSubmissionFormQueryData
|
form: FormPagerFragment
|
||||||
submission: AdminPagerSubmissionEntryQueryData
|
submission: SubmissionFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SubmissionValues: React.FC<Props> = (props) => {
|
export const SubmissionValues: React.FC<Props> = (props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const columns: ColumnsType<AdminPagerSubmissionEntryFieldQueryData> = [
|
const columns: ColumnsType<SubmissionFragmentField> = [
|
||||||
{
|
{
|
||||||
title: t('submission:field'),
|
title: t('submission:field'),
|
||||||
render(row: AdminPagerSubmissionEntryFieldQueryData) {
|
render(_, row) {
|
||||||
if (row.field) {
|
if (row.field) {
|
||||||
return `${row.field.title}${row.field.required ? '*' : ''}`
|
return `${row.field.title}${row.field.required ? '*' : ''}`
|
||||||
}
|
}
|
||||||
@ -29,10 +29,12 @@ export const SubmissionValues: React.FC<Props> = (props) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('submission:value'),
|
title: t('submission:value'),
|
||||||
render(row: AdminPagerSubmissionEntryFieldQueryData) {
|
render(_, row) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(row.value) as { value: string }
|
const data = JSON.parse(row.value) as { value: string }
|
||||||
|
|
||||||
|
console.log('DATA', data)
|
||||||
|
|
||||||
return data.value
|
return data.value
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return row.value
|
return row.value
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { AdminFieldTypeProps } from './type.props'
|
|||||||
export const RatingType: React.FC<AdminFieldTypeProps> = (props) => {
|
export const RatingType: React.FC<AdminFieldTypeProps> = (props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// TODO add ratings
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { AdminFieldTypeProps } from './type.props'
|
|||||||
export const YesNoType: React.FC<AdminFieldTypeProps> = (props) => {
|
export const YesNoType: React.FC<AdminFieldTypeProps> = (props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// TODO add switch
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { Form, message } from 'antd'
|
import { Form, message } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FormDesignFragment, FormFieldFragment } from '../../graphql/fragment/form.fragment'
|
import {
|
||||||
|
FormPublicDesignFragment,
|
||||||
|
FormPublicFieldFragment,
|
||||||
|
} from '../../graphql/fragment/form.public.fragment'
|
||||||
import { StyledButton } from '../styled/button'
|
import { StyledButton } from '../styled/button'
|
||||||
import { StyledH1 } from '../styled/h1'
|
import { StyledH1 } from '../styled/h1'
|
||||||
import { StyledMarkdown } from '../styled/markdown'
|
import { StyledMarkdown } from '../styled/markdown'
|
||||||
@ -11,8 +14,8 @@ import { TextType } from './types/text.type'
|
|||||||
import { FieldTypeProps } from './types/type.props'
|
import { FieldTypeProps } from './types/type.props'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
field: FormFieldFragment
|
field: FormPublicFieldFragment
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
save: (data: any) => void
|
save: (data: any) => void
|
||||||
@ -84,9 +87,9 @@ export const Field: React.FC<Props> = ({ field, save, design, next, prev, ...pro
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledButton
|
<StyledButton
|
||||||
background={design.colors.buttonColor}
|
background={design.colors.button}
|
||||||
color={design.colors.buttonTextColor}
|
color={design.colors.buttonText}
|
||||||
highlight={design.colors.buttonActiveColor}
|
highlight={design.colors.buttonActive}
|
||||||
onClick={prev}
|
onClick={prev}
|
||||||
>
|
>
|
||||||
{'Previous'}
|
{'Previous'}
|
||||||
@ -95,9 +98,9 @@ export const Field: React.FC<Props> = ({ field, save, design, next, prev, ...pro
|
|||||||
<div style={{ flex: 1 }} />
|
<div style={{ flex: 1 }} />
|
||||||
|
|
||||||
<StyledButton
|
<StyledButton
|
||||||
background={design.colors.buttonColor}
|
background={design.colors.button}
|
||||||
color={design.colors.buttonTextColor}
|
color={design.colors.buttonText}
|
||||||
highlight={design.colors.buttonActiveColor}
|
highlight={design.colors.buttonActive}
|
||||||
size={'large'}
|
size={'large'}
|
||||||
onClick={form.submit}
|
onClick={form.submit}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { Space } from 'antd'
|
import { Space } from 'antd'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FormDesignFragment, FormPageFragment } from '../../graphql/fragment/form.fragment'
|
import {
|
||||||
|
FormPublicDesignFragment,
|
||||||
|
FormPublicPageFragment,
|
||||||
|
} from '../../graphql/fragment/form.public.fragment'
|
||||||
import { StyledButton } from '../styled/button'
|
import { StyledButton } from '../styled/button'
|
||||||
import { StyledH1 } from '../styled/h1'
|
import { StyledH1 } from '../styled/h1'
|
||||||
import { StyledMarkdown } from '../styled/markdown'
|
import { StyledMarkdown } from '../styled/markdown'
|
||||||
@ -8,8 +11,8 @@ import scss from './page.module.scss'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: 'start' | 'end'
|
type: 'start' | 'end'
|
||||||
page: FormPageFragment
|
page: FormPublicPageFragment
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
className?: string
|
className?: string
|
||||||
|
|
||||||
next: () => void
|
next: () => void
|
||||||
@ -59,9 +62,9 @@ export const FormPage: React.FC<Props> = ({ page, design, next, prev, className,
|
|||||||
<div style={{ flex: 1 }} />
|
<div style={{ flex: 1 }} />
|
||||||
|
|
||||||
<StyledButton
|
<StyledButton
|
||||||
background={design.colors.buttonColor}
|
background={design.colors.button}
|
||||||
color={design.colors.buttonTextColor}
|
color={design.colors.buttonText}
|
||||||
highlight={design.colors.buttonActiveColor}
|
highlight={design.colors.buttonActive}
|
||||||
size={'large'}
|
size={'large'}
|
||||||
onClick={next}
|
onClick={next}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { FieldTypeProps } from './type.props'
|
|||||||
|
|
||||||
export const RatingType: React.FC<FieldTypeProps> = ({ field, urlValue }) => {
|
export const RatingType: React.FC<FieldTypeProps> = ({ field, urlValue }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
// TODO add ratings
|
|
||||||
|
|
||||||
let initialValue: number = undefined
|
let initialValue: number = undefined
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { FormDesignFragment, FormFieldFragment } from '../../../graphql/fragment/form.fragment'
|
import {
|
||||||
|
FormPublicDesignFragment,
|
||||||
|
FormPublicFieldFragment,
|
||||||
|
} from '../../../graphql/fragment/form.public.fragment'
|
||||||
|
|
||||||
export interface FieldTypeProps {
|
export interface FieldTypeProps {
|
||||||
field: FormFieldFragment
|
field: FormPublicFieldFragment
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
urlValue?: string
|
urlValue?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { SETTINGS_QUERY, SettingsQueryData } from '../graphql/query/settings.query'
|
import { useSettingsQuery } from '../graphql/query/settings.query'
|
||||||
import scss from './omf.module.scss'
|
import scss from './omf.module.scss'
|
||||||
|
|
||||||
export const Omf: React.FC = () => {
|
export const Omf: React.FC = () => {
|
||||||
const { data, loading } = useQuery<SettingsQueryData>(SETTINGS_QUERY)
|
const { data, loading } = useSettingsQuery()
|
||||||
|
|
||||||
if (loading || (data && data.hideContrib.value)) {
|
if (loading || (data && data.hideContrib.value)) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import { CaretDownOutlined, UserOutlined } from '@ant-design/icons'
|
import { CaretDownOutlined, UserOutlined } from '@ant-design/icons'
|
||||||
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons/lib'
|
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons/lib'
|
||||||
import { useQuery } from '@apollo/react-hooks'
|
import { Alert, Dropdown, Layout, Menu, PageHeader, Select, Space, Spin, Tag } from 'antd'
|
||||||
import { Dropdown, Layout, Menu, PageHeader, Select, Space, Spin, Tag } from 'antd'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { CSSProperties, FunctionComponent } from 'react'
|
import React, { CSSProperties, FunctionComponent } from 'react'
|
||||||
|
import GitHubButton from 'react-github-button'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ME_QUERY, MeQueryData } from '../graphql/query/me.query'
|
import { useMeQuery } from '../graphql/query/me.query'
|
||||||
import { languages } from '../i18n'
|
import { languages } from '../i18n'
|
||||||
import { sideMenu, SideMenuElement } from './sidemenu'
|
import { sideMenu, SideMenuElement } from './sidemenu'
|
||||||
import GitHubButton from 'react-github-button'
|
|
||||||
import { useWindowSize } from './use.window.size'
|
import { useWindowSize } from './use.window.size'
|
||||||
import { clearAuth } from './with.auth'
|
import { clearAuth } from './with.auth'
|
||||||
|
|
||||||
@ -33,9 +32,10 @@ interface Props {
|
|||||||
title?: string
|
title?: string
|
||||||
subTitle?: string
|
subTitle?: string
|
||||||
extra?: JSX.Element[]
|
extra?: JSX.Element[]
|
||||||
|
error?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const Structure: FunctionComponent<Props> = (props) => {
|
export const Structure: FunctionComponent<Props> = (props) => {
|
||||||
const { t, i18n } = useTranslation()
|
const { t, i18n } = useTranslation()
|
||||||
const size = useWindowSize()
|
const size = useWindowSize()
|
||||||
const [userMenu, setUserMenu] = React.useState(false)
|
const [userMenu, setUserMenu] = React.useState(false)
|
||||||
@ -43,7 +43,7 @@ const Structure: FunctionComponent<Props> = (props) => {
|
|||||||
const [selected, setSelected] = React.useState<string[]>()
|
const [selected, setSelected] = React.useState<string[]>()
|
||||||
const [sidebar, setSidebar] = React.useState(size.width < 700)
|
const [sidebar, setSidebar] = React.useState(size.width < 700)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const user = useQuery<MeQueryData>(ME_QUERY)
|
const user = useMeQuery()
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (sidebar !== size.width < 700) {
|
if (sidebar !== size.width < 700) {
|
||||||
@ -76,7 +76,7 @@ const Structure: FunctionComponent<Props> = (props) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.data.me.roles.includes(element.role)
|
return user.data?.me.roles.includes(element.role)
|
||||||
})
|
})
|
||||||
.map(
|
.map(
|
||||||
(element): JSX.Element => {
|
(element): JSX.Element => {
|
||||||
@ -249,7 +249,9 @@ const Structure: FunctionComponent<Props> = (props) => {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Sider>
|
</Sider>
|
||||||
<Layout style={{ padding: '0 24px 24px' }}>
|
<Layout
|
||||||
|
style={{ padding: '0 24px 24px', minHeight: 500, height: '100%', overflow: 'auto' }}
|
||||||
|
>
|
||||||
{props.title && (
|
{props.title && (
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={props.title}
|
title={props.title}
|
||||||
@ -285,6 +287,10 @@ const Structure: FunctionComponent<Props> = (props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{props.error && (
|
||||||
|
<Alert message={props.error} type={'error'} style={{ marginBottom: 24 }} />
|
||||||
|
)}
|
||||||
|
|
||||||
<Spin spinning={!!props.loading}>
|
<Spin spinning={!!props.loading}>
|
||||||
<Content
|
<Content
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -3,15 +3,15 @@ import { PickerProps } from 'antd/lib/date-picker/generatePicker'
|
|||||||
import { Moment } from 'moment'
|
import { Moment } from 'moment'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { transparentize } from './color.change'
|
import { transparentize } from './color.change'
|
||||||
|
|
||||||
type Props = { design: FormDesignFragment } & PickerProps<Moment>
|
type Props = { design: FormPublicDesignFragment } & PickerProps<Moment>
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(DatePicker)`
|
const Field = styled(DatePicker)`
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
background: none !important;
|
background: none !important;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
@ -21,7 +21,7 @@ const Field = styled(DatePicker)`
|
|||||||
|
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ant-picker {
|
&.ant-picker {
|
||||||
@ -33,15 +33,15 @@ const Field = styled(DatePicker)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
|
color: ${(props: Props) => transparentize(props.design.colors.answer, 60)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: 'question' | 'answer'
|
type: 'question' | 'answer'
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
const Header = styled.h1`
|
const Header = styled.h1`
|
||||||
color: ${(props: Props) =>
|
color: ${(props: Props) =>
|
||||||
props.type === 'question'
|
props.type === 'question' ? props.design.colors.question : props.design.colors.answer};
|
||||||
? props.design.colors.questionColor
|
|
||||||
: props.design.colors.answerColor};
|
|
||||||
`
|
`
|
||||||
|
|
||||||
export const StyledH1: React.FC<Props> = ({ children, ...props }) => {
|
export const StyledH1: React.FC<Props> = ({ children, ...props }) => {
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: 'question' | 'answer'
|
type: 'question' | 'answer'
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
const Header = styled.h2`
|
const Header = styled.h2`
|
||||||
color: ${(props: Props) =>
|
color: ${(props: Props) =>
|
||||||
props.type === 'question'
|
props.type === 'question' ? props.design.colors.question : props.design.colors.answer};
|
||||||
? props.design.colors.questionColor
|
|
||||||
: props.design.colors.answerColor};
|
|
||||||
`
|
`
|
||||||
|
|
||||||
export const StyledH2: React.FC<Props> = ({ children, ...props }) => {
|
export const StyledH2: React.FC<Props> = ({ children, ...props }) => {
|
||||||
|
|||||||
@ -2,17 +2,17 @@ import { Input } from 'antd'
|
|||||||
import { InputProps } from 'antd/lib/input/Input'
|
import { InputProps } from 'antd/lib/input/Input'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { transparentize } from './color.change'
|
import { transparentize } from './color.change'
|
||||||
|
|
||||||
interface Props extends InputProps {
|
interface Props extends InputProps {
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(Input)`
|
const Field = styled(Input)`
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
background: none !important;
|
background: none !important;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
@ -20,12 +20,12 @@ const Field = styled(Input)`
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
|
outline: ${(props: Props) => props.design.colors.answer} auto 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ant-input-affix-wrapper {
|
&.ant-input-affix-wrapper {
|
||||||
@ -34,15 +34,15 @@ const Field = styled(Input)`
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
|
color: ${(props: Props) => transparentize(props.design.colors.answer, 60)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown'
|
import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { lighten } from './color.change'
|
import { lighten } from './color.change'
|
||||||
|
|
||||||
interface Props extends ReactMarkdownProps {
|
interface Props extends ReactMarkdownProps {
|
||||||
type: 'question' | 'answer'
|
type: 'question' | 'answer'
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
const getColor = (props: Props) =>
|
const getColor = (props: Props) =>
|
||||||
props.type === 'question' ? props.design.colors.questionColor : props.design.colors.answerColor
|
props.type === 'question' ? props.design.colors.question : props.design.colors.answer
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
||||||
const Markdown = styled(ReactMarkdown)`
|
const Markdown = styled(ReactMarkdown)`
|
||||||
|
|||||||
@ -2,17 +2,17 @@ import { InputNumber } from 'antd'
|
|||||||
import { InputNumberProps } from 'antd/lib/input-number'
|
import { InputNumberProps } from 'antd/lib/input-number'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { transparentize } from './color.change'
|
import { transparentize } from './color.change'
|
||||||
|
|
||||||
interface Props extends InputNumberProps {
|
interface Props extends InputNumberProps {
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(InputNumber)`
|
const Field = styled(InputNumber)`
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
background: none !important;
|
background: none !important;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
@ -21,12 +21,12 @@ const Field = styled(InputNumber)`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
|
outline: ${(props: Props) => props.design.colors.answer} auto 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ant-input-number {
|
&.ant-input-number {
|
||||||
@ -35,15 +35,15 @@ const Field = styled(InputNumber)`
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
|
color: ${(props: Props) => transparentize(props.design.colors.answer, 60)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type: 'question' | 'answer'
|
type: 'question' | 'answer'
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
|
||||||
const Paragraph = styled.p`
|
const Paragraph = styled.p`
|
||||||
color: ${(props: Props) =>
|
color: ${(props: Props) =>
|
||||||
props.type === 'question'
|
props.type === 'question' ? props.design.colors.question : props.design.colors.answer};
|
||||||
? props.design.colors.questionColor
|
|
||||||
: props.design.colors.answerColor};
|
|
||||||
`
|
`
|
||||||
|
|
||||||
export const StyledP: React.FC<Props> = ({ children, ...props }) => {
|
export const StyledP: React.FC<Props> = ({ children, ...props }) => {
|
||||||
|
|||||||
@ -2,34 +2,34 @@ import { Radio } from 'antd'
|
|||||||
import { RadioProps } from 'antd/lib/radio/interface'
|
import { RadioProps } from 'antd/lib/radio/interface'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
|
|
||||||
interface Props extends RadioProps {
|
interface Props extends RadioProps {
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(Radio)`
|
const Field = styled(Radio)`
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
.ant-radio {
|
.ant-radio {
|
||||||
.ant-radio-inner {
|
.ant-radio-inner {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
background: ${(props: Props) => props.design.colors.answerColor};
|
background: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -2,18 +2,18 @@ import { Select } from 'antd'
|
|||||||
import { SelectProps } from 'antd/lib/select'
|
import { SelectProps } from 'antd/lib/select'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { transparentize } from './color.change'
|
import { transparentize } from './color.change'
|
||||||
|
|
||||||
interface Props extends SelectProps<string> {
|
interface Props extends SelectProps<string> {
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(Select)`
|
const Field = styled(Select)`
|
||||||
.ant-select-selector {
|
.ant-select-selector {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor} !important;
|
border-color: ${(props: Props) => props.design.colors.answer} !important;
|
||||||
background: none !important;
|
background: none !important;
|
||||||
border-right: none !important;
|
border-right: none !important;
|
||||||
border-top: none !important;
|
border-top: none !important;
|
||||||
@ -23,25 +23,25 @@ const Field = styled(Select)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
|
outline: ${(props: Props) => props.design.colors.answer} auto 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
|
color: ${(props: Props) => transparentize(props.design.colors.answer, 60)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,17 @@ import { Input } from 'antd'
|
|||||||
import { TextAreaProps } from 'antd/lib/input/TextArea'
|
import { TextAreaProps } from 'antd/lib/input/TextArea'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { FormDesignFragment } from '../../graphql/fragment/form.fragment'
|
import { FormPublicDesignFragment } from '../../graphql/fragment/form.public.fragment'
|
||||||
import { transparentize } from './color.change'
|
import { transparentize } from './color.change'
|
||||||
|
|
||||||
interface Props extends TextAreaProps {
|
interface Props extends TextAreaProps {
|
||||||
design: FormDesignFragment
|
design: FormPublicDesignFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
|
||||||
const Field = styled(Input.TextArea)`
|
const Field = styled(Input.TextArea)`
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
background: none !important;
|
background: none !important;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
@ -22,25 +22,25 @@ const Field = styled(Input.TextArea)`
|
|||||||
:focus {
|
:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
border-color: ${(props: Props) => props.design.colors.answerColor};
|
border-color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
|
color: ${(props: Props) => transparentize(props.design.colors.answer, 60)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.anticon {
|
.anticon {
|
||||||
color: ${(props: Props) => props.design.colors.answerColor};
|
color: ${(props: Props) => props.design.colors.answer};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useMutation } from '@apollo/react-hooks'
|
import { useMutation } from '@apollo/client'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
SUBMISSION_SET_FIELD_MUTATION,
|
SUBMISSION_SET_FIELD_MUTATION,
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import { AxiosRequestConfig } from 'axios'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ME_QUERY, MeQueryData } from '../graphql/query/me.query'
|
import { useMeQuery } from '../graphql/query/me.query'
|
||||||
import { LoadingPage } from './loading.page'
|
import { LoadingPage } from './loading.page'
|
||||||
|
|
||||||
export const clearAuth = (): void => {
|
export const clearAuth = (): void => {
|
||||||
localStorage.removeItem('access')
|
localStorage.removeItem('access')
|
||||||
localStorage.removeItem('refresh')
|
localStorage.removeItem('refresh')
|
||||||
|
|
||||||
// TODO logout on server!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setAuth = (access: string, refresh: string): void => {
|
export const setAuth = (access: string, refresh: string): void => {
|
||||||
@ -18,26 +14,6 @@ export const setAuth = (access: string, refresh: string): void => {
|
|||||||
localStorage.setItem('refresh', refresh)
|
localStorage.setItem('refresh', refresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authConfig = (config: AxiosRequestConfig = {}): AxiosRequestConfig => {
|
|
||||||
if (!config.headers) {
|
|
||||||
config.headers = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const token = localStorage.getItem('access')
|
|
||||||
// TODO check for validity / use refresh token
|
|
||||||
|
|
||||||
if (token) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
||||||
config.headers.Authorization = `Bearer ${token}`
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any
|
||||||
export const withAuth = (Component: any, roles: string[] = [], optional?: boolean): React.FC => {
|
export const withAuth = (Component: any, roles: string[] = [], optional?: boolean): React.FC => {
|
||||||
// eslint-disable-next-line react/display-name
|
// eslint-disable-next-line react/display-name
|
||||||
@ -45,7 +21,7 @@ export const withAuth = (Component: any, roles: string[] = [], optional?: boolea
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [access, setAccess] = useState(false)
|
const [access, setAccess] = useState(false)
|
||||||
const { loading, data, error } = useQuery<MeQueryData>(ME_QUERY)
|
const { loading, data, error } = useMeQuery()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (roles.length === 0) {
|
if (roles.length === 0) {
|
||||||
|
|||||||
8
doc/environment.md
Normal file
8
doc/environment.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Environment Variables
|
||||||
|
|
||||||
|
| Name | Default Value | Description |
|
||||||
|
| ---- | ------------- | ----------- |
|
||||||
|
| ENDPOINT | `/graphql` | Path to graphql api endpoint |
|
||||||
|
| SERVER_ENDPOINT | *ENDPOINT* | if endpoint is relative it should point to a resolvable url of graphql api endpoint |
|
||||||
|
| MAIN_BACKGROUND | *not set* | background color of home page |
|
||||||
|
| SPA | `false` | dependent on the build mode this must be set to true to have working routing
|
||||||
45
graphql/client.ts
Normal file
45
graphql/client.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client'
|
||||||
|
import { setContext } from '@apollo/client/link/context'
|
||||||
|
import 'isomorphic-fetch'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
import { NextConfigType } from '../next.config.type'
|
||||||
|
|
||||||
|
let client: ApolloClient<any>
|
||||||
|
|
||||||
|
const getClient = (): ApolloClient<any> => {
|
||||||
|
if (!client) {
|
||||||
|
const config = getConfig() as NextConfigType
|
||||||
|
|
||||||
|
if (!config) return client
|
||||||
|
|
||||||
|
const { publicRuntimeConfig, serverRuntimeConfig } = config
|
||||||
|
|
||||||
|
client = new ApolloClient({
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
link: from([
|
||||||
|
setContext((request, context) => {
|
||||||
|
const headers: { [key: string]: string } = {}
|
||||||
|
|
||||||
|
if (process.browser) {
|
||||||
|
const access = localStorage.getItem('access')
|
||||||
|
|
||||||
|
if (access) {
|
||||||
|
headers.authorization = `Bearer ${access}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new HttpLink({
|
||||||
|
uri: serverRuntimeConfig.endpoint || publicRuntimeConfig.endpoint,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getClient
|
||||||
@ -1,209 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminFormPageFragment {
|
|
||||||
show: boolean
|
|
||||||
title?: string
|
|
||||||
paragraph?: string
|
|
||||||
buttonText?: string
|
|
||||||
buttons: {
|
|
||||||
url?: string
|
|
||||||
action?: string
|
|
||||||
text?: string
|
|
||||||
bgColor?: string
|
|
||||||
color?: string
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormFieldOptionFragment {
|
|
||||||
key?: string
|
|
||||||
title?: string
|
|
||||||
value: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormFieldOptionKeysFragment {
|
|
||||||
[key: string]: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormFieldLogicJumpFragment {
|
|
||||||
fieldA?: string
|
|
||||||
valueB?: string
|
|
||||||
expressionString?: string
|
|
||||||
jumpTo?: string
|
|
||||||
enabled: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormFieldFragment {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
slug?: string
|
|
||||||
type: string
|
|
||||||
description: string
|
|
||||||
required: boolean
|
|
||||||
value: string
|
|
||||||
|
|
||||||
options: AdminFormFieldOptionFragment[]
|
|
||||||
optionKeys?: AdminFormFieldOptionKeysFragment
|
|
||||||
|
|
||||||
logicJump: AdminFormFieldLogicJumpFragment
|
|
||||||
|
|
||||||
rating?: {
|
|
||||||
steps?: number
|
|
||||||
shape?: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormHookFragment {
|
|
||||||
id: string
|
|
||||||
enabled: boolean
|
|
||||||
url?: string
|
|
||||||
format?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormFragment {
|
|
||||||
id?: string
|
|
||||||
title: string
|
|
||||||
created: string
|
|
||||||
lastModified?: string
|
|
||||||
language: string
|
|
||||||
showFooter: boolean
|
|
||||||
isLive: boolean
|
|
||||||
fields: AdminFormFieldFragment[]
|
|
||||||
hooks: AdminFormHookFragment[]
|
|
||||||
selfNotifications: {
|
|
||||||
enabled: boolean
|
|
||||||
subject?: string
|
|
||||||
htmlTemplate?: string
|
|
||||||
fromField?: string
|
|
||||||
toEmail?: string
|
|
||||||
}
|
|
||||||
respondentNotifications: {
|
|
||||||
enabled: boolean
|
|
||||||
subject?: string
|
|
||||||
htmlTemplate?: string
|
|
||||||
toField?: string
|
|
||||||
fromEmail?: string
|
|
||||||
}
|
|
||||||
design: {
|
|
||||||
colors: {
|
|
||||||
backgroundColor: string
|
|
||||||
questionColor: string
|
|
||||||
answerColor: string
|
|
||||||
buttonColor: string
|
|
||||||
buttonTextColor: string
|
|
||||||
}
|
|
||||||
font?: string
|
|
||||||
}
|
|
||||||
startPage: AdminFormPageFragment
|
|
||||||
endPage: AdminFormPageFragment
|
|
||||||
admin: {
|
|
||||||
id: string
|
|
||||||
username: string
|
|
||||||
email: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_FORM_FRAGMENT = gql`
|
|
||||||
fragment AdminForm on Form {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
created
|
|
||||||
lastModified
|
|
||||||
language
|
|
||||||
showFooter
|
|
||||||
isLive
|
|
||||||
|
|
||||||
hooks {
|
|
||||||
id
|
|
||||||
enabled
|
|
||||||
format
|
|
||||||
url
|
|
||||||
}
|
|
||||||
|
|
||||||
fields {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
type
|
|
||||||
description
|
|
||||||
required
|
|
||||||
value
|
|
||||||
|
|
||||||
options {
|
|
||||||
key
|
|
||||||
title
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
logicJump {
|
|
||||||
fieldA
|
|
||||||
valueB
|
|
||||||
expressionString
|
|
||||||
jumpTo
|
|
||||||
enabled
|
|
||||||
}
|
|
||||||
rating {
|
|
||||||
steps
|
|
||||||
shape
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selfNotifications {
|
|
||||||
enabled
|
|
||||||
subject
|
|
||||||
htmlTemplate
|
|
||||||
fromField
|
|
||||||
toEmail
|
|
||||||
}
|
|
||||||
respondentNotifications {
|
|
||||||
enabled
|
|
||||||
subject
|
|
||||||
htmlTemplate
|
|
||||||
toField
|
|
||||||
fromEmail
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
admin {
|
|
||||||
id
|
|
||||||
username
|
|
||||||
email
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface AdminProfileFragment {
|
export interface AdminProfileFragment {
|
||||||
id: string
|
id: string
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface AdminUserFragment {
|
export interface AdminUserFragment {
|
||||||
id: string
|
id: string
|
||||||
|
|||||||
@ -1,32 +1,41 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface FormPageFragment {
|
export interface FormPageFragment {
|
||||||
|
id: string
|
||||||
show: boolean
|
show: boolean
|
||||||
title?: string
|
title?: string
|
||||||
paragraph?: string
|
paragraph?: string
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
buttons: {
|
buttons: {
|
||||||
|
id: string
|
||||||
url?: string
|
url?: string
|
||||||
action?: string
|
action?: string
|
||||||
text?: string
|
text?: string
|
||||||
bgColor?: string
|
bgColor?: string
|
||||||
activeColor?: string
|
|
||||||
color?: string
|
color?: string
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormFieldOptionFragment {
|
export interface FormFieldOptionFragment {
|
||||||
|
id: string
|
||||||
key?: string
|
key?: string
|
||||||
title?: string
|
title?: string
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormFieldLogicJumpFragment {
|
export interface FormFieldOptionKeysFragment {
|
||||||
fieldA?: string
|
[key: string]: string
|
||||||
valueB?: string
|
}
|
||||||
expressionString?: string
|
|
||||||
jumpTo?: string
|
export interface FormFieldLogicFragment {
|
||||||
|
id: string
|
||||||
|
action: string
|
||||||
|
formula: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
|
jumpTo?: string
|
||||||
|
require?: boolean
|
||||||
|
visible?: boolean
|
||||||
|
disable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormFieldFragment {
|
export interface FormFieldFragment {
|
||||||
@ -39,8 +48,9 @@ export interface FormFieldFragment {
|
|||||||
value: string
|
value: string
|
||||||
|
|
||||||
options: FormFieldOptionFragment[]
|
options: FormFieldOptionFragment[]
|
||||||
|
optionKeys?: FormFieldOptionKeysFragment
|
||||||
|
|
||||||
logicJump: FormFieldLogicJumpFragment
|
logic: FormFieldLogicFragment[]
|
||||||
|
|
||||||
rating?: {
|
rating?: {
|
||||||
steps?: number
|
steps?: number
|
||||||
@ -48,36 +58,70 @@ export interface FormFieldFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormDesignFragment {
|
export interface FormHookFragment {
|
||||||
colors: {
|
id: string
|
||||||
backgroundColor: string
|
enabled: boolean
|
||||||
questionColor: string
|
url?: string
|
||||||
answerColor: string
|
format?: string
|
||||||
buttonColor: string
|
|
||||||
buttonActiveColor: string
|
|
||||||
buttonTextColor: string
|
|
||||||
}
|
}
|
||||||
font?: string
|
|
||||||
|
export interface FormNotificationFragment {
|
||||||
|
id: string
|
||||||
|
enabled: boolean
|
||||||
|
subject?: string
|
||||||
|
htmlTemplate?: string
|
||||||
|
toField?: string
|
||||||
|
toEmail?: string
|
||||||
|
fromField?: string
|
||||||
|
fromEmail?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormFragment {
|
export interface FormFragment {
|
||||||
id?: string
|
id?: string
|
||||||
title: string
|
title: string
|
||||||
created: string
|
created: string
|
||||||
|
lastModified?: string
|
||||||
language: string
|
language: string
|
||||||
showFooter: boolean
|
showFooter: boolean
|
||||||
|
isLive: boolean
|
||||||
fields: FormFieldFragment[]
|
fields: FormFieldFragment[]
|
||||||
design: FormDesignFragment
|
hooks: FormHookFragment[]
|
||||||
|
notifications: FormNotificationFragment[]
|
||||||
|
design: {
|
||||||
|
colors: {
|
||||||
|
background: string
|
||||||
|
question: string
|
||||||
|
answer: string
|
||||||
|
button: string
|
||||||
|
buttonText: string
|
||||||
|
}
|
||||||
|
font?: string
|
||||||
|
}
|
||||||
startPage: FormPageFragment
|
startPage: FormPageFragment
|
||||||
endPage: FormPageFragment
|
endPage: FormPageFragment
|
||||||
|
admin: {
|
||||||
|
id: string
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FORM_FRAGMENT = gql`
|
export const FORM_FRAGMENT = gql`
|
||||||
fragment Form on Form {
|
fragment Form on Form {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
|
created
|
||||||
|
lastModified
|
||||||
language
|
language
|
||||||
showFooter
|
showFooter
|
||||||
|
isLive
|
||||||
|
|
||||||
|
hooks {
|
||||||
|
id
|
||||||
|
enabled
|
||||||
|
format
|
||||||
|
url
|
||||||
|
}
|
||||||
|
|
||||||
fields {
|
fields {
|
||||||
id
|
id
|
||||||
@ -89,17 +133,21 @@ export const FORM_FRAGMENT = gql`
|
|||||||
value
|
value
|
||||||
|
|
||||||
options {
|
options {
|
||||||
|
id
|
||||||
key
|
key
|
||||||
title
|
title
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
logicJump {
|
logic {
|
||||||
fieldA
|
id
|
||||||
valueB
|
action
|
||||||
expressionString
|
formula
|
||||||
jumpTo
|
|
||||||
enabled
|
enabled
|
||||||
|
jumpTo
|
||||||
|
require
|
||||||
|
visible
|
||||||
|
disable
|
||||||
}
|
}
|
||||||
rating {
|
rating {
|
||||||
steps
|
steps
|
||||||
@ -107,24 +155,36 @@ export const FORM_FRAGMENT = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifications {
|
||||||
|
id
|
||||||
|
enabled
|
||||||
|
subject
|
||||||
|
htmlTemplate
|
||||||
|
fromField
|
||||||
|
fromEmail
|
||||||
|
toField
|
||||||
|
toEmail
|
||||||
|
}
|
||||||
|
|
||||||
design {
|
design {
|
||||||
colors {
|
colors {
|
||||||
backgroundColor
|
background
|
||||||
questionColor
|
question
|
||||||
answerColor
|
answer
|
||||||
buttonColor
|
button
|
||||||
buttonActiveColor
|
buttonActive
|
||||||
buttonTextColor
|
buttonText
|
||||||
}
|
}
|
||||||
font
|
font
|
||||||
}
|
}
|
||||||
|
|
||||||
startPage {
|
startPage {
|
||||||
|
id
|
||||||
show
|
show
|
||||||
title
|
title
|
||||||
paragraph
|
paragraph
|
||||||
buttonText
|
buttonText
|
||||||
buttons {
|
buttons {
|
||||||
|
id
|
||||||
url
|
url
|
||||||
action
|
action
|
||||||
text
|
text
|
||||||
@ -133,13 +193,14 @@ export const FORM_FRAGMENT = gql`
|
|||||||
color
|
color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endPage {
|
endPage {
|
||||||
|
id
|
||||||
show
|
show
|
||||||
title
|
title
|
||||||
paragraph
|
paragraph
|
||||||
buttonText
|
buttonText
|
||||||
buttons {
|
buttons {
|
||||||
|
id
|
||||||
url
|
url
|
||||||
action
|
action
|
||||||
text
|
text
|
||||||
@ -148,5 +209,10 @@ export const FORM_FRAGMENT = gql`
|
|||||||
color
|
color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
admin {
|
||||||
|
id
|
||||||
|
username
|
||||||
|
email
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
31
graphql/fragment/form.pager.fragment.ts
Normal file
31
graphql/fragment/form.pager.fragment.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
export interface FormPagerFragment {
|
||||||
|
id: string
|
||||||
|
created: string
|
||||||
|
lastModified?: string
|
||||||
|
title: string
|
||||||
|
isLive: boolean
|
||||||
|
language: string
|
||||||
|
admin: {
|
||||||
|
id: string
|
||||||
|
email: string
|
||||||
|
username: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FORM_PAGER_FRAGMENT = gql`
|
||||||
|
fragment Form on Form {
|
||||||
|
id
|
||||||
|
created
|
||||||
|
lastModified
|
||||||
|
title
|
||||||
|
isLive
|
||||||
|
language
|
||||||
|
admin {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
173
graphql/fragment/form.public.fragment.ts
Normal file
173
graphql/fragment/form.public.fragment.ts
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
export interface FormPublicPageFragment {
|
||||||
|
id: string
|
||||||
|
show: boolean
|
||||||
|
title?: string
|
||||||
|
paragraph?: string
|
||||||
|
buttonText?: string
|
||||||
|
buttons: {
|
||||||
|
id: string
|
||||||
|
url?: string
|
||||||
|
action?: string
|
||||||
|
text?: string
|
||||||
|
bgColor?: string
|
||||||
|
activeColor?: string
|
||||||
|
color?: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormPublicFieldOptionFragment {
|
||||||
|
key?: string
|
||||||
|
title?: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormPublicFieldLogicFragment {
|
||||||
|
id: string
|
||||||
|
action: string
|
||||||
|
formula: string
|
||||||
|
jumpTo?: string
|
||||||
|
require?: boolean
|
||||||
|
visible?: boolean
|
||||||
|
disable?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormPublicFieldFragment {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
slug?: string
|
||||||
|
type: string
|
||||||
|
description: string
|
||||||
|
required: boolean
|
||||||
|
value: string
|
||||||
|
|
||||||
|
options: FormPublicFieldOptionFragment[]
|
||||||
|
|
||||||
|
logic: FormPublicFieldLogicFragment[]
|
||||||
|
|
||||||
|
rating?: {
|
||||||
|
steps?: number
|
||||||
|
shape?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormPublicDesignFragment {
|
||||||
|
colors: {
|
||||||
|
background: string
|
||||||
|
question: string
|
||||||
|
answer: string
|
||||||
|
button: string
|
||||||
|
buttonActive: string
|
||||||
|
buttonText: string
|
||||||
|
}
|
||||||
|
font?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormPublicFragment {
|
||||||
|
id?: string
|
||||||
|
title: string
|
||||||
|
created: string
|
||||||
|
language: string
|
||||||
|
showFooter: boolean
|
||||||
|
fields: FormPublicFieldFragment[]
|
||||||
|
design: FormPublicDesignFragment
|
||||||
|
startPage: FormPublicPageFragment
|
||||||
|
endPage: FormPublicPageFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FORM_PUBLIC_FRAGMENT = gql`
|
||||||
|
fragment Form on Form {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
language
|
||||||
|
showFooter
|
||||||
|
|
||||||
|
fields {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
type
|
||||||
|
description
|
||||||
|
required
|
||||||
|
value
|
||||||
|
|
||||||
|
logic {
|
||||||
|
id
|
||||||
|
formula
|
||||||
|
action
|
||||||
|
disable
|
||||||
|
jumpTo
|
||||||
|
require
|
||||||
|
visible
|
||||||
|
}
|
||||||
|
|
||||||
|
options {
|
||||||
|
id
|
||||||
|
key
|
||||||
|
title
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
logic {
|
||||||
|
id
|
||||||
|
action
|
||||||
|
formula
|
||||||
|
jumpTo
|
||||||
|
require
|
||||||
|
visible
|
||||||
|
disable
|
||||||
|
}
|
||||||
|
rating {
|
||||||
|
steps
|
||||||
|
shape
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
design {
|
||||||
|
colors {
|
||||||
|
background
|
||||||
|
question
|
||||||
|
answer
|
||||||
|
button
|
||||||
|
buttonActive
|
||||||
|
buttonText
|
||||||
|
}
|
||||||
|
font
|
||||||
|
}
|
||||||
|
|
||||||
|
startPage {
|
||||||
|
id
|
||||||
|
show
|
||||||
|
title
|
||||||
|
paragraph
|
||||||
|
buttonText
|
||||||
|
buttons {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
action
|
||||||
|
text
|
||||||
|
bgColor
|
||||||
|
activeColor
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endPage {
|
||||||
|
id
|
||||||
|
show
|
||||||
|
title
|
||||||
|
paragraph
|
||||||
|
buttonText
|
||||||
|
buttons {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
action
|
||||||
|
text
|
||||||
|
bgColor
|
||||||
|
activeColor
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -1,16 +1,61 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
interface SubmissionFragmentFormField {
|
||||||
|
title: string
|
||||||
|
required: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SubmissionFragmentField {
|
||||||
|
id: string
|
||||||
|
value: string
|
||||||
|
type: string
|
||||||
|
|
||||||
|
field?: SubmissionFragmentFormField
|
||||||
|
}
|
||||||
|
|
||||||
export interface SubmissionFragment {
|
export interface SubmissionFragment {
|
||||||
id?: string
|
id: string
|
||||||
title: string
|
|
||||||
created: string
|
created: string
|
||||||
|
lastModified?: string
|
||||||
|
percentageComplete: number
|
||||||
|
timeElapsed: number
|
||||||
|
geoLocation: {
|
||||||
|
country: string
|
||||||
|
city: string
|
||||||
|
}
|
||||||
|
device: {
|
||||||
|
type: string
|
||||||
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FORM_FRAGMENT = gql`
|
fields: SubmissionFragmentField[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SUBMISSION_FRAGMENT = gql`
|
||||||
fragment Submission on Submission {
|
fragment Submission on Submission {
|
||||||
id
|
id
|
||||||
|
created
|
||||||
|
lastModified
|
||||||
|
percentageComplete
|
||||||
|
timeElapsed
|
||||||
|
geoLocation {
|
||||||
|
country
|
||||||
|
city
|
||||||
|
}
|
||||||
|
device {
|
||||||
|
type
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
fields {
|
||||||
|
id
|
||||||
|
value
|
||||||
|
type
|
||||||
|
|
||||||
|
field {
|
||||||
title
|
title
|
||||||
language
|
required
|
||||||
showFooter
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
19
graphql/fragment/user.pager.fragment.ts
Normal file
19
graphql/fragment/user.pager.fragment.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
export interface UserPagerFragment {
|
||||||
|
id: string
|
||||||
|
roles: string[]
|
||||||
|
verifiedEmail: boolean
|
||||||
|
email: string
|
||||||
|
created: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const USER_PAGER_FRAGMENT = gql`
|
||||||
|
fragment User on User {
|
||||||
|
id
|
||||||
|
roles
|
||||||
|
verifiedEmail
|
||||||
|
email
|
||||||
|
created
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
import { ADMIN_FORM_FRAGMENT, AdminFormFragment } from '../fragment/admin.form.fragment'
|
|
||||||
|
|
||||||
export interface AdminFormCreateMutationData {
|
|
||||||
form: AdminFormFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormCreateMutationVariables {
|
|
||||||
form: AdminFormFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_FORM_CREATE_MUTATION = gql`
|
|
||||||
mutation update($form: FormCreateInput!) {
|
|
||||||
form: createForm(form: $form) {
|
|
||||||
...AdminForm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${ADMIN_FORM_FRAGMENT}
|
|
||||||
`
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminFormDeleteMutationData {
|
|
||||||
form: {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormDeleteMutationVariables {
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_FORM_DELETE_MUTATION = gql`
|
|
||||||
mutation delete($id: ID!) {
|
|
||||||
form: deleteForm(id: $id) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
import { ADMIN_FORM_FRAGMENT, AdminFormFragment } from '../fragment/admin.form.fragment'
|
|
||||||
|
|
||||||
export interface AdminFormUpdateMutationData {
|
|
||||||
form: AdminFormFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormUpdateMutationVariables {
|
|
||||||
form: AdminFormFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_FORM_UPDATE_MUTATION = gql`
|
|
||||||
mutation update($form: FormUpdateInput!) {
|
|
||||||
form: updateForm(form: $form) {
|
|
||||||
...AdminForm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${ADMIN_FORM_FRAGMENT}
|
|
||||||
`
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
import { ADMIN_PROFILE_FRAGMENT } from '../fragment/admin.profile.fragment'
|
|
||||||
import { AdminUserFragment } from '../fragment/admin.user.fragment'
|
|
||||||
|
|
||||||
export interface AdminProfileUpdateMutationData {
|
|
||||||
user: AdminUserFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminProfileUpdateMutationVariables {
|
|
||||||
user: AdminUserFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_PROFILE_UPDATE_MUTATION = gql`
|
|
||||||
mutation update($user: ProfileUpdateInput!) {
|
|
||||||
form: updateProfile(user: $user) {
|
|
||||||
...AdminProfile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${ADMIN_PROFILE_FRAGMENT}
|
|
||||||
`
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminUserDeleteMutationData {
|
|
||||||
form: {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminUserDeleteMutationVariables {
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_USER_DELETE_MUTATION = gql`
|
|
||||||
mutation delete($id: ID!) {
|
|
||||||
form: deleteUser(id: $id) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment'
|
|
||||||
|
|
||||||
export interface AdminUserUpdateMutationData {
|
|
||||||
user: AdminUserFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminUserUpdateMutationVariables {
|
|
||||||
user: AdminUserFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_USER_UPDATE_MUTATION = gql`
|
|
||||||
mutation update($user: UserUpdateInput!) {
|
|
||||||
form: updateUser(user: $user) {
|
|
||||||
...AdminUser
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${ADMIN_USER_FRAGMENT}
|
|
||||||
`
|
|
||||||
30
graphql/mutation/form.create.mutation.ts
Normal file
30
graphql/mutation/form.create.mutation.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
form: FormFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
form: {
|
||||||
|
isLive: boolean
|
||||||
|
language: string
|
||||||
|
showFooter?: boolean
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MUTATION = gql`
|
||||||
|
mutation update($form: FormCreateInput!) {
|
||||||
|
form: createForm(form: $form) {
|
||||||
|
...Form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FORM_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useFormCreateMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
24
graphql/mutation/form.delete.mutation.ts
Normal file
24
graphql/mutation/form.delete.mutation.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
form: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const MUTATION = gql`
|
||||||
|
mutation delete($id: ID!) {
|
||||||
|
form: deleteForm(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useFormDeleteMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
25
graphql/mutation/form.update.mutation.ts
Normal file
25
graphql/mutation/form.update.mutation.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
form: FormFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
form: FormFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
const MUTATION = gql`
|
||||||
|
mutation update($form: FormUpdateInput!) {
|
||||||
|
form: updateForm(form: $form) {
|
||||||
|
...Form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FORM_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useFormUpdateMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface LoginMutationData {
|
export interface LoginMutationData {
|
||||||
tokens: {
|
tokens: {
|
||||||
|
|||||||
34
graphql/mutation/profile.update.mutation.ts
Normal file
34
graphql/mutation/profile.update.mutation.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { ADMIN_PROFILE_FRAGMENT } from '../fragment/admin.profile.fragment'
|
||||||
|
import { AdminUserFragment } from '../fragment/admin.user.fragment'
|
||||||
|
|
||||||
|
export interface Data {
|
||||||
|
user: AdminUserFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Variables {
|
||||||
|
user: {
|
||||||
|
email?: string
|
||||||
|
firstName?: string
|
||||||
|
id: string
|
||||||
|
language?: string
|
||||||
|
lastName?: string
|
||||||
|
password?: string
|
||||||
|
username?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MUTATION = gql`
|
||||||
|
mutation update($user: ProfileUpdateInput!) {
|
||||||
|
form: updateProfile(user: $user) {
|
||||||
|
...AdminProfile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${ADMIN_PROFILE_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useProfileUpdateMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface RegisterMutationData {
|
interface Data {
|
||||||
tokens: {
|
tokens: {
|
||||||
access: string
|
access: string
|
||||||
refresh: string
|
refresh: string
|
||||||
@ -13,11 +14,11 @@ export interface RegisterUserData {
|
|||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RegisterMutationVariables {
|
interface Variables {
|
||||||
user: RegisterUserData
|
user: RegisterUserData
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REGISTER_MUTATION = gql`
|
const MUTATION = gql`
|
||||||
mutation register($user: UserCreateInput!) {
|
mutation register($user: UserCreateInput!) {
|
||||||
tokens: authRegister(user: $user) {
|
tokens: authRegister(user: $user) {
|
||||||
access: accessToken
|
access: accessToken
|
||||||
@ -25,3 +26,7 @@ export const REGISTER_MUTATION = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const useRegisterMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export const SUBMISSION_FINISH_MUTATION = gql`
|
export const SUBMISSION_FINISH_MUTATION = gql`
|
||||||
mutation start($submission: ID!, $field: SubmissionSetFieldInput!) {
|
mutation start($submission: ID!, $field: SubmissionSetFieldInput!) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface SubmissionSetFieldMutationData {
|
export interface SubmissionSetFieldMutationData {
|
||||||
submission: {
|
submission: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface SubmissionStartMutationData {
|
export interface SubmissionStartMutationData {
|
||||||
submission: {
|
submission: {
|
||||||
|
|||||||
24
graphql/mutation/user.delete.mutation.ts
Normal file
24
graphql/mutation/user.delete.mutation.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
form: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const MUTATION = gql`
|
||||||
|
mutation delete($id: ID!) {
|
||||||
|
form: deleteUser(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useUserDeleteMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
25
graphql/mutation/user.update.mutation.ts
Normal file
25
graphql/mutation/user.update.mutation.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { MutationHookOptions, MutationTuple, useMutation } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
user: AdminUserFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
user: AdminUserFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
const MUTATION = gql`
|
||||||
|
mutation update($user: UserUpdateInput!) {
|
||||||
|
form: updateUser(user: $user) {
|
||||||
|
...AdminUser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${ADMIN_USER_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useUserUpdateMutation = (
|
||||||
|
data?: MutationHookOptions<Data, Variables>
|
||||||
|
): MutationTuple<Data, Variables> => useMutation<Data, Variables>(MUTATION, data)
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
import { ADMIN_FORM_FRAGMENT, AdminFormFragment } from '../fragment/admin.form.fragment'
|
|
||||||
|
|
||||||
export interface AdminFormQueryData {
|
|
||||||
form: AdminFormFragment
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminFormQueryVariables {
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_FORM_QUERY = gql`
|
|
||||||
query form($id: ID!) {
|
|
||||||
form: getFormById(id: $id) {
|
|
||||||
...AdminForm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${ADMIN_FORM_FRAGMENT}
|
|
||||||
`
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminPagerFormEntryAdminQueryData {
|
|
||||||
id: string
|
|
||||||
email: string
|
|
||||||
username: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerFormEntryQueryData {
|
|
||||||
id: string
|
|
||||||
created: string
|
|
||||||
lastModified?: string
|
|
||||||
title: string
|
|
||||||
isLive: boolean
|
|
||||||
language: string
|
|
||||||
admin: AdminPagerFormEntryAdminQueryData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerFormQueryData {
|
|
||||||
pager: {
|
|
||||||
entries: AdminPagerFormEntryQueryData[]
|
|
||||||
|
|
||||||
total: number
|
|
||||||
limit: number
|
|
||||||
start: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerFormQueryVariables {
|
|
||||||
start?: number
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_PAGER_FORM_QUERY = gql`
|
|
||||||
query pager($start: Int, $limit: Int) {
|
|
||||||
pager: listForms(start: $start, limit: $limit) {
|
|
||||||
entries {
|
|
||||||
id
|
|
||||||
created
|
|
||||||
lastModified
|
|
||||||
title
|
|
||||||
isLive
|
|
||||||
language
|
|
||||||
admin {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total
|
|
||||||
limit
|
|
||||||
start
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionFormFieldQueryData {
|
|
||||||
title: string
|
|
||||||
required: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionFormQueryData {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
isLive: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionEntryFieldQueryData {
|
|
||||||
id: string
|
|
||||||
value: string
|
|
||||||
type: string
|
|
||||||
|
|
||||||
field?: AdminPagerSubmissionFormFieldQueryData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionEntryQueryData {
|
|
||||||
id: string
|
|
||||||
created: string
|
|
||||||
lastModified?: string
|
|
||||||
percentageComplete: number
|
|
||||||
timeElapsed: number
|
|
||||||
geoLocation: {
|
|
||||||
country: string
|
|
||||||
city: string
|
|
||||||
}
|
|
||||||
device: {
|
|
||||||
type: string
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
fields: AdminPagerSubmissionEntryFieldQueryData[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionQueryData {
|
|
||||||
pager: {
|
|
||||||
entries: AdminPagerSubmissionEntryQueryData[]
|
|
||||||
|
|
||||||
total: number
|
|
||||||
limit: number
|
|
||||||
start: number
|
|
||||||
}
|
|
||||||
|
|
||||||
form: AdminPagerSubmissionFormQueryData
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerSubmissionQueryVariables {
|
|
||||||
form: string
|
|
||||||
start?: number
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_PAGER_SUBMISSION_QUERY = gql`
|
|
||||||
query pager($form: ID!, $start: Int, $limit: Int) {
|
|
||||||
form: getFormById(id: $form) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
isLive
|
|
||||||
}
|
|
||||||
|
|
||||||
pager: listSubmissions(form: $form, start: $start, limit: $limit) {
|
|
||||||
entries {
|
|
||||||
id
|
|
||||||
created
|
|
||||||
lastModified
|
|
||||||
percentageComplete
|
|
||||||
timeElapsed
|
|
||||||
geoLocation {
|
|
||||||
country
|
|
||||||
city
|
|
||||||
}
|
|
||||||
device {
|
|
||||||
type
|
|
||||||
name
|
|
||||||
}
|
|
||||||
|
|
||||||
fields {
|
|
||||||
id
|
|
||||||
value
|
|
||||||
type
|
|
||||||
|
|
||||||
field {
|
|
||||||
title
|
|
||||||
required
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total
|
|
||||||
limit
|
|
||||||
start
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import { gql } from 'apollo-boost'
|
|
||||||
|
|
||||||
export interface AdminPagerUserEntryQueryData {
|
|
||||||
id: string
|
|
||||||
roles: string[]
|
|
||||||
verifiedEmail: boolean
|
|
||||||
email: string
|
|
||||||
created: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerUserQueryData {
|
|
||||||
pager: {
|
|
||||||
entries: AdminPagerUserEntryQueryData[]
|
|
||||||
|
|
||||||
total: number
|
|
||||||
limit: number
|
|
||||||
start: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminPagerUserQueryVariables {
|
|
||||||
start?: number
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ADMIN_PAGER_USER_QUERY = gql`
|
|
||||||
query pager($start: Int, $limit: Int) {
|
|
||||||
pager: listUsers(start: $start, limit: $limit) {
|
|
||||||
entries {
|
|
||||||
id
|
|
||||||
roles
|
|
||||||
verifiedEmail
|
|
||||||
email
|
|
||||||
created
|
|
||||||
}
|
|
||||||
total
|
|
||||||
limit
|
|
||||||
start
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
import { ADMIN_PROFILE_FRAGMENT, AdminProfileFragment } from '../fragment/admin.profile.fragment'
|
import { ADMIN_PROFILE_FRAGMENT, AdminProfileFragment } from '../fragment/admin.profile.fragment'
|
||||||
|
|
||||||
export interface AdminProfileQueryData {
|
interface Data {
|
||||||
user: AdminProfileFragment
|
user: AdminProfileFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminProfileQueryVariables {}
|
export const QUERY = gql`
|
||||||
|
|
||||||
export const ADMIN_PROFILE_QUERY = gql`
|
|
||||||
query profile {
|
query profile {
|
||||||
user: me {
|
user: me {
|
||||||
...AdminProfile
|
...AdminProfile
|
||||||
@ -16,3 +15,7 @@ export const ADMIN_PROFILE_QUERY = gql`
|
|||||||
|
|
||||||
${ADMIN_PROFILE_FRAGMENT}
|
${ADMIN_PROFILE_FRAGMENT}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const useProfileQuery = (
|
||||||
|
options?: QueryHookOptions<Data, unknown>
|
||||||
|
): QueryResult<Data, unknown> => useQuery<Data, unknown>(QUERY, options)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface AdminStatisticQueryData {
|
export interface AdminStatisticQueryData {
|
||||||
forms: {
|
forms: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { gql } from '@apollo/client/core'
|
||||||
import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment'
|
import { ADMIN_USER_FRAGMENT, AdminUserFragment } from '../fragment/admin.user.fragment'
|
||||||
|
|
||||||
export interface AdminUserQueryData {
|
export interface AdminUserQueryData {
|
||||||
|
|||||||
37
graphql/query/form.pager.query.ts
Normal file
37
graphql/query/form.pager.query.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { FORM_PAGER_FRAGMENT, FormPagerFragment } from '../fragment/form.pager.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
pager: {
|
||||||
|
entries: FormPagerFragment[]
|
||||||
|
|
||||||
|
total: number
|
||||||
|
limit: number
|
||||||
|
start: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
start?: number
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY = gql`
|
||||||
|
query pager($start: Int, $limit: Int) {
|
||||||
|
pager: listForms(start: $start, limit: $limit) {
|
||||||
|
entries {
|
||||||
|
...Form
|
||||||
|
}
|
||||||
|
total
|
||||||
|
limit
|
||||||
|
start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FORM_PAGER_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useFormPagerQuery = (
|
||||||
|
options?: QueryHookOptions<Data, Variables>
|
||||||
|
): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options)
|
||||||
25
graphql/query/form.public.query.ts
Normal file
25
graphql/query/form.public.query.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { FORM_PUBLIC_FRAGMENT, FormPublicFragment } from '../fragment/form.public.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
form: FormPublicFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY = gql`
|
||||||
|
query form($id: ID!) {
|
||||||
|
form: getFormById(id: $id) {
|
||||||
|
...Form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FORM_PUBLIC_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useFormPublicQuery = (
|
||||||
|
options?: QueryHookOptions<Data, Variables>
|
||||||
|
): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options)
|
||||||
@ -1,16 +1,17 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment'
|
import { FORM_FRAGMENT, FormFragment } from '../fragment/form.fragment'
|
||||||
|
|
||||||
export interface FormQueryData {
|
export interface Data {
|
||||||
form: FormFragment
|
form: FormFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormQueryVariables {
|
interface Variables {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FORM_QUERY = gql`
|
const QUERY = gql`
|
||||||
query form($id: ID!) {
|
query getFormById($id: ID!) {
|
||||||
form: getFormById(id: $id) {
|
form: getFormById(id: $id) {
|
||||||
...Form
|
...Form
|
||||||
}
|
}
|
||||||
@ -18,3 +19,7 @@ export const FORM_QUERY = gql`
|
|||||||
|
|
||||||
${FORM_FRAGMENT}
|
${FORM_FRAGMENT}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const useFormQuery = (
|
||||||
|
options?: QueryHookOptions<Data, Variables>
|
||||||
|
): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface MeQueryData {
|
interface Data {
|
||||||
me: {
|
me: {
|
||||||
id: string
|
id: string
|
||||||
username: string
|
username: string
|
||||||
@ -8,8 +9,8 @@ export interface MeQueryData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ME_QUERY = gql`
|
const QUERY = gql`
|
||||||
query {
|
query me {
|
||||||
me {
|
me {
|
||||||
id
|
id
|
||||||
roles
|
roles
|
||||||
@ -17,3 +18,6 @@ export const ME_QUERY = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const useMeQuery = (options?: QueryHookOptions<Data, unknown>): QueryResult<Data, unknown> =>
|
||||||
|
useQuery<Data, unknown>(QUERY, options)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { gql } from 'apollo-boost'
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
|
||||||
export interface SettingsQueryData {
|
interface Data {
|
||||||
disabledSignUp: {
|
disabledSignUp: {
|
||||||
value: boolean
|
value: boolean
|
||||||
}
|
}
|
||||||
@ -12,8 +13,8 @@ export interface SettingsQueryData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SETTINGS_QUERY = gql`
|
const QUERY = gql`
|
||||||
query {
|
query settings {
|
||||||
disabledSignUp: getSetting(key: "SIGNUP_DISABLED") {
|
disabledSignUp: getSetting(key: "SIGNUP_DISABLED") {
|
||||||
value: isTrue
|
value: isTrue
|
||||||
}
|
}
|
||||||
@ -25,3 +26,7 @@ export const SETTINGS_QUERY = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const useSettingsQuery = (
|
||||||
|
options?: QueryHookOptions<Data, unknown>
|
||||||
|
): QueryResult<Data, unknown> => useQuery<Data, unknown>(QUERY, options)
|
||||||
|
|||||||
49
graphql/query/submission.pager.query.ts
Normal file
49
graphql/query/submission.pager.query.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { useImperativeQuery } from '../../components/use.imerative.query'
|
||||||
|
import { FORM_PAGER_FRAGMENT, FormPagerFragment } from '../fragment/form.pager.fragment'
|
||||||
|
import { SUBMISSION_FRAGMENT, SubmissionFragment } from '../fragment/submission.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
pager: {
|
||||||
|
entries: SubmissionFragment[]
|
||||||
|
|
||||||
|
total: number
|
||||||
|
limit: number
|
||||||
|
start: number
|
||||||
|
}
|
||||||
|
|
||||||
|
form: FormPagerFragment
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
form: string
|
||||||
|
start?: number
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY = gql`
|
||||||
|
query pager($form: ID!, $start: Int, $limit: Int) {
|
||||||
|
form: getFormById(id: $form) {
|
||||||
|
...Form
|
||||||
|
}
|
||||||
|
|
||||||
|
pager: listSubmissions(form: $form, start: $start, limit: $limit) {
|
||||||
|
entries {
|
||||||
|
...Submission
|
||||||
|
}
|
||||||
|
total
|
||||||
|
limit
|
||||||
|
start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${SUBMISSION_FRAGMENT}
|
||||||
|
${FORM_PAGER_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useSubmissionPagerQuery = (
|
||||||
|
options?: QueryHookOptions<Data, Variables>
|
||||||
|
): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options)
|
||||||
|
|
||||||
|
export const useSubmissionPagerImperativeQuery = () => useImperativeQuery<Data, Variables>(QUERY)
|
||||||
37
graphql/query/user.pager.query.ts
Normal file
37
graphql/query/user.pager.query.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { QueryHookOptions, QueryResult, useQuery } from '@apollo/client'
|
||||||
|
import { gql } from '@apollo/client/core'
|
||||||
|
import { USER_PAGER_FRAGMENT, UserPagerFragment } from '../fragment/user.pager.fragment'
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
pager: {
|
||||||
|
entries: UserPagerFragment[]
|
||||||
|
|
||||||
|
total: number
|
||||||
|
limit: number
|
||||||
|
start: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
start?: number
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY = gql`
|
||||||
|
query pager($start: Int, $limit: Int) {
|
||||||
|
pager: listUsers(start: $start, limit: $limit) {
|
||||||
|
entries {
|
||||||
|
...User
|
||||||
|
}
|
||||||
|
total
|
||||||
|
limit
|
||||||
|
start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${USER_PAGER_FRAGMENT}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useUserPagerQuery = (
|
||||||
|
options?: QueryHookOptions<Data, Variables>
|
||||||
|
): QueryResult<Data, Variables> => useQuery<Data, Variables>(QUERY, options)
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
|
"profile": "Profile",
|
||||||
"checkingCredentials": "Checking Credentials",
|
"checkingCredentials": "Checking Credentials",
|
||||||
"loadingCredentials": "Loading Credentials",
|
"loadingCredentials": "Loading Credentials",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
|
|||||||
@ -6,8 +6,12 @@ const version = p.version;
|
|||||||
module.exports = withImages({
|
module.exports = withImages({
|
||||||
poweredByHeader: false,
|
poweredByHeader: false,
|
||||||
publicRuntimeConfig: {
|
publicRuntimeConfig: {
|
||||||
endpoint: process.env.API_HOST || '/graphql',
|
endpoint: process.env.ENDPOINT || '/graphql',
|
||||||
spa: !!process.env.SPA || false,
|
spa: !!process.env.SPA || false,
|
||||||
|
mainBackground: process.env.MAIN_BACKGROUND || '#8FA2A6'
|
||||||
|
},
|
||||||
|
serverRuntimeConfig: {
|
||||||
|
endpoint: process.env.SERVER_ENDPOINT || process.env.ENDPOINT || '/graphql',
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
version,
|
version,
|
||||||
|
|||||||
10
next.config.type.ts
Normal file
10
next.config.type.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface NextConfigType {
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
endpoint: string
|
||||||
|
spa?: boolean
|
||||||
|
mainBackground?: string
|
||||||
|
}
|
||||||
|
serverRuntimeConfig: {
|
||||||
|
endpoint: string
|
||||||
|
}
|
||||||
|
}
|
||||||
87
package.json
87
package.json
@ -1,71 +1,70 @@
|
|||||||
{
|
{
|
||||||
"name": "ohmyform-react",
|
"name": "ohmyform-react",
|
||||||
"version": "0.9.8",
|
"version": "1.0.0-alpha",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start:dev": "next dev -p 4000",
|
"start:dev": "next dev -p 4000",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"lint": "eslint pages/ store/ components/ graphql/",
|
"lint": "eslint pages/ store/ components/ graphql/",
|
||||||
|
"type-check": "tsc --pretty",
|
||||||
"export": "cross-env SPA=1 next build && next export",
|
"export": "cross-env SPA=1 next build && next export",
|
||||||
"start": "next start -p $PORT",
|
"start": "next start -p $PORT",
|
||||||
"translation:sort": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node-script locales/sort.ts",
|
"translation:sort": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node-script locales/sort.ts",
|
||||||
"translation:missing": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node locales/missing.ts"
|
"translation:missing": "cross-env TS_NODE_TRANSPILE_ONLY=true ts-node locales/missing.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^4.2.2",
|
"@ant-design/icons": "^4.6.2",
|
||||||
"@apollo/client": "^3.2.0",
|
"@apollo/client": "^3.3.15",
|
||||||
"@apollo/react-common": "^3.1.4",
|
"@lifeomic/axios-fetch": "^2.0.0",
|
||||||
"@apollo/react-hooks": "^4.0.0",
|
"antd": "^4.15.3",
|
||||||
"@lifeomic/axios-fetch": "^1.4.2",
|
"axios": "^0.21.1",
|
||||||
"antd": "^4.6.2",
|
"cross-env": "^7.0.3",
|
||||||
"apollo-boost": "^0.4.9",
|
"dayjs": "^1.10.4",
|
||||||
"axios": "^0.20.0",
|
"exceljs": "^4.2.1",
|
||||||
"cross-env": "^7.0.2",
|
"graphql": "^15.5.0",
|
||||||
"dayjs": "^1.8.34",
|
"i18next": "^19.9.2",
|
||||||
"exceljs": "^4.2.0",
|
"i18next-browser-languagedetector": "^6.1.0",
|
||||||
"graphql": "^15.3.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
"i18next": "^19.7.0",
|
"next": "^10.2.0",
|
||||||
"i18next-browser-languagedetector": "^6.0.1",
|
"next-images": "^1.7.0",
|
||||||
"next": "9.5.3",
|
|
||||||
"next-images": "^1.4.1",
|
|
||||||
"next-redux-wrapper": "^6.0.2",
|
"next-redux-wrapper": "^6.0.2",
|
||||||
"react": "16.13.1",
|
"react": "^17.0.2",
|
||||||
"react-color": "^2.18.1",
|
"react-color": "^2.19.3",
|
||||||
"react-dom": "16.13.1",
|
"react-dom": "^17.0.2",
|
||||||
"react-github-button": "^0.1.11",
|
"react-github-button": "^0.1.11",
|
||||||
"react-i18next": "^11.7.2",
|
"react-i18next": "^11.8.15",
|
||||||
"react-icons": "^3.11.0",
|
"react-icons": "^3.11.0",
|
||||||
"react-id-swiper": "^4.0.0",
|
"react-id-swiper": "^4.0.0",
|
||||||
"react-markdown": "^4.3.1",
|
"react-markdown": "^4.3.1",
|
||||||
"react-redux": "^7.2.1",
|
"react-redux": "^7.2.4",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.1.0",
|
||||||
"redux-devtools-extension": "^2.13.8",
|
"redux-devtools-extension": "^2.13.9",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"sass": "^1.26.10",
|
"sass": "^1.32.12",
|
||||||
"styled-components": "^5.1.1",
|
"styled-components": "^5.2.3",
|
||||||
"swiper": "^6.1.2"
|
"swiper": "^6.5.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
"@types/lifeomic__axios-fetch": "^1.4.0",
|
"@types/lifeomic__axios-fetch": "^1.5.0",
|
||||||
"@types/node": "^14.6.2",
|
"@types/node": "^14.14.43",
|
||||||
"@types/node-fetch": "^2.5.7",
|
"@types/node-fetch": "^2.5.10",
|
||||||
"@types/react": "^16.9.49",
|
"@types/react": "^17.0.4",
|
||||||
"@types/styled-components": "^5.1.2",
|
"@types/styled-components": "^5.1.9",
|
||||||
"@types/swiper": "^5.4.0",
|
"@types/swiper": "^5.4.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||||
"@typescript-eslint/parser": "^4.0.1",
|
"@typescript-eslint/parser": "^4.22.0",
|
||||||
"commander": "^6.1.0",
|
"commander": "^6.2.1",
|
||||||
"eslint": "^7.8.1",
|
"eslint": "^7.25.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.15.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.3.1",
|
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"eslint-plugin-react": "^7.20.6",
|
"eslint-plugin-react": "^7.23.2",
|
||||||
"eslint-plugin-react-hooks": "^4.1.0",
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"prettier": "^2.1.1",
|
"prettier": "^2.1.1",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.1.1",
|
||||||
"typescript": "^4.0.2"
|
"typescript": "^4.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { ApolloProvider } from '@apollo/react-common'
|
import { ApolloProvider } from '@apollo/client'
|
||||||
import { buildAxiosFetch } from '@lifeomic/axios-fetch'
|
|
||||||
import 'antd/dist/antd.css'
|
import 'antd/dist/antd.css'
|
||||||
import { ApolloProvider as ApolloHooksProvider } from '@apollo/react-hooks'
|
|
||||||
import ApolloClient from 'apollo-boost'
|
|
||||||
import 'assets/global.scss'
|
import 'assets/global.scss'
|
||||||
import 'assets/variables.scss'
|
import 'assets/variables.scss'
|
||||||
import axios from 'axios'
|
|
||||||
import { authConfig } from 'components/with.auth'
|
|
||||||
import 'i18n'
|
import 'i18n'
|
||||||
import { AppInitialProps, AppProps } from 'next/app'
|
import { AppInitialProps } from 'next/app'
|
||||||
import getConfig from 'next/config'
|
import getConfig from 'next/config'
|
||||||
import { AppType } from 'next/dist/next-server/lib/utils'
|
import { AppType } from 'next/dist/next-server/lib/utils'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { wrapper } from 'store'
|
import { wrapper } from 'store'
|
||||||
|
import getClient from '../graphql/client'
|
||||||
|
|
||||||
const { publicRuntimeConfig } = getConfig() as {
|
const { publicRuntimeConfig } = getConfig() as {
|
||||||
publicRuntimeConfig: {
|
publicRuntimeConfig: {
|
||||||
@ -21,26 +17,14 @@ const { publicRuntimeConfig } = getConfig() as {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = new ApolloClient({
|
|
||||||
uri: publicRuntimeConfig.endpoint,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-explicit-any
|
|
||||||
fetch: buildAxiosFetch(axios as any) as any,
|
|
||||||
request: (operation): void => {
|
|
||||||
operation.setContext(authConfig())
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const App: AppType = ({ Component, pageProps }) => {
|
const App: AppType = ({ Component, pageProps }) => {
|
||||||
return (
|
return (
|
||||||
<ApolloProvider client={client}>
|
<ApolloProvider client={getClient()}>
|
||||||
{/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */}
|
|
||||||
<ApolloHooksProvider client={client as any}>
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>OhMyForm</title>
|
<title>OhMyForm</title>
|
||||||
<meta name="theme-color" content={'#4182e4'} />
|
<meta name="theme-color" content={'#4182e4'} />
|
||||||
</Head>
|
</Head>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</ApolloHooksProvider>
|
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, Form, Input, message, Tabs } from 'antd'
|
import { Button, Form, Input, message, Tabs } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import { cleanInput } from 'components/clean.input'
|
import { cleanInput } from 'components/clean.input'
|
||||||
@ -6,45 +5,37 @@ import { BaseDataTab } from 'components/form/admin/base.data.tab'
|
|||||||
import { DesignTab } from 'components/form/admin/design.tab'
|
import { DesignTab } from 'components/form/admin/design.tab'
|
||||||
import { EndPageTab } from 'components/form/admin/end.page.tab'
|
import { EndPageTab } from 'components/form/admin/end.page.tab'
|
||||||
import { FieldsTab } from 'components/form/admin/fields.tab'
|
import { FieldsTab } from 'components/form/admin/fields.tab'
|
||||||
import { RespondentNotificationsTab } from 'components/form/admin/respondent.notifications.tab'
|
import { NotificationsTab } from 'components/form/admin/notifications.tab'
|
||||||
import { SelfNotificationsTab } from 'components/form/admin/self.notifications.tab'
|
|
||||||
import { StartPageTab } from 'components/form/admin/start.page.tab'
|
import { StartPageTab } from 'components/form/admin/start.page.tab'
|
||||||
import Structure from 'components/structure'
|
import { Structure } from 'components/structure'
|
||||||
import { withAuth } from 'components/with.auth'
|
import { withAuth } from 'components/with.auth'
|
||||||
import {
|
import { useFormUpdateMutation } from 'graphql/mutation/form.update.mutation'
|
||||||
AdminFormFieldFragment,
|
|
||||||
AdminFormFieldOptionKeysFragment,
|
|
||||||
} 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'
|
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { HooksTab } from '../../../../components/form/admin/hooks.tab'
|
import { HooksTab } from '../../../../components/form/admin/hooks.tab'
|
||||||
|
import {
|
||||||
|
FormFieldFragment,
|
||||||
|
FormFieldOptionKeysFragment,
|
||||||
|
} from '../../../../graphql/fragment/form.fragment'
|
||||||
|
import { Data, useFormQuery } from '../../../../graphql/query/form.query'
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [form] = useForm()
|
const [form] = useForm()
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [fields, setFields] = useState<AdminFormFieldFragment[]>([])
|
const [fields, setFields] = useState<FormFieldFragment[]>([])
|
||||||
const [update] = useMutation<AdminFormUpdateMutationData, AdminFormUpdateMutationVariables>(
|
const [update] = useFormUpdateMutation()
|
||||||
ADMIN_FORM_UPDATE_MUTATION
|
|
||||||
)
|
|
||||||
|
|
||||||
const processNext = (next: AdminFormQueryData): AdminFormQueryData => {
|
const processNext = (next: Data) => {
|
||||||
next.form.fields = next.form.fields.map((field) => {
|
return {
|
||||||
const keys: AdminFormFieldOptionKeysFragment = {}
|
form: {
|
||||||
|
...next.form,
|
||||||
|
fields: next.form.fields.map((field) => {
|
||||||
|
const keys: FormFieldOptionKeysFragment = {}
|
||||||
|
|
||||||
field.options.forEach((option) => {
|
field.options.forEach((option) => {
|
||||||
if (option.key) {
|
if (option.key) {
|
||||||
@ -52,29 +43,28 @@ const Index: NextPage = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
field.options = field.options.filter((option) => !option.key)
|
return {
|
||||||
field.optionKeys = keys
|
...field,
|
||||||
return field
|
options: field.options.filter((option) => !option.key),
|
||||||
})
|
optionKeys: keys,
|
||||||
|
}
|
||||||
return next
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, loading } = useQuery<AdminFormQueryData, AdminFormQueryVariables>(
|
const { data, loading } = useFormQuery({
|
||||||
ADMIN_FORM_QUERY,
|
|
||||||
{
|
|
||||||
variables: {
|
variables: {
|
||||||
id: router.query.id as string,
|
id: router.query.id as string,
|
||||||
},
|
},
|
||||||
onCompleted: (next) => {
|
onCompleted: (next) => {
|
||||||
next = processNext(next)
|
const processed = processNext(next)
|
||||||
form.setFieldsValue(next)
|
form.setFieldsValue(processed)
|
||||||
setFields(next.form.fields)
|
setFields(processed.form.fields)
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
const save = async (formData: AdminFormQueryData) => {
|
const save = async (formData: Data) => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|
||||||
formData.form.fields = formData.form.fields
|
formData.form.fields = formData.form.fields
|
||||||
@ -89,6 +79,7 @@ const Index: NextPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
|
id: null, // TODO improve this
|
||||||
value: optionKeys[key],
|
value: optionKeys[key],
|
||||||
key,
|
key,
|
||||||
})
|
})
|
||||||
@ -175,15 +166,9 @@ const Index: NextPage = () => {
|
|||||||
/>
|
/>
|
||||||
<BaseDataTab key={'base_data'} tab={t('form:baseDataTab')} />
|
<BaseDataTab key={'base_data'} tab={t('form:baseDataTab')} />
|
||||||
<DesignTab key={'design'} tab={t('form:designTab')} />
|
<DesignTab key={'design'} tab={t('form:designTab')} />
|
||||||
<SelfNotificationsTab
|
<NotificationsTab
|
||||||
key={'self_notifications'}
|
key={'notifications'}
|
||||||
tab={t('form:selfNotificationsTab')}
|
tab={t('form:notificationsTab')}
|
||||||
fields={fields}
|
|
||||||
form={form}
|
|
||||||
/>
|
|
||||||
<RespondentNotificationsTab
|
|
||||||
key={'respondent_notifications'}
|
|
||||||
tab={t('form:respondentNotificationsTab')}
|
|
||||||
fields={fields}
|
fields={fields}
|
||||||
form={form}
|
form={form}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, Progress, Table } from 'antd'
|
import { Button, Progress, Table } from 'antd'
|
||||||
import { PaginationProps } from 'antd/es/pagination'
|
import { PaginationProps } from 'antd/es/pagination'
|
||||||
import { ProgressProps } from 'antd/lib/progress'
|
import { ProgressProps } from 'antd/lib/progress'
|
||||||
@ -15,13 +14,9 @@ import React, { useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ExportSubmissionAction } from '../../../../components/form/admin/export.submission.action'
|
import { ExportSubmissionAction } from '../../../../components/form/admin/export.submission.action'
|
||||||
import { SubmissionValues } from '../../../../components/form/admin/submission.values'
|
import { SubmissionValues } from '../../../../components/form/admin/submission.values'
|
||||||
import {
|
import { FormPagerFragment } from '../../../../graphql/fragment/form.pager.fragment'
|
||||||
ADMIN_PAGER_SUBMISSION_QUERY,
|
import { SubmissionFragment } from '../../../../graphql/fragment/submission.fragment'
|
||||||
AdminPagerSubmissionEntryQueryData,
|
import { useSubmissionPagerQuery } from '../../../../graphql/query/submission.pager.query'
|
||||||
AdminPagerSubmissionFormQueryData,
|
|
||||||
AdminPagerSubmissionQueryData,
|
|
||||||
AdminPagerSubmissionQueryVariables,
|
|
||||||
} from '../../../../graphql/query/admin.pager.submission.query'
|
|
||||||
|
|
||||||
const Submissions: NextPage = () => {
|
const Submissions: NextPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -29,12 +24,9 @@ const Submissions: NextPage = () => {
|
|||||||
const [pagination, setPagination] = useState<PaginationProps>({
|
const [pagination, setPagination] = useState<PaginationProps>({
|
||||||
pageSize: 25,
|
pageSize: 25,
|
||||||
})
|
})
|
||||||
const [form, setForm] = useState<AdminPagerSubmissionFormQueryData>()
|
const [form, setForm] = useState<FormPagerFragment>()
|
||||||
const [entries, setEntries] = useState<AdminPagerSubmissionEntryQueryData[]>()
|
const [entries, setEntries] = useState<SubmissionFragment[]>()
|
||||||
const { loading, refetch } = useQuery<
|
const { loading, refetch } = useSubmissionPagerQuery({
|
||||||
AdminPagerSubmissionQueryData,
|
|
||||||
AdminPagerSubmissionQueryVariables
|
|
||||||
>(ADMIN_PAGER_SUBMISSION_QUERY, {
|
|
||||||
variables: {
|
variables: {
|
||||||
form: router.query.id as string,
|
form: router.query.id as string,
|
||||||
limit: pagination.pageSize,
|
limit: pagination.pageSize,
|
||||||
@ -50,10 +42,10 @@ const Submissions: NextPage = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const columns: ColumnsType<AdminPagerSubmissionEntryQueryData> = [
|
const columns: ColumnsType<SubmissionFragment> = [
|
||||||
{
|
{
|
||||||
title: t('submission:progress'),
|
title: t('submission:progress'),
|
||||||
render(row: AdminPagerSubmissionEntryQueryData) {
|
render(_, row) {
|
||||||
const props: ProgressProps = {
|
const props: ProgressProps = {
|
||||||
status: 'active',
|
status: 'active',
|
||||||
percent: Math.round(row.percentageComplete * 100),
|
percent: Math.round(row.percentageComplete * 100),
|
||||||
|
|||||||
@ -1,31 +1,27 @@
|
|||||||
import { useMutation } from '@apollo/react-hooks'
|
|
||||||
import { Button, Form, Input, message, Tabs } from 'antd'
|
import { Button, Form, Input, message, Tabs } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
|
||||||
import { cleanInput } from 'components/clean.input'
|
import { cleanInput } from 'components/clean.input'
|
||||||
import { BaseDataTab } from 'components/form/admin/base.data.tab'
|
import { BaseDataTab } from 'components/form/admin/base.data.tab'
|
||||||
import Structure from 'components/structure'
|
import Structure from 'components/structure'
|
||||||
import { withAuth } from 'components/with.auth'
|
import { withAuth } from 'components/with.auth'
|
||||||
import { AdminFormQueryData } from 'graphql/query/admin.form.query'
|
import { FormFragment } from 'graphql/fragment/form.fragment'
|
||||||
|
import { useFormCreateMutation } from 'graphql/mutation/form.create.mutation'
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import {
|
|
||||||
ADMIN_FORM_CREATE_MUTATION,
|
interface FormData {
|
||||||
AdminFormCreateMutationData,
|
form: FormFragment
|
||||||
AdminFormCreateMutationVariables,
|
}
|
||||||
} from '../../../graphql/mutation/admin.form.create.mutation'
|
|
||||||
|
|
||||||
const Create: NextPage = () => {
|
const Create: NextPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [form] = useForm()
|
const [form] = Form.useForm<FormData>()
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [create] = useMutation<AdminFormCreateMutationData, AdminFormCreateMutationVariables>(
|
const [create] = useFormCreateMutation()
|
||||||
ADMIN_FORM_CREATE_MUTATION
|
|
||||||
)
|
|
||||||
|
|
||||||
const save = async (formData: AdminFormQueryData) => {
|
const save = async (formData: FormData) => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import {
|
|||||||
GlobalOutlined,
|
GlobalOutlined,
|
||||||
UnorderedListOutlined,
|
UnorderedListOutlined,
|
||||||
} from '@ant-design/icons/lib'
|
} from '@ant-design/icons/lib'
|
||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, message, Popconfirm, Space, Table, Tag, Tooltip } from 'antd'
|
import { Button, message, Popconfirm, Space, Table, Tag, Tooltip } from 'antd'
|
||||||
import { PaginationProps } from 'antd/es/pagination'
|
import { PaginationProps } from 'antd/es/pagination'
|
||||||
import { ColumnsType } from 'antd/lib/table/interface'
|
import { ColumnsType } from 'antd/lib/table/interface'
|
||||||
@ -13,23 +12,14 @@ import { FormIsLive } from 'components/form/admin/is.live'
|
|||||||
import Structure from 'components/structure'
|
import Structure from 'components/structure'
|
||||||
import { TimeAgo } from 'components/time.ago'
|
import { TimeAgo } from 'components/time.ago'
|
||||||
import { withAuth } from 'components/with.auth'
|
import { withAuth } from 'components/with.auth'
|
||||||
import {
|
|
||||||
ADMIN_PAGER_FORM_QUERY,
|
|
||||||
AdminPagerFormEntryAdminQueryData,
|
|
||||||
AdminPagerFormEntryQueryData,
|
|
||||||
AdminPagerFormQueryData,
|
|
||||||
AdminPagerFormQueryVariables,
|
|
||||||
} from 'graphql/query/admin.pager.form.query'
|
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useWindowSize } from '../../../components/use.window.size'
|
import { useWindowSize } from '../../../components/use.window.size'
|
||||||
import {
|
import { FormPagerFragment } from '../../../graphql/fragment/form.pager.fragment'
|
||||||
ADMIN_FORM_DELETE_MUTATION,
|
import { useFormDeleteMutation } from '../../../graphql/mutation/form.delete.mutation'
|
||||||
AdminFormDeleteMutationData,
|
import { useFormPagerQuery } from '../../../graphql/query/form.pager.query'
|
||||||
AdminFormDeleteMutationVariables,
|
|
||||||
} from '../../../graphql/mutation/admin.form.delete.mutation'
|
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -37,10 +27,8 @@ const Index: NextPage = () => {
|
|||||||
const [pagination, setPagination] = useState<PaginationProps>({
|
const [pagination, setPagination] = useState<PaginationProps>({
|
||||||
pageSize: 25,
|
pageSize: 25,
|
||||||
})
|
})
|
||||||
const [entries, setEntries] = useState<AdminPagerFormEntryQueryData[]>()
|
const [entries, setEntries] = useState<FormPagerFragment[]>()
|
||||||
const { loading, refetch } = useQuery<AdminPagerFormQueryData, AdminPagerFormQueryVariables>(
|
const { loading, refetch, error } = useFormPagerQuery({
|
||||||
ADMIN_PAGER_FORM_QUERY,
|
|
||||||
{
|
|
||||||
variables: {
|
variables: {
|
||||||
limit: pagination.pageSize,
|
limit: pagination.pageSize,
|
||||||
start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0,
|
start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0,
|
||||||
@ -52,21 +40,17 @@ const Index: NextPage = () => {
|
|||||||
})
|
})
|
||||||
setEntries(pager.entries)
|
setEntries(pager.entries)
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
const [executeDelete] = useFormDeleteMutation()
|
||||||
const [executeDelete] = useMutation<
|
|
||||||
AdminFormDeleteMutationData,
|
|
||||||
AdminFormDeleteMutationVariables
|
|
||||||
>(ADMIN_FORM_DELETE_MUTATION)
|
|
||||||
|
|
||||||
const deleteForm = async (form: AdminFormDeleteMutationVariables) => {
|
const deleteForm = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
await executeDelete({
|
await executeDelete({
|
||||||
variables: {
|
variables: {
|
||||||
id: form.id,
|
id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const next = entries.filter((entry) => entry.id !== form.id)
|
const next = entries.filter((entry) => entry.id !== id)
|
||||||
if (next.length === 0) {
|
if (next.length === 0) {
|
||||||
setPagination({ ...pagination, current: 1 })
|
setPagination({ ...pagination, current: 1 })
|
||||||
} else {
|
} else {
|
||||||
@ -79,7 +63,7 @@ const Index: NextPage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: ColumnsType<AdminPagerFormEntryQueryData> = [
|
const columns: ColumnsType<FormPagerFragment> = [
|
||||||
{
|
{
|
||||||
title: t('form:row.isLive'),
|
title: t('form:row.isLive'),
|
||||||
dataIndex: 'isLive',
|
dataIndex: 'isLive',
|
||||||
@ -95,7 +79,7 @@ const Index: NextPage = () => {
|
|||||||
{
|
{
|
||||||
title: t('form:row.admin'),
|
title: t('form:row.admin'),
|
||||||
dataIndex: 'admin',
|
dataIndex: 'admin',
|
||||||
render(user: AdminPagerFormEntryAdminQueryData) {
|
render(_, { admin: user }) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return <Tag color={'red'} title={t('form:row.adminMissing')} />
|
return <Tag color={'red'} title={t('form:row.adminMissing')} />
|
||||||
}
|
}
|
||||||
@ -137,7 +121,7 @@ const Index: NextPage = () => {
|
|||||||
{
|
{
|
||||||
title: t('form:row.menu'),
|
title: t('form:row.menu'),
|
||||||
align: 'right',
|
align: 'right',
|
||||||
render(row: AdminPagerFormEntryQueryData) {
|
render(_, row) {
|
||||||
return (
|
return (
|
||||||
<Space direction={width < 600 ? 'vertical' : 'horizontal'}>
|
<Space direction={width < 600 ? 'vertical' : 'horizontal'}>
|
||||||
<Link href={'/admin/forms/[id]/submissions'} as={`/admin/forms/${row.id}/submissions`}>
|
<Link href={'/admin/forms/[id]/submissions'} as={`/admin/forms/${row.id}/submissions`}>
|
||||||
@ -156,7 +140,7 @@ const Index: NextPage = () => {
|
|||||||
|
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={t('form:confirmDelete')}
|
title={t('form:confirmDelete')}
|
||||||
onConfirm={() => deleteForm(row)}
|
onConfirm={() => deleteForm(row.id)}
|
||||||
okText={t('form:deleteNow')}
|
okText={t('form:deleteNow')}
|
||||||
okButtonProps={{ danger: true }}
|
okButtonProps={{ danger: true }}
|
||||||
>
|
>
|
||||||
@ -188,6 +172,7 @@ const Index: NextPage = () => {
|
|||||||
<Button type={'primary'}>{t('form:new')}</Button>
|
<Button type={'primary'}>{t('form:new')}</Button>
|
||||||
</Link>,
|
</Link>,
|
||||||
]}
|
]}
|
||||||
|
error={error?.message}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
import { useQuery } from '@apollo/client'
|
||||||
import { Col, Row, Statistic } from 'antd'
|
import { Col, Row, Statistic } from 'antd'
|
||||||
import Structure from 'components/structure'
|
import Structure from 'components/structure'
|
||||||
import { withAuth } from 'components/with.auth'
|
import { withAuth } from 'components/with.auth'
|
||||||
|
|||||||
@ -1,50 +1,57 @@
|
|||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
import { Button, Divider, Form, Input, message, Select } from 'antd'
|
||||||
import { Button, Form, Input, message, Select } from 'antd'
|
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { cleanInput } from '../../components/clean.input'
|
|
||||||
import Structure from '../../components/structure'
|
import Structure from '../../components/structure'
|
||||||
import { withAuth } from '../../components/with.auth'
|
import { withAuth } from '../../components/with.auth'
|
||||||
import {
|
import { useProfileUpdateMutation } from '../../graphql/mutation/profile.update.mutation'
|
||||||
ADMIN_PROFILE_UPDATE_MUTATION,
|
import { useProfileQuery } from '../../graphql/query/admin.profile.query'
|
||||||
AdminProfileUpdateMutationData,
|
|
||||||
AdminProfileUpdateMutationVariables,
|
|
||||||
} from '../../graphql/mutation/admin.profile.update.mutation'
|
|
||||||
import {
|
|
||||||
ADMIN_PROFILE_QUERY,
|
|
||||||
AdminProfileQueryData,
|
|
||||||
AdminProfileQueryVariables,
|
|
||||||
} from '../../graphql/query/admin.profile.query'
|
|
||||||
import { AdminUserQueryData } from '../../graphql/query/admin.user.query'
|
|
||||||
import { languages } from '../../i18n'
|
import { languages } from '../../i18n'
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
user: {
|
||||||
|
id: string
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
language: string
|
||||||
|
firstName: string
|
||||||
|
lastName: string
|
||||||
|
}
|
||||||
|
password: string
|
||||||
|
confirm: string
|
||||||
|
}
|
||||||
|
|
||||||
const Profile: NextPage = () => {
|
const Profile: NextPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [form] = useForm()
|
const [form] = useForm<FormData>()
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const { loading } = useQuery<AdminProfileQueryData, AdminProfileQueryVariables>(
|
const { loading } = useProfileQuery({
|
||||||
ADMIN_PROFILE_QUERY,
|
|
||||||
{
|
|
||||||
onCompleted: (next) => {
|
onCompleted: (next) => {
|
||||||
form.setFieldsValue(next)
|
form.setFieldsValue(next)
|
||||||
},
|
},
|
||||||
}
|
onError(e) {
|
||||||
)
|
void router.push('/')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const [update] = useMutation<AdminProfileUpdateMutationData, AdminProfileUpdateMutationVariables>(
|
const [update] = useProfileUpdateMutation()
|
||||||
ADMIN_PROFILE_UPDATE_MUTATION
|
|
||||||
)
|
|
||||||
|
|
||||||
const save = async (formData: AdminUserQueryData) => {
|
const save = async (data: FormData) => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const next = (
|
const next = (
|
||||||
await update({
|
await update({
|
||||||
variables: cleanInput(formData),
|
variables: {
|
||||||
|
user: {
|
||||||
|
...data.user,
|
||||||
|
password: data.password && data.password === data.confirm ? data.password : undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
).data
|
).data
|
||||||
|
|
||||||
@ -147,6 +154,46 @@ const Profile: NextPage = () => {
|
|||||||
<Form.Item label={t('profile:lastName')} name={['user', 'lastName']}>
|
<Form.Item label={t('profile:lastName')} name={['user', 'lastName']}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="password"
|
||||||
|
label={t('profile:password')}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
min: 5,
|
||||||
|
message: t('validation:passwordMinLength'),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input.Password />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item noStyle shouldUpdate>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
name="confirm"
|
||||||
|
label={t('profile:confirmPassword')}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: Boolean(form.getFieldValue('password')),
|
||||||
|
message: t('validation:passwordConfirmRequired'),
|
||||||
|
},
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (!value || getFieldValue('password') === value) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(t('validation:passwordConfirmMismatch')))
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input.Password />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Structure>
|
</Structure>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
import { useQuery } from '@apollo/client'
|
||||||
import { Button, Form, Input, message, Tabs } from 'antd'
|
import { Button, Form, Input, message, Tabs } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import Structure from 'components/structure'
|
import Structure from 'components/structure'
|
||||||
@ -9,11 +9,7 @@ import React, { useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { cleanInput } from '../../../../components/clean.input'
|
import { cleanInput } from '../../../../components/clean.input'
|
||||||
import { BaseDataTab } from '../../../../components/user/admin/base.data.tab'
|
import { BaseDataTab } from '../../../../components/user/admin/base.data.tab'
|
||||||
import {
|
import { useUserUpdateMutation } from '../../../../graphql/mutation/user.update.mutation'
|
||||||
ADMIN_USER_UPDATE_MUTATION,
|
|
||||||
AdminUserUpdateMutationData,
|
|
||||||
AdminUserUpdateMutationVariables,
|
|
||||||
} from '../../../../graphql/mutation/admin.user.update.mutation'
|
|
||||||
import {
|
import {
|
||||||
ADMIN_USER_QUERY,
|
ADMIN_USER_QUERY,
|
||||||
AdminUserQueryData,
|
AdminUserQueryData,
|
||||||
@ -38,9 +34,7 @@ const Index: NextPage = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const [update] = useMutation<AdminUserUpdateMutationData, AdminUserUpdateMutationVariables>(
|
const [update] = useUserUpdateMutation()
|
||||||
ADMIN_USER_UPDATE_MUTATION
|
|
||||||
)
|
|
||||||
|
|
||||||
const save = async (formData: AdminUserQueryData) => {
|
const save = async (formData: AdminUserQueryData) => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons/lib'
|
import { DeleteOutlined, EditOutlined } from '@ant-design/icons/lib'
|
||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, message, Popconfirm, Space, Table, Tag } from 'antd'
|
import { Button, message, Popconfirm, Space, Table, Tag } from 'antd'
|
||||||
import { PaginationProps } from 'antd/es/pagination'
|
import { PaginationProps } from 'antd/es/pagination'
|
||||||
import { ColumnsType } from 'antd/lib/table/interface'
|
import { ColumnsType } from 'antd/lib/table/interface'
|
||||||
@ -12,17 +11,9 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { DateTime } from '../../../components/date.time'
|
import { DateTime } from '../../../components/date.time'
|
||||||
import { useWindowSize } from '../../../components/use.window.size'
|
import { useWindowSize } from '../../../components/use.window.size'
|
||||||
import { UserRole } from '../../../components/user/role'
|
import { UserRole } from '../../../components/user/role'
|
||||||
import {
|
import { UserPagerFragment } from '../../../graphql/fragment/user.pager.fragment'
|
||||||
ADMIN_USER_DELETE_MUTATION,
|
import { useUserDeleteMutation } from '../../../graphql/mutation/user.delete.mutation'
|
||||||
AdminUserDeleteMutationData,
|
import { useUserPagerQuery } from '../../../graphql/query/user.pager.query'
|
||||||
AdminUserDeleteMutationVariables,
|
|
||||||
} from '../../../graphql/mutation/admin.user.delete.mutation'
|
|
||||||
import {
|
|
||||||
ADMIN_PAGER_USER_QUERY,
|
|
||||||
AdminPagerUserEntryQueryData,
|
|
||||||
AdminPagerUserQueryData,
|
|
||||||
AdminPagerUserQueryVariables,
|
|
||||||
} from '../../../graphql/query/admin.pager.user.query'
|
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
const { width } = useWindowSize()
|
const { width } = useWindowSize()
|
||||||
@ -30,10 +21,8 @@ const Index: NextPage = () => {
|
|||||||
const [pagination, setPagination] = useState<PaginationProps>({
|
const [pagination, setPagination] = useState<PaginationProps>({
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
})
|
})
|
||||||
const [entries, setEntries] = useState<AdminPagerUserEntryQueryData[]>()
|
const [entries, setEntries] = useState<UserPagerFragment[]>()
|
||||||
const { loading, refetch } = useQuery<AdminPagerUserQueryData, AdminPagerUserQueryVariables>(
|
const { loading, refetch, error } = useUserPagerQuery({
|
||||||
ADMIN_PAGER_USER_QUERY,
|
|
||||||
{
|
|
||||||
variables: {
|
variables: {
|
||||||
limit: pagination.pageSize,
|
limit: pagination.pageSize,
|
||||||
start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0,
|
start: Math.max(0, pagination.current - 1) * pagination.pageSize || 0,
|
||||||
@ -45,21 +34,17 @@ const Index: NextPage = () => {
|
|||||||
})
|
})
|
||||||
setEntries(pager.entries)
|
setEntries(pager.entries)
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
const [executeDelete] = useUserDeleteMutation()
|
||||||
const [executeDelete] = useMutation<
|
|
||||||
AdminUserDeleteMutationData,
|
|
||||||
AdminUserDeleteMutationVariables
|
|
||||||
>(ADMIN_USER_DELETE_MUTATION)
|
|
||||||
|
|
||||||
const deleteUser = async (form: AdminPagerUserEntryQueryData) => {
|
const deleteUser = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
await executeDelete({
|
await executeDelete({
|
||||||
variables: {
|
variables: {
|
||||||
id: form.id,
|
id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const next = entries.filter((entry) => entry.id !== form.id)
|
const next = entries.filter((entry) => entry.id !== id)
|
||||||
if (next.length === 0) {
|
if (next.length === 0) {
|
||||||
setPagination({ ...pagination, current: 1 })
|
setPagination({ ...pagination, current: 1 })
|
||||||
} else {
|
} else {
|
||||||
@ -71,7 +56,7 @@ const Index: NextPage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: ColumnsType<AdminPagerUserEntryQueryData> = [
|
const columns: ColumnsType<UserPagerFragment> = [
|
||||||
{
|
{
|
||||||
title: t('user:row.roles'),
|
title: t('user:row.roles'),
|
||||||
dataIndex: 'roles',
|
dataIndex: 'roles',
|
||||||
@ -82,7 +67,7 @@ const Index: NextPage = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('user:row.email'),
|
title: t('user:row.email'),
|
||||||
render(row: AdminPagerUserEntryQueryData) {
|
render(_, row) {
|
||||||
return <Tag color={row.verifiedEmail ? 'lime' : 'volcano'}>{row.email}</Tag>
|
return <Tag color={row.verifiedEmail ? 'lime' : 'volcano'}>{row.email}</Tag>
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -97,7 +82,7 @@ const Index: NextPage = () => {
|
|||||||
{
|
{
|
||||||
title: t('user:row.menu'),
|
title: t('user:row.menu'),
|
||||||
align: 'right',
|
align: 'right',
|
||||||
render(row: AdminPagerUserEntryQueryData) {
|
render(_, row) {
|
||||||
return (
|
return (
|
||||||
<Space direction={width < 600 ? 'vertical' : 'horizontal'}>
|
<Space direction={width < 600 ? 'vertical' : 'horizontal'}>
|
||||||
<Link href={'/admin/users/[id]'} as={`/admin/users/${row.id}`}>
|
<Link href={'/admin/users/[id]'} as={`/admin/users/${row.id}`}>
|
||||||
@ -108,7 +93,7 @@ const Index: NextPage = () => {
|
|||||||
|
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title={t('user:confirmDelete')}
|
title={t('user:confirmDelete')}
|
||||||
onConfirm={() => deleteUser(row)}
|
onConfirm={() => deleteUser(row.id)}
|
||||||
okText={t('user:deleteNow')}
|
okText={t('user:deleteNow')}
|
||||||
okButtonProps={{ danger: true }}
|
okButtonProps={{ danger: true }}
|
||||||
>
|
>
|
||||||
@ -128,6 +113,7 @@ const Index: NextPage = () => {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
breadcrumbs={[{ href: '/admin', name: t('admin:home') }]}
|
breadcrumbs={[{ href: '/admin', name: t('admin:home') }]}
|
||||||
padded={false}
|
padded={false}
|
||||||
|
error={error?.message}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Modal } from 'antd'
|
import { Modal } from 'antd'
|
||||||
import { ErrorPage } from 'components/error.page'
|
import { ErrorPage } from 'components/error.page'
|
||||||
import { Field } from 'components/form/field'
|
import { Field } from 'components/form/field'
|
||||||
import { FormPage } from 'components/form/page'
|
import { FormPage } from 'components/form/page'
|
||||||
import { LoadingPage } from 'components/loading.page'
|
import { LoadingPage } from 'components/loading.page'
|
||||||
import { FORM_QUERY, FormQueryData, FormQueryVariables } from 'graphql/query/form.query'
|
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
@ -14,6 +12,7 @@ import { ReactIdSwiperProps } from 'react-id-swiper/lib/types'
|
|||||||
import * as OriginalSwiper from 'swiper'
|
import * as OriginalSwiper from 'swiper'
|
||||||
import { Omf } from '../../../components/omf'
|
import { Omf } from '../../../components/omf'
|
||||||
import { useSubmission } from '../../../components/use.submission'
|
import { useSubmission } from '../../../components/use.submission'
|
||||||
|
import { useFormPublicQuery } from '../../../graphql/query/form.public.query'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string
|
id: string
|
||||||
@ -26,7 +25,7 @@ const Index: NextPage<Props> = () => {
|
|||||||
const [swiper, setSwiper] = useState<OriginalSwiper.default>(null)
|
const [swiper, setSwiper] = useState<OriginalSwiper.default>(null)
|
||||||
const submission = useSubmission(id)
|
const submission = useSubmission(id)
|
||||||
|
|
||||||
const { loading, data, error } = useQuery<FormQueryData, FormQueryVariables>(FORM_QUERY, {
|
const { loading, data, error } = useFormPublicQuery({
|
||||||
variables: {
|
variables: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
@ -74,7 +73,7 @@ const Index: NextPage<Props> = () => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: design.colors.backgroundColor,
|
background: design.colors.background,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Omf />
|
<Omf />
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { Layout } from 'antd'
|
import { Layout } from 'antd'
|
||||||
import { AuthFooter } from 'components/auth/footer'
|
import { AuthFooter } from 'components/auth/footer'
|
||||||
import { NextPage } from 'next'
|
import { GetStaticProps, NextPage } from 'next'
|
||||||
import getConfig from 'next/config'
|
import getConfig from 'next/config'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { LoadingPage } from '../components/loading.page'
|
import { LoadingPage } from '../components/loading.page'
|
||||||
import { Omf } from '../components/omf'
|
import { Omf } from '../components/omf'
|
||||||
|
import { NextConfigType } from '../next.config.type'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
const { publicRuntimeConfig } = getConfig() as NextConfigType
|
||||||
const { publicRuntimeConfig } = getConfig() as {
|
|
||||||
publicRuntimeConfig: {
|
|
||||||
spa: boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -56,7 +52,7 @@ const Index: NextPage = () => {
|
|||||||
<Layout
|
<Layout
|
||||||
style={{
|
style={{
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
background: '#437fdc',
|
background: publicRuntimeConfig.mainBackground,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Omf />
|
<Omf />
|
||||||
@ -76,4 +72,11 @@ const Index: NextPage = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getStaticProps: GetStaticProps = async () => {
|
||||||
|
return {
|
||||||
|
revalidate: 10,
|
||||||
|
props: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Index
|
export default Index
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
import { useMutation } from '@apollo/client'
|
||||||
import { Alert, Button, Form, Input, message } from 'antd'
|
import { Alert, Button, Form, Input, message } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import { AuthFooter } from 'components/auth/footer'
|
import { AuthFooter } from 'components/auth/footer'
|
||||||
@ -16,7 +16,7 @@ import React, { useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
import { Omf } from '../../components/omf'
|
import { Omf } from '../../components/omf'
|
||||||
import { SETTINGS_QUERY, SettingsQueryData } from '../../graphql/query/settings.query'
|
import { useSettingsQuery } from '../../graphql/query/settings.query'
|
||||||
import scss from './index.module.scss'
|
import scss from './index.module.scss'
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
@ -25,7 +25,7 @@ const Index: NextPage = () => {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [login] = useMutation<LoginMutationData, LoginMutationVariables>(LOGIN_MUTATION)
|
const [login] = useMutation<LoginMutationData, LoginMutationVariables>(LOGIN_MUTATION)
|
||||||
const { data } = useQuery<SettingsQueryData>(SETTINGS_QUERY)
|
const { data } = useSettingsQuery()
|
||||||
|
|
||||||
const finish = async (data: LoginMutationVariables) => {
|
const finish = async (data: LoginMutationVariables) => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|||||||
@ -1,15 +1,9 @@
|
|||||||
import { useMutation, useQuery } from '@apollo/react-hooks'
|
|
||||||
import { Button, Form, Input, message } from 'antd'
|
import { Button, Form, Input, message } from 'antd'
|
||||||
import { useForm } from 'antd/lib/form/Form'
|
import { useForm } from 'antd/lib/form/Form'
|
||||||
import { AuthFooter } from 'components/auth/footer'
|
import { AuthFooter } from 'components/auth/footer'
|
||||||
import { AuthLayout } from 'components/auth/layout'
|
import { AuthLayout } from 'components/auth/layout'
|
||||||
import { setAuth } from 'components/with.auth'
|
import { setAuth } from 'components/with.auth'
|
||||||
import {
|
import { RegisterUserData, useRegisterMutation } from 'graphql/mutation/register.mutation'
|
||||||
REGISTER_MUTATION,
|
|
||||||
RegisterMutationData,
|
|
||||||
RegisterMutationVariables,
|
|
||||||
RegisterUserData,
|
|
||||||
} from 'graphql/mutation/register.mutation'
|
|
||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
@ -17,7 +11,7 @@ import React, { useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ErrorPage } from '../components/error.page'
|
import { ErrorPage } from '../components/error.page'
|
||||||
import { Omf } from '../components/omf'
|
import { Omf } from '../components/omf'
|
||||||
import { SETTINGS_QUERY, SettingsQueryData } from '../graphql/query/settings.query'
|
import { useSettingsQuery } from '../graphql/query/settings.query'
|
||||||
import scss from './register.module.scss'
|
import scss from './register.module.scss'
|
||||||
|
|
||||||
const Register: NextPage = () => {
|
const Register: NextPage = () => {
|
||||||
@ -25,9 +19,9 @@ const Register: NextPage = () => {
|
|||||||
const [form] = useForm()
|
const [form] = useForm()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const { data } = useQuery<SettingsQueryData>(SETTINGS_QUERY)
|
const { data } = useSettingsQuery()
|
||||||
|
|
||||||
const [register] = useMutation<RegisterMutationData, RegisterMutationVariables>(REGISTER_MUTATION)
|
const [register] = useRegisterMutation()
|
||||||
|
|
||||||
const finish = async (data: RegisterUserData) => {
|
const finish = async (data: RegisterUserData) => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|||||||
205
schema.graphql
205
schema.graphql
@ -5,12 +5,6 @@ schema {
|
|||||||
mutation: Mutation
|
mutation: Mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Notification {
|
|
||||||
enabled: Boolean!
|
|
||||||
htmlTemplate: String
|
|
||||||
subject: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthToken {
|
type AuthToken {
|
||||||
accessToken: String!
|
accessToken: String!
|
||||||
refreshToken: String!
|
refreshToken: String!
|
||||||
@ -21,17 +15,18 @@ type Button {
|
|||||||
activeColor: String
|
activeColor: String
|
||||||
bgColor: String
|
bgColor: String
|
||||||
color: String
|
color: String
|
||||||
|
id: ID!
|
||||||
text: String
|
text: String
|
||||||
url: String
|
url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Colors {
|
type Colors {
|
||||||
answerColor: String!
|
answer: String!
|
||||||
backgroundColor: String!
|
background: String!
|
||||||
buttonActiveColor: String!
|
button: String!
|
||||||
buttonColor: String!
|
buttonActive: String!
|
||||||
buttonTextColor: String!
|
buttonText: String!
|
||||||
questionColor: String!
|
question: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Deleted {
|
type Deleted {
|
||||||
@ -44,6 +39,7 @@ type Design {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Device {
|
type Device {
|
||||||
|
language: String
|
||||||
name: String!
|
name: String!
|
||||||
type: String!
|
type: String!
|
||||||
}
|
}
|
||||||
@ -59,8 +55,7 @@ type Form {
|
|||||||
isLive: Boolean!
|
isLive: Boolean!
|
||||||
language: String!
|
language: String!
|
||||||
lastModified: DateTime
|
lastModified: DateTime
|
||||||
respondentNotifications: RespondentNotificationsModel!
|
notifications: [FormNotification!]!
|
||||||
selfNotifications: SelfNotificationsModel!
|
|
||||||
showFooter: Boolean!
|
showFooter: Boolean!
|
||||||
startPage: Page!
|
startPage: Page!
|
||||||
title: String!
|
title: String!
|
||||||
@ -69,7 +64,7 @@ type Form {
|
|||||||
type FormField {
|
type FormField {
|
||||||
description: String!
|
description: String!
|
||||||
id: ID!
|
id: ID!
|
||||||
logicJump: LogicJump!
|
logic: [FormFieldLogic!]!
|
||||||
options: [FormFieldOption!]!
|
options: [FormFieldOption!]!
|
||||||
rating: FormFieldRating
|
rating: FormFieldRating
|
||||||
required: Boolean!
|
required: Boolean!
|
||||||
@ -79,7 +74,19 @@ type FormField {
|
|||||||
value: String!
|
value: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormFieldLogic {
|
||||||
|
action: String!
|
||||||
|
disable: Boolean
|
||||||
|
enabled: Boolean!
|
||||||
|
formula: String
|
||||||
|
id: ID!
|
||||||
|
jumpTo: ID
|
||||||
|
require: Boolean
|
||||||
|
visible: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
type FormFieldOption {
|
type FormFieldOption {
|
||||||
|
id: ID!
|
||||||
key: String
|
key: String
|
||||||
title: String
|
title: String
|
||||||
value: String!
|
value: String!
|
||||||
@ -97,6 +104,24 @@ type FormHook {
|
|||||||
url: String
|
url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormNotification {
|
||||||
|
enabled: Boolean!
|
||||||
|
fromEmail: String
|
||||||
|
fromField: String
|
||||||
|
htmlTemplate: String
|
||||||
|
id: ID!
|
||||||
|
subject: String
|
||||||
|
toEmail: String
|
||||||
|
toField: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormPager {
|
||||||
|
entries: [Form!]!
|
||||||
|
limit: Int!
|
||||||
|
start: Int!
|
||||||
|
total: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type FormStatistic {
|
type FormStatistic {
|
||||||
total: Int!
|
total: Int!
|
||||||
}
|
}
|
||||||
@ -106,14 +131,6 @@ type GeoLocation {
|
|||||||
country: String
|
country: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogicJump {
|
|
||||||
enabled: Boolean!
|
|
||||||
expressionString: String
|
|
||||||
fieldA: ID
|
|
||||||
jumpTo: ID
|
|
||||||
valueB: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
authLogin(password: String!, username: String!): AuthToken!
|
authLogin(password: String!, username: String!): AuthToken!
|
||||||
authRegister(user: UserCreateInput!): AuthToken!
|
authRegister(user: UserCreateInput!): AuthToken!
|
||||||
@ -130,39 +147,12 @@ type Mutation {
|
|||||||
type Page {
|
type Page {
|
||||||
buttonText: String
|
buttonText: String
|
||||||
buttons: [Button!]!
|
buttons: [Button!]!
|
||||||
|
id: ID!
|
||||||
paragraph: String
|
paragraph: String
|
||||||
show: Boolean!
|
show: Boolean!
|
||||||
title: String
|
title: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type PagerForm {
|
|
||||||
entries: [Form!]!
|
|
||||||
limit: Int!
|
|
||||||
start: Int!
|
|
||||||
total: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type PagerSetting {
|
|
||||||
entries: [Setting!]!
|
|
||||||
limit: Int!
|
|
||||||
start: Int!
|
|
||||||
total: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type PagerSubmission {
|
|
||||||
entries: [Submission!]!
|
|
||||||
limit: Int!
|
|
||||||
start: Int!
|
|
||||||
total: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type PagerUser {
|
|
||||||
entries: [User!]!
|
|
||||||
limit: Int!
|
|
||||||
start: Int!
|
|
||||||
total: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Profile {
|
type Profile {
|
||||||
created: DateTime!
|
created: DateTime!
|
||||||
email: String!
|
email: String!
|
||||||
@ -180,33 +170,17 @@ type Query {
|
|||||||
getFormById(id: ID!): Form!
|
getFormById(id: ID!): Form!
|
||||||
getFormStatistic: FormStatistic!
|
getFormStatistic: FormStatistic!
|
||||||
getSetting(key: ID!): Setting!
|
getSetting(key: ID!): Setting!
|
||||||
getSettings: PagerSetting!
|
getSettings: SettingPager!
|
||||||
getSubmissionStatistic: SubmissionStatistic!
|
getSubmissionStatistic: SubmissionStatistic!
|
||||||
getUserById(id: ID!): User!
|
getUserById(id: ID!): User!
|
||||||
getUserStatistic: UserStatistic!
|
getUserStatistic: UserStatistic!
|
||||||
listForms(limit: Int = 50, start: Int = 0): PagerForm!
|
listForms(limit: Int = 50, start: Int = 0): FormPager!
|
||||||
listSubmissions(form: ID!, limit: Int = 50, start: Int = 0): PagerSubmission!
|
listSubmissions(form: ID!, limit: Int = 50, start: Int = 0): SubmissionPager!
|
||||||
listUsers(limit: Int = 50, start: Int = 0): PagerUser!
|
listUsers(limit: Int = 50, start: Int = 0): UserPager!
|
||||||
me: Profile!
|
me: Profile!
|
||||||
status: Version!
|
status: Version!
|
||||||
}
|
}
|
||||||
|
|
||||||
type RespondentNotificationsModel implements Notification {
|
|
||||||
enabled: Boolean!
|
|
||||||
fromEmail: String
|
|
||||||
htmlTemplate: String
|
|
||||||
subject: String
|
|
||||||
toField: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type SelfNotificationsModel implements Notification {
|
|
||||||
enabled: Boolean!
|
|
||||||
fromField: String
|
|
||||||
htmlTemplate: String
|
|
||||||
subject: String
|
|
||||||
toEmail: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type Setting {
|
type Setting {
|
||||||
isFalse: Boolean!
|
isFalse: Boolean!
|
||||||
isTrue: Boolean!
|
isTrue: Boolean!
|
||||||
@ -214,6 +188,13 @@ type Setting {
|
|||||||
value: String
|
value: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SettingPager {
|
||||||
|
entries: [Setting!]!
|
||||||
|
limit: Int!
|
||||||
|
start: Int!
|
||||||
|
total: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type Submission {
|
type Submission {
|
||||||
created: DateTime!
|
created: DateTime!
|
||||||
device: Device!
|
device: Device!
|
||||||
@ -233,6 +214,13 @@ type SubmissionField {
|
|||||||
value: String!
|
value: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SubmissionPager {
|
||||||
|
entries: [Submission!]!
|
||||||
|
limit: Int!
|
||||||
|
start: Int!
|
||||||
|
total: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type SubmissionProgress {
|
type SubmissionProgress {
|
||||||
created: DateTime!
|
created: DateTime!
|
||||||
id: ID!
|
id: ID!
|
||||||
@ -258,6 +246,13 @@ type User {
|
|||||||
verifiedEmail: Boolean!
|
verifiedEmail: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserPager {
|
||||||
|
entries: [User!]!
|
||||||
|
limit: Int!
|
||||||
|
start: Int!
|
||||||
|
total: Int!
|
||||||
|
}
|
||||||
|
|
||||||
type UserStatistic {
|
type UserStatistic {
|
||||||
total: Int!
|
total: Int!
|
||||||
}
|
}
|
||||||
@ -271,17 +266,18 @@ input ButtonInput {
|
|||||||
activeColor: String
|
activeColor: String
|
||||||
bgColor: String
|
bgColor: String
|
||||||
color: String
|
color: String
|
||||||
|
id: ID
|
||||||
text: String
|
text: String
|
||||||
url: String
|
url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ColorsInput {
|
input ColorsInput {
|
||||||
answerColor: String!
|
answer: String!
|
||||||
backgroundColor: String!
|
background: String!
|
||||||
buttonActiveColor: String!
|
button: String!
|
||||||
buttonColor: String!
|
buttonActive: String!
|
||||||
buttonTextColor: String!
|
buttonText: String!
|
||||||
questionColor: String!
|
question: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input DesignInput {
|
input DesignInput {
|
||||||
@ -290,6 +286,7 @@ input DesignInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input DeviceInput {
|
input DeviceInput {
|
||||||
|
language: String
|
||||||
name: String!
|
name: String!
|
||||||
type: String!
|
type: String!
|
||||||
}
|
}
|
||||||
@ -303,8 +300,9 @@ input FormCreateInput {
|
|||||||
|
|
||||||
input FormFieldInput {
|
input FormFieldInput {
|
||||||
description: String!
|
description: String!
|
||||||
|
disabled: Boolean
|
||||||
id: ID!
|
id: ID!
|
||||||
logicJump: LogicJumpInput
|
logic: [FormFieldLogicInput!]
|
||||||
options: [FormFieldOptionInput!]
|
options: [FormFieldOptionInput!]
|
||||||
rating: FormFieldRatingInput
|
rating: FormFieldRatingInput
|
||||||
required: Boolean!
|
required: Boolean!
|
||||||
@ -314,7 +312,19 @@ input FormFieldInput {
|
|||||||
value: String!
|
value: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input FormFieldLogicInput {
|
||||||
|
action: String
|
||||||
|
disable: Boolean
|
||||||
|
enabled: Boolean
|
||||||
|
formula: String
|
||||||
|
id: ID
|
||||||
|
jumpTo: ID
|
||||||
|
require: Boolean
|
||||||
|
visible: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
input FormFieldOptionInput {
|
input FormFieldOptionInput {
|
||||||
|
id: ID
|
||||||
key: String
|
key: String
|
||||||
title: String
|
title: String
|
||||||
value: String!
|
value: String!
|
||||||
@ -332,6 +342,17 @@ input FormHookInput {
|
|||||||
url: String
|
url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input FormNotificationInput {
|
||||||
|
enabled: Boolean!
|
||||||
|
fromEmail: String
|
||||||
|
fromField: String
|
||||||
|
htmlTemplate: String
|
||||||
|
id: ID
|
||||||
|
subject: String
|
||||||
|
toEmail: String
|
||||||
|
toField: String
|
||||||
|
}
|
||||||
|
|
||||||
input FormUpdateInput {
|
input FormUpdateInput {
|
||||||
design: DesignInput
|
design: DesignInput
|
||||||
endPage: PageInput
|
endPage: PageInput
|
||||||
@ -340,24 +361,16 @@ input FormUpdateInput {
|
|||||||
id: ID!
|
id: ID!
|
||||||
isLive: Boolean
|
isLive: Boolean
|
||||||
language: String
|
language: String
|
||||||
respondentNotifications: RespondentNotificationsInput
|
notifications: [FormNotificationInput!]
|
||||||
selfNotifications: SelfNotificationsInput
|
|
||||||
showFooter: Boolean
|
showFooter: Boolean
|
||||||
startPage: PageInput
|
startPage: PageInput
|
||||||
title: String
|
title: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input LogicJumpInput {
|
|
||||||
enabled: Boolean
|
|
||||||
expressionString: String
|
|
||||||
fieldA: ID
|
|
||||||
jumpTo: ID
|
|
||||||
valueB: String
|
|
||||||
}
|
|
||||||
|
|
||||||
input PageInput {
|
input PageInput {
|
||||||
buttonText: String
|
buttonText: String
|
||||||
buttons: [ButtonInput!]!
|
buttons: [ButtonInput!]!
|
||||||
|
id: ID
|
||||||
paragraph: String
|
paragraph: String
|
||||||
show: Boolean!
|
show: Boolean!
|
||||||
title: String
|
title: String
|
||||||
@ -373,22 +386,6 @@ input ProfileUpdateInput {
|
|||||||
username: String
|
username: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input RespondentNotificationsInput {
|
|
||||||
enabled: Boolean!
|
|
||||||
fromEmail: String
|
|
||||||
htmlTemplate: String
|
|
||||||
subject: String
|
|
||||||
toField: String
|
|
||||||
}
|
|
||||||
|
|
||||||
input SelfNotificationsInput {
|
|
||||||
enabled: Boolean!
|
|
||||||
fromField: String
|
|
||||||
htmlTemplate: String
|
|
||||||
subject: String
|
|
||||||
toEmail: String
|
|
||||||
}
|
|
||||||
|
|
||||||
input SubmissionSetFieldInput {
|
input SubmissionSetFieldInput {
|
||||||
data: String!
|
data: String!
|
||||||
field: ID!
|
field: ID!
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user