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