update linting

This commit is contained in:
Michael Schramm 2020-06-09 16:27:56 +02:00
parent a983cb218a
commit acb26096d6
57 changed files with 372 additions and 220 deletions

View File

@ -3,6 +3,8 @@ module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: { jsx: true },
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
extends: [
'eslint:recommended',
@ -12,11 +14,13 @@ module.exports = {
'plugin:jsx-a11y/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
rules: {
'prettier/prettier': ['error', {}, { usePrettierrc: true }],
'react/prop-types': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-var-requires': 'off',
},
settings: {
react: {

View File

@ -1,7 +1,7 @@
# OhMyForm UI
![Project Status](https://badgen.net/github/checks/ohmyform/ui)
![Travis Status](https://badgen.net/travis/ohmyform/ui)
[![Build Status](https://travis-ci.org/ohmyform/ui.svg?branch=master)](https://travis-ci.org/ohmyform/ui)
![Latest Release](https://badgen.net/github/tag/ohmyform/ui)
![Docker Pulls](https://badgen.net/docker/pulls/ohmyform/ui)
[![Lokalise](https://badgen.net/badge/Lokalise/EN/green?icon=libraries)](https://app.lokalise.com/public/379418475ede5d5c6937b0.31012044/)

View File

@ -1,3 +1,4 @@
/* eslint-disable */
const omitDeepArrayWalk = (arr, key) => {
return arr.map((val) => {
if (Array.isArray(val)) return omitDeepArrayWalk(val, key)
@ -6,16 +7,11 @@ const omitDeepArrayWalk = (arr, key) => {
})
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const omitDeep = (obj: any, key: string | number): any => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const keys: Array<any> = Object.keys(obj)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const newObj: any = {}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
keys.forEach((i: any) => {
if (i !== key) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const val: any = obj[i]
if (val instanceof Date) newObj[i] = val
else if (Array.isArray(val)) newObj[i] = omitDeepArrayWalk(val, key)

View File

@ -21,10 +21,10 @@ export const FieldCard: React.FC<Props> = (props) => {
const { t } = useTranslation()
const { form, field, fields, onChangeFields, remove, index } = props
const type = form.getFieldValue(['form', 'fields', field.name as string, 'type'])
const type = form.getFieldValue(['form', 'fields', field.name as string, 'type']) as string
const TypeComponent = adminTypes[type] || TextType
const [nextTitle, setNextTitle] = useState(
const [nextTitle, setNextTitle] = useState<string>(
form.getFieldValue(['form', 'fields', field.name as string, 'title'])
)

View File

@ -2,6 +2,7 @@ import { PlusOutlined } from '@ant-design/icons/lib'
import { Button, Form, Select, Space, Tabs } from 'antd'
import { FormInstance } from 'antd/lib/form'
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'
@ -19,7 +20,7 @@ export const FieldsTab: React.FC<Props> = (props) => {
const [nextType, setNextType] = useState('textfield')
const renderType = useCallback(
(field, index, remove) => {
(field: FieldData, index: number, remove: (index: number) => void) => {
return (
<FieldCard
form={props.form}
@ -35,7 +36,7 @@ export const FieldsTab: React.FC<Props> = (props) => {
)
const addField = useCallback(
(add, index) => {
(add: (defaults: unknown) => void, index: number) => {
return (
<Form.Item wrapperCol={{ span: 24 }}>
<Space

View File

@ -16,7 +16,7 @@ export const RespondentNotificationsTab: React.FC<Props> = (props) => {
const [enabled, setEnabled] = useState<boolean>()
useEffect(() => {
const next = props.form.getFieldValue(['form', 'respondentNotifications', 'enabled'])
const next = props.form.getFieldValue(['form', 'respondentNotifications', 'enabled']) as boolean
if (next !== enabled) {
setEnabled(next)
@ -24,14 +24,18 @@ export const RespondentNotificationsTab: React.FC<Props> = (props) => {
}, [props.form.getFieldValue(['form', 'respondentNotifications', 'enabled'])])
useEffect(() => {
props.form.validateFields([
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 = {}
const groups: {
[key: string]: AdminFormFieldFragment[]
} = {}
props.fields.forEach((field) => {
if (!groups[field.type]) {

View File

@ -16,7 +16,7 @@ export const SelfNotificationsTab: React.FC<Props> = (props) => {
const [enabled, setEnabled] = useState<boolean>()
useEffect(() => {
const next = props.form.getFieldValue(['form', 'selfNotifications', 'enabled'])
const next = props.form.getFieldValue(['form', 'selfNotifications', 'enabled']) as boolean
if (next !== enabled) {
setEnabled(next)
@ -24,13 +24,17 @@ export const SelfNotificationsTab: React.FC<Props> = (props) => {
}, [props.form.getFieldValue(['form', 'selfNotifications', 'enabled'])])
useEffect(() => {
props.form.validateFields([
props.form
.validateFields([
['form', 'selfNotifications', 'subject'],
['form', 'selfNotifications', 'htmlTemplate'],
])
.catch((e: Error) => console.error('failed to validate', e))
}, [enabled])
const groups = {}
const groups: {
[key: string]: AdminFormFieldFragment[]
} = {}
props.fields.forEach((field) => {
if (!groups[field.type]) {
groups[field.type] = []

View File

@ -19,7 +19,7 @@ export const SubmissionValues: React.FC<Props> = (props) => {
const columns: ColumnsType<AdminPagerSubmissionEntryFieldQueryData> = [
{
title: t('submission:field'),
render: (row: AdminPagerSubmissionEntryFieldQueryData) => {
render(row: AdminPagerSubmissionEntryFieldQueryData) {
if (row.field) {
return `${row.field.title}${row.field.required ? '*' : ''}`
}
@ -29,9 +29,9 @@ export const SubmissionValues: React.FC<Props> = (props) => {
},
{
title: t('submission:value'),
render: (row) => {
render(row: AdminPagerSubmissionEntryFieldQueryData) {
try {
const data = JSON.parse(row.value)
const data = JSON.parse(row.value) as { value: string }
return data.value
} catch (e) {

View File

@ -1,5 +1,5 @@
import { DatePicker, Form } from 'antd'
import moment from 'moment'
import moment, { Moment } from 'moment'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { AdminFieldTypeProps } from './type.props'
@ -11,29 +11,29 @@ export const DateType: React.FC<AdminFieldTypeProps> = ({ field }) => {
<div>
<Form.Item
label={t('type:date.default')}
name={[field.name, 'value']}
name={[field.name as string, 'value']}
labelCol={{ span: 6 }}
getValueFromEvent={(e) => (e ? e.format('YYYY-MM-DD') : undefined)}
getValueProps={(e) => ({ value: e ? moment(e) : undefined })}
getValueFromEvent={(e: Moment) => (e ? e.format('YYYY-MM-DD') : undefined)}
getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })}
>
<DatePicker format={'YYYY-MM-DD'} />
</Form.Item>
<Form.Item
label={t('type:date.min')}
name={[field.name, 'optionKeys', 'min']}
name={[field.name as string, 'optionKeys', 'min']}
labelCol={{ span: 6 }}
getValueFromEvent={(e) => e.format('YYYY-MM-DD')}
getValueProps={(e) => ({ value: e ? moment(e) : undefined })}
getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')}
getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })}
>
<DatePicker />
</Form.Item>
<Form.Item
label={t('type:date.max')}
name={[field.name, 'optionKeys', 'max']}
name={[field.name as string, 'optionKeys', 'max']}
labelCol={{ span: 6 }}
getValueFromEvent={(e) => e.format('YYYY-MM-DD')}
getValueProps={(e) => ({ value: e ? moment(e) : undefined })}
getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')}
getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })}
>
<DatePicker />
</Form.Item>

View File

@ -10,13 +10,13 @@ export const DropdownType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:dropdown.default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input />
</Form.Item>
<Form.List name={[props.field.name, 'options']}>
<Form.List name={[props.field.name as string, 'options']}>
{(fields, { add, remove }) => {
return (
<div>

View File

@ -10,7 +10,7 @@ export const EmailType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:email.default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
rules={[{ type: 'email', message: t('validation:emailRequired') }]}
labelCol={{ span: 6 }}
>

View File

@ -10,7 +10,7 @@ export const HiddenType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:hidden.default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input />

View File

@ -10,7 +10,7 @@ export const LinkType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:link.default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
rules={[{ type: 'url', message: t('validation:invalidUrl') }]}
labelCol={{ span: 6 }}
>

View File

@ -10,7 +10,7 @@ export const NumberType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:number:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<InputNumber />

View File

@ -10,13 +10,13 @@ export const RadioType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:radio:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input />
</Form.Item>
<Form.List name={[props.field.name, 'options']}>
<Form.List name={[props.field.name as string, 'options']}>
{(fields, { add, remove }) => {
return (
<div>

View File

@ -11,7 +11,7 @@ export const RatingType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:rating:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
extra={t('type:rating.clearNote')}
>

View File

@ -9,7 +9,7 @@ export const TextType: React.FC<AdminFieldTypeProps> = (props) => {
return (
<Form.Item
label={t('type:textfield:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input />

View File

@ -10,7 +10,7 @@ export const TextareaType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:textarea:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input.TextArea autoSize />

View File

@ -1,6 +1,7 @@
import { FormInstance } from 'antd/lib/form'
import { FieldData } from 'rc-field-form/lib/interface'
export interface AdminFieldTypeProps {
form: FormInstance
field: { name: string }
field: FieldData
}

View File

@ -11,7 +11,7 @@ export const YesNoType: React.FC<AdminFieldTypeProps> = (props) => {
<div>
<Form.Item
label={t('type:yes_no:default')}
name={[props.field.name, 'value']}
name={[props.field.name as string, 'value']}
labelCol={{ span: 6 }}
>
<Input />

View File

@ -30,8 +30,8 @@ export const Field: React.FC<Props> = ({ field, save, design, next, prev, ...pro
next()
}
const error = () => {
message.error('Check inputs!')
const error = async () => {
await message.error('Check inputs!')
}
return (

View File

@ -25,8 +25,8 @@ export const DateType: React.FC<FieldTypeProps> = ({ field, design }) => {
<Form.Item
name={[field.id, 'value']}
rules={[{ required: field.required, message: 'Please provide Information' }]}
getValueFromEvent={(e) => e.format('YYYY-MM-DD')}
getValueProps={(e) => ({ value: e ? moment(e) : undefined })}
getValueFromEvent={(e: Moment) => e.format('YYYY-MM-DD')}
getValueProps={(e: string) => ({ value: e ? moment(e) : undefined })}
initialValue={field.value ? moment(field.value) : undefined}
>
<StyledDateInput

View File

@ -18,7 +18,7 @@ export const InputColor: React.FC<Props> = (props) => {
triangle={'hide'}
width={'100%'}
color={props.value}
onChange={(e) => props.onChange(e.hex)}
onChange={(e: { hex: string }) => props.onChange(e.hex)}
styles={{
default: {
card: {

View File

@ -105,9 +105,9 @@ const Structure: FunctionComponent<Props> = (props) => {
return (
<Menu.Item
onClick={(): void => {
onClick={async () => {
if (element.href) {
router.push(element.href)
await router.push(element.href)
}
}}
key={element.key}
@ -120,8 +120,8 @@ const Structure: FunctionComponent<Props> = (props) => {
)
}
const signOut = async (): Promise<void> => {
await clearAuth()
const signOut = (): void => {
clearAuth()
router.reload()
}
@ -147,7 +147,7 @@ const Structure: FunctionComponent<Props> = (props) => {
})}
<img
src={require('assets/images/logo_white_small.png')}
src={require('assets/images/logo_white_small.png') as string}
height={30}
style={{ marginRight: 16 }}
alt={'OhMyForm'}

View File

@ -10,15 +10,16 @@ interface Props extends ButtonProps {
color: string
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Styled = styled(Button)`
background: ${(props) => props.background};
color: ${(props) => props.color};
border-color: ${(props) => darken(props.background, 10)};
background: ${(props: Props) => props.background};
color: ${(props: Props) => props.color};
border-color: ${(props: Props) => darken(props.background, 10)};
:hover {
color: ${(props) => props.highlight};
background-color: ${(props) => lighten(props.background, 10)};
border-color: ${(props) => darken(props.highlight, 10)};
color: ${(props: Props) => props.highlight};
background-color: ${(props: Props) => lighten(props.background, 10)};
border-color: ${(props: Props) => darken(props.highlight, 10)};
}
`

View File

@ -1,3 +1,4 @@
/* eslint-disable */
/**
* @link https://css-tricks.com/snippets/javascript/lighten-darken-color/
*

View File

@ -8,9 +8,10 @@ import { transparentize } from './color.change'
type Props = { design: FormDesignFragment } & PickerProps<Moment>
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(DatePicker)`
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
background: none !important;
border-right: none;
border-top: none;
@ -20,7 +21,7 @@ const Field = styled(DatePicker)`
:hover,
:active {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
&.ant-picker {
@ -32,15 +33,15 @@ const Field = styled(DatePicker)`
}
input {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
::placeholder {
color: ${(props) => transparentize(props.design.colors.answerColor, 60)};
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -8,7 +8,7 @@ interface Props {
}
const Header = styled.h1`
color: ${(props) =>
color: ${(props: Props) =>
props.type === 'question'
? props.design.colors.questionColor
: props.design.colors.answerColor};

View File

@ -7,7 +7,7 @@ interface Props {
design: FormDesignFragment
}
const Header = styled.h2`
color: ${(props) =>
color: ${(props: Props) =>
props.type === 'question'
? props.design.colors.questionColor
: props.design.colors.answerColor};

View File

@ -9,9 +9,10 @@ interface Props extends InputProps {
design: FormDesignFragment
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(Input)`
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
background: none !important;
border-right: none;
border-top: none;
@ -19,12 +20,12 @@ const Field = styled(Input)`
border-radius: 0;
:focus {
outline: ${(props) => props.design.colors.answerColor} auto 5px;
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
}
:hover,
:active {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
&.ant-input-affix-wrapper {
@ -33,15 +34,15 @@ const Field = styled(Input)`
input {
background: none !important;
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
::placeholder {
color: ${(props) => transparentize(props.design.colors.answerColor, 60)};
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -9,9 +9,10 @@ interface Props extends InputNumberProps {
design: FormDesignFragment
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(InputNumber)`
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
background: none !important;
border-right: none;
border-top: none;
@ -20,12 +21,12 @@ const Field = styled(InputNumber)`
width: 100%;
:focus {
outline: ${(props) => props.design.colors.answerColor} auto 5px;
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
}
:hover,
:active {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
&.ant-input-number {
@ -34,15 +35,15 @@ const Field = styled(InputNumber)`
input {
background: none !important;
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
::placeholder {
color: ${(props) => transparentize(props.design.colors.answerColor, 60)};
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -7,8 +7,9 @@ interface Props {
design: FormDesignFragment
}
// 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) =>
color: ${(props: Props) =>
props.type === 'question'
? props.design.colors.questionColor
: props.design.colors.answerColor};

View File

@ -8,27 +8,28 @@ interface Props extends RadioProps {
design: FormDesignFragment
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(Radio)`
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
background: none;
.ant-radio {
.ant-radio-inner {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
&::after {
background: ${(props) => props.design.colors.answerColor};
background: ${(props: Props) => props.design.colors.answerColor};
}
}
&::after {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -9,10 +9,11 @@ interface Props extends SelectProps<string> {
design: FormDesignFragment
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(Select)`
.ant-select-selector {
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor} !important;
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor} !important;
background: none !important;
border-right: none !important;
border-top: none !important;
@ -22,25 +23,25 @@ const Field = styled(Select)`
}
:focus {
outline: ${(props) => props.design.colors.answerColor} auto 5px;
outline: ${(props: Props) => props.design.colors.answerColor} auto 5px;
}
:hover,
:active {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
input {
background: none !important;
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
::placeholder {
color: ${(props) => transparentize(props.design.colors.answerColor, 60)};
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -9,9 +9,10 @@ interface Props extends TextAreaProps {
design: FormDesignFragment
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
const Field = styled(Input.TextArea)`
color: ${(props) => props.design.colors.answerColor};
border-color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
background: none !important;
border-right: none;
border-top: none;
@ -21,25 +22,25 @@ const Field = styled(Input.TextArea)`
:focus {
outline: none;
box-shadow: none;
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
:hover,
:active {
border-color: ${(props) => props.design.colors.answerColor};
border-color: ${(props: Props) => props.design.colors.answerColor};
}
input {
background: none !important;
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
::placeholder {
color: ${(props) => transparentize(props.design.colors.answerColor, 60)};
color: ${(props: Props) => transparentize(props.design.colors.answerColor, 60)};
}
}
.anticon {
color: ${(props) => props.design.colors.answerColor};
color: ${(props: Props) => props.design.colors.answerColor};
}
`

View File

@ -13,7 +13,7 @@ import {
interface Submission {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setField: (fieldId: string, data: any) => Promise<void>
setField: (fieldId: string, data: unknown) => Promise<void>
finish: () => void
}
@ -28,10 +28,10 @@ export const useSubmission = (formId: string): Submission => {
)
useEffect(() => {
;(async () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const token = [...Array(40)].map(() => Math.random().toString(36)[2]).join('')
const { data } = await start({
start({
variables: {
form: formId,
submission: {
@ -43,12 +43,13 @@ export const useSubmission = (formId: string): Submission => {
},
},
})
.then(({ data }) => {
setSubmission({
id: data.submission.id,
token,
})
})()
})
.catch((e: Error) => console.error('failed to start submission', e))
}, [formId])
const setField = useCallback(

View File

@ -55,7 +55,7 @@ export const BaseDataTab: React.FC<TabPaneProps> = (props) => {
return ['user']
}
}}
getValueProps={(v) => {
getValueProps={(v: string[]) => {
let role = 'user'
if (v && v.includes('superuser')) {

View File

@ -6,7 +6,7 @@ interface Props {
}
export const UserRole: React.FC<Props> = (props) => {
let color
let color: string
let level = 'unknown'
const css: CSSProperties = {}

View File

@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'
import { ME_QUERY, MeQueryData } from '../graphql/query/me.query'
import { LoadingPage } from './loading.page'
export const clearAuth = async (): Promise<void> => {
export const clearAuth = (): void => {
localStorage.removeItem('access')
localStorage.removeItem('refresh')
@ -18,7 +18,7 @@ export const setAuth = (access: string, refresh: string): void => {
localStorage.setItem('refresh', refresh)
}
export const authConfig = async (config: AxiosRequestConfig = {}): Promise<AxiosRequestConfig> => {
export const authConfig = (config: AxiosRequestConfig = {}): AxiosRequestConfig => {
if (!config.headers) {
config.headers = {}
}
@ -28,6 +28,7 @@ export const authConfig = async (config: AxiosRequestConfig = {}): Promise<Axios
// 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) {
@ -60,7 +61,7 @@ export const withAuth = (Component: any, roles: string[] = []): React.FC => {
const path = router.asPath || router.pathname
localStorage.setItem('redirect', path)
router.push('/login')
router.push('/login').catch((e: Error) => console.error('failed to redirect to login', e))
}, [error])
useEffect(() => {
@ -74,7 +75,7 @@ export const withAuth = (Component: any, roles: string[] = []): React.FC => {
setAccess(next)
if (!next) {
router.push('/')
router.push('/').catch((e: Error) => console.error('failed to redirect to /', e))
}
}, [data])

View File

@ -1,5 +1,17 @@
import { gql } from 'apollo-boost'
export interface LoginMutationData {
tokens: {
access: string
refresh: string
}
}
export interface LoginMutationVariables {
username: string
password: string
}
export const LOGIN_MUTATION = gql`
mutation login($username: String!, $password: String!) {
tokens: authLogin(username: $username, password: $password) {

View File

@ -1,5 +1,22 @@
import { gql } from 'apollo-boost'
export interface RegisterMutationData {
tokens: {
access: string
refresh: string
}
}
export interface RegisterUserData {
username: string
email: string
password: string
}
export interface RegisterMutationVariables {
user: RegisterUserData
}
export const REGISTER_MUTATION = gql`
mutation register($user: UserCreateInput!) {
tokens: authRegister(user: $user) {

View File

@ -1,5 +1,11 @@
import { gql } from 'apollo-boost'
export interface AdminPagerFormEntryAdminQueryData {
id: string
email: string
username: string
}
export interface AdminPagerFormEntryQueryData {
id: string
created: string
@ -7,11 +13,7 @@ export interface AdminPagerFormEntryQueryData {
title: string
isLive: boolean
language: string
admin: {
id: string
email: string
username: string
}
admin: AdminPagerFormEntryAdminQueryData
}
export interface AdminPagerFormQueryData {

View File

@ -15,7 +15,6 @@
"@ant-design/icons": "^4.1.0",
"@apollo/react-hooks": "^3.1.5",
"@lifeomic/axios-fetch": "^1.4.2",
"@types/swiper": "^5.3.1",
"antd": "^4.2.2",
"apollo-boost": "^0.4.9",
"axios": "^0.19.2",
@ -42,8 +41,13 @@
"swiper": "^5.4.1"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/lifeomic__axios-fetch": "^1.4.0",
"@types/node": "^14.0.1",
"@types/node-fetch": "^2.5.7",
"@types/react": "^16.9.35",
"@types/styled-components": "^5.1.0",
"@types/swiper": "^5.3.1",
"@typescript-eslint/eslint-plugin": "^3.2.0",
"@typescript-eslint/parser": "^3.2.0",
"commander": "^5.1.0",

View File

@ -13,13 +13,18 @@ import Head from 'next/head'
import React from 'react'
import { wrapper } from 'store'
const { publicRuntimeConfig } = getConfig()
const { publicRuntimeConfig } = getConfig() as {
publicRuntimeConfig: {
endpoint: string
}
}
const client = new ApolloClient({
uri: publicRuntimeConfig.endpoint,
fetch: buildAxiosFetch(axios),
request: async (operation): Promise<void> => {
operation.setContext(await authConfig())
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-explicit-any
fetch: buildAxiosFetch(axios) as any,
request: (operation): void => {
operation.setContext(authConfig())
},
})

View File

@ -112,10 +112,10 @@ const Index: NextPage = () => {
form.setFieldsValue(next)
setFields(next.form.fields)
message.success(t('form:updated'))
await message.success(t('form:updated'))
} catch (e) {
console.error('failed to save', e)
message.error(t('form:updateError'))
await message.error(t('form:updateError'))
}
setSaving(false)
@ -134,7 +134,7 @@ const Index: NextPage = () => {
<Link
key={'submissions'}
href={'/admin/forms/[id]/submissions'}
as={`/admin/forms/${router.query.id}/submissions`}
as={`/admin/forms/${router.query.id as string}/submissions`}
>
<Button>{t('admin:submissions')}</Button>
</Link>,
@ -147,9 +147,9 @@ const Index: NextPage = () => {
<Form
form={form}
onFinish={save}
onFinishFailed={() => {
onFinishFailed={async () => {
// TODO process errors
message.error(t('validation:mandatoryFieldsMissing'))
await message.error(t('validation:mandatoryFieldsMissing'))
}}
labelCol={{
xs: { span: 24 },

View File

@ -70,14 +70,14 @@ const Submissions: NextPage = () => {
{
title: t('submission:created'),
dataIndex: 'created',
render(date) {
render(date: string) {
return <DateTime date={date} />
},
},
{
title: t('submission:lastModified'),
dataIndex: 'lastModified',
render(date) {
render(date: string) {
return <TimeAgo date={date} />
},
},
@ -94,15 +94,24 @@ const Submissions: NextPage = () => {
{
href: '/admin/forms/[id]',
name: loading || !form ? t('form:loading') : t('form:mange', { title: form.title }),
as: `/admin/forms/${router.query.id}`,
as: `/admin/forms/${router.query.id as string}`,
},
]}
padded={false}
extra={[
<Link key={'edit'} href={'/admin/forms/[id]'} as={`/admin/forms/${router.query.id}`}>
<Link
key={'edit'}
href={'/admin/forms/[id]'}
as={`/admin/forms/${router.query.id as string}`}
>
<Button>{t('submission:edit')}</Button>
</Link>,
<Button key={'web'} href={`/form/${router.query.id}`} target={'_blank'} type={'primary'}>
<Button
key={'web'}
href={`/form/${router.query.id as string}`}
target={'_blank'}
type={'primary'}
>
{t('submission:add')}
</Button>,
]}
@ -120,9 +129,9 @@ const Submissions: NextPage = () => {
return record.percentageComplete > 0
},
}}
onChange={(next) => {
onChange={async (next) => {
setPagination(next)
refetch()
await refetch()
}}
/>
</Structure>

View File

@ -35,12 +35,12 @@ const Create: NextPage = () => {
})
).data
message.success(t('form:created'))
await message.success(t('form:created'))
router.replace('/admin/forms/[id]', `/admin/forms/${next.form.id}`)
await router.replace('/admin/forms/[id]', `/admin/forms/${next.form.id}`)
} catch (e) {
console.error('failed to save', e)
message.error(t('form:creationError'))
await message.error(t('form:creationError'))
}
setSaving(false)
@ -65,9 +65,9 @@ const Create: NextPage = () => {
<Form
form={form}
onFinish={save}
onFinishFailed={() => {
onFinishFailed={async () => {
// TODO process errors
message.error(t('validation:mandatoryFieldsMissing'))
await message.error(t('validation:mandatoryFieldsMissing'))
}}
labelCol={{
xs: { span: 24 },

View File

@ -15,6 +15,7 @@ import { TimeAgo } from 'components/time.ago'
import { withAuth } from 'components/with.auth'
import {
ADMIN_PAGER_FORM_QUERY,
AdminPagerFormEntryAdminQueryData,
AdminPagerFormEntryQueryData,
AdminPagerFormQueryData,
AdminPagerFormQueryVariables,
@ -56,7 +57,7 @@ const Index: NextPage = () => {
AdminFormDeleteMutationVariables
>(ADMIN_FORM_DELETE_MUTATION)
const deleteForm = async (form) => {
const deleteForm = async (form: AdminFormDeleteMutationVariables) => {
try {
await executeDelete({
variables: {
@ -70,9 +71,9 @@ const Index: NextPage = () => {
setEntries(next)
}
message.success(t('form:deleted'))
await message.success(t('form:deleted'))
} catch (e) {
message.error(t('form:deleteError'))
await message.error(t('form:deleteError'))
}
}
@ -80,7 +81,7 @@ const Index: NextPage = () => {
{
title: t('form:row.isLive'),
dataIndex: 'isLive',
render(live) {
render(live: boolean) {
return <FormIsLive isLive={live} />
},
},
@ -91,7 +92,7 @@ const Index: NextPage = () => {
{
title: t('form:row.admin'),
dataIndex: 'admin',
render(user) {
render(user: AdminPagerFormEntryAdminQueryData) {
return (
<Link href={'/admin/users/[id]'} as={`/admin/users/${user.id}`}>
<Tooltip title={user.email}>
@ -104,28 +105,28 @@ const Index: NextPage = () => {
{
title: t('form:row.language'),
dataIndex: 'language',
render(lang) {
render(lang: string) {
return t(`language:${lang}`)
},
},
{
title: t('form:row.created'),
dataIndex: 'created',
render(date) {
render(date: string) {
return <DateTime date={date} />
},
},
{
title: t('form:row.lastModified'),
dataIndex: 'lastModified',
render(date) {
render(date: string) {
return <TimeAgo date={date} />
},
},
{
title: t('form:row.menu'),
align: 'right',
render(row) {
render(row: AdminPagerFormEntryQueryData) {
return (
<Space>
<Link href={'/admin/forms/[id]/submissions'} as={`/admin/forms/${row.id}/submissions`}>
@ -182,9 +183,9 @@ const Index: NextPage = () => {
dataSource={entries}
rowKey={'id'}
pagination={pagination}
onChange={(next) => {
onChange={async (next) => {
setPagination(next)
refetch()
await refetch()
}}
/>
</Structure>

View File

@ -49,10 +49,10 @@ const Profile: NextPage = () => {
form.setFieldsValue(next)
message.success(t('profile:updated'))
await message.success(t('profile:updated'))
} catch (e) {
console.error('failed to save', e)
message.error(t('profile:updateError'))
await message.error(t('profile:updateError'))
}
setSaving(false)
@ -73,9 +73,9 @@ const Profile: NextPage = () => {
<Form
form={form}
onFinish={save}
onFinishFailed={() => {
onFinishFailed={async () => {
// TODO process errors
message.error(t('validation:mandatoryFieldsMissing'))
await message.error(t('validation:mandatoryFieldsMissing'))
}}
labelCol={{
xs: { span: 24 },

View File

@ -53,10 +53,10 @@ const Index: NextPage = () => {
form.setFieldsValue(next)
message.success(t('user:updated'))
await message.success(t('user:updated'))
} catch (e) {
console.error('failed to save', e)
message.error(t('user:updateError'))
await message.error(t('user:updateError'))
}
setSaving(false)
@ -81,9 +81,9 @@ const Index: NextPage = () => {
<Form
form={form}
onFinish={save}
onFinishFailed={() => {
onFinishFailed={async () => {
// TODO process errors
message.error(t('validation:mandatoryFieldsMissing'))
await message.error(t('validation:mandatoryFieldsMissing'))
}}
labelCol={{
xs: { span: 24 },

View File

@ -50,7 +50,7 @@ const Index: NextPage = () => {
AdminUserDeleteMutationVariables
>(ADMIN_USER_DELETE_MUTATION)
const deleteUser = async (form) => {
const deleteUser = async (form: AdminPagerUserEntryQueryData) => {
try {
await executeDelete({
variables: {
@ -63,9 +63,9 @@ const Index: NextPage = () => {
} else {
setEntries(next)
}
message.success(t('user:deleted'))
await message.success(t('user:deleted'))
} catch (e) {
message.error(t('user:deleteError'))
await message.error(t('user:deleteError'))
}
}
@ -73,27 +73,27 @@ const Index: NextPage = () => {
{
title: t('user:row.roles'),
dataIndex: 'roles',
render(roles) {
render(roles: string[]) {
return <UserRole roles={roles} />
},
},
{
title: t('user:row.email'),
render(row) {
render(row: AdminPagerUserEntryQueryData) {
return <Tag color={row.verifiedEmail ? 'lime' : 'volcano'}>{row.email}</Tag>
},
},
{
title: t('user:row.created'),
dataIndex: 'created',
render(date) {
render(date: string) {
return <DateTime date={date} />
},
},
{
title: t('user:row.menu'),
align: 'right',
render(row) {
render(row: AdminPagerUserEntryQueryData) {
return (
<Space>
<Link href={'/admin/users/[id]'} as={`/admin/users/${row.id}`}>
@ -130,9 +130,9 @@ const Index: NextPage = () => {
dataSource={entries}
rowKey={'id'}
pagination={pagination}
onChange={(next) => {
onChange={async (next) => {
setPagination(next)
refetch()
await refetch()
}}
/>
</Structure>

View File

@ -38,7 +38,9 @@ const Index: NextPage<Props> = () => {
}
if (i18n.language !== data.form.language) {
i18n.changeLanguage(data.form.language)
i18n
.changeLanguage(data.form.language)
.catch((e: Error) => console.error('failed to change language', e))
}
}, [data])
@ -98,8 +100,8 @@ const Index: NextPage<Props> = () => {
key={field.id}
field={field}
design={design}
save={(values) => {
submission.setField(field.id, values[field.id])
save={async (values: { [key: string]: unknown }) => {
await submission.setField(field.id, values[field.id])
if (data.form.fields.length === i + 1) {
submission.finish()
@ -144,7 +146,7 @@ const Index: NextPage<Props> = () => {
)
}
Index.getInitialProps = async ({ query }) => {
Index.getInitialProps = ({ query }) => {
return {
id: query.id as string,
}

View File

@ -7,7 +7,12 @@ import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { LoadingPage } from '../components/loading.page'
const { publicRuntimeConfig } = getConfig()
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { publicRuntimeConfig } = getConfig() as {
publicRuntimeConfig: {
spa: boolean
}
}
const Index: NextPage = () => {
const router = useRouter()
@ -17,14 +22,17 @@ const Index: NextPage = () => {
if (router.pathname !== window.location.pathname) {
let href = router.asPath
const as = router.asPath
const possible = [/(\/form\/)[^/]+/i, /(\/admin\/forms\/)[^/]+/i, /(\/admin\/users\/)[^/]+/i]
;[/(\/form\/)[^/]+/i, /(\/admin\/forms\/)[^/]+/i, /(\/admin\/users\/)[^/]+/i].forEach((r) => {
possible.forEach((r) => {
if (r.test(as)) {
href = href.replace(r, '$1[id]')
}
})
router.replace(href, as)
router.replace(href, as).catch((e: Error) => {
console.error('failed redirect', e)
})
}
})
@ -50,7 +58,7 @@ const Index: NextPage = () => {
width: 500,
textAlign: 'center',
}}
src={require('../assets/images/logo_white.png')}
src={require('../assets/images/logo_white.png') as string}
/>
<AuthFooter />

View File

@ -4,7 +4,11 @@ import { useForm } from 'antd/lib/form/Form'
import { AuthFooter } from 'components/auth/footer'
import { AuthLayout } from 'components/auth/layout'
import { setAuth } from 'components/with.auth'
import { LOGIN_MUTATION } from 'graphql/mutation/login.mutation'
import {
LOGIN_MUTATION,
LoginMutationData,
LoginMutationVariables,
} from 'graphql/mutation/login.mutation'
import { NextPage } from 'next'
import Link from 'next/link'
import { useRouter } from 'next/router'
@ -16,29 +20,29 @@ const Index: NextPage = () => {
const [form] = useForm()
const router = useRouter()
const [loading, setLoading] = useState(false)
const [login] = useMutation(LOGIN_MUTATION)
const [login] = useMutation<LoginMutationData, LoginMutationVariables>(LOGIN_MUTATION)
const finish = async (data) => {
const finish = async (data: LoginMutationVariables) => {
setLoading(true)
try {
const result = await login({
variables: data,
})
await setAuth(result.data.tokens.access, result.data.tokens.refresh)
setAuth(result.data.tokens.access, result.data.tokens.refresh)
message.success(t('login:welcomeBack'))
await message.success(t('login:welcomeBack'))
router.push('/admin')
await router.push('/admin')
} catch (e) {
message.error(t('login:invalidLoginCredentials'))
await message.error(t('login:invalidLoginCredentials'))
}
setLoading(false)
}
const failed = () => {
message.error(t('validation:mandatoryFieldsMissing'))
const failed = async () => {
await message.error(t('validation:mandatoryFieldsMissing'))
}
return (
@ -55,7 +59,7 @@ const Index: NextPage = () => {
}}
>
<img
src={require('../../assets/images/logo_white_small.png')}
src={require('../../assets/images/logo_white_small.png') as string}
alt={'OhMyForm'}
style={{
display: 'block',

View File

@ -4,7 +4,12 @@ import { useForm } from 'antd/lib/form/Form'
import { AuthFooter } from 'components/auth/footer'
import { AuthLayout } from 'components/auth/layout'
import { setAuth } from 'components/with.auth'
import { REGISTER_MUTATION } from 'graphql/mutation/register.mutation'
import {
REGISTER_MUTATION,
RegisterMutationData,
RegisterMutationVariables,
RegisterUserData,
} from 'graphql/mutation/register.mutation'
import { NextPage } from 'next'
import Link from 'next/link'
import { useRouter } from 'next/router'
@ -20,9 +25,9 @@ const Register: NextPage = () => {
const [loading, setLoading] = useState(false)
const { data } = useQuery<SettingsQueryData>(SETTINGS_QUERY)
const [register] = useMutation(REGISTER_MUTATION)
const [register] = useMutation<RegisterMutationData, RegisterMutationVariables>(REGISTER_MUTATION)
const finish = async (data) => {
const finish = async (data: RegisterUserData) => {
setLoading(true)
try {
@ -32,19 +37,19 @@ const Register: NextPage = () => {
},
})
await setAuth(result.data.tokens.access, result.data.tokens.refresh)
setAuth(result.data.tokens.access, result.data.tokens.refresh)
message.success(t('register:welcome'))
await message.success(t('register:welcome'))
router.push('/')
await router.push('/')
} catch (e) {
message.error(t('register:credentialsAlreadyInUse'))
await message.error(t('register:credentialsAlreadyInUse'))
setLoading(false)
}
}
const failed = () => {
message.error(t('validation:mandatoryFieldsMissing'))
const failed = async () => {
await message.error(t('validation:mandatoryFieldsMissing'))
}
if (data && data.disabledSignUp.value) {
@ -65,7 +70,7 @@ const Register: NextPage = () => {
}}
>
<img
src={require('../assets/images/logo_white_small.png')}
src={require('../assets/images/logo_white_small.png') as string}
alt={'OhMyForm'}
style={{
display: 'block',

View File

@ -8,10 +8,10 @@ export interface State {
auth: AuthState
}
const root = (state: State, action: AnyAction) => {
const root = (state: State, action: AnyAction): State => {
switch (action.type) {
case HYDRATE:
return { ...state, ...action.payload }
return { ...state, ...action.payload } as State
}
const combined = combineReducers({

View File

@ -1169,6 +1169,13 @@
resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-9.4.0.tgz#6f8732e1909fb12f6dca8a82b7fc4b79c6c8cfcd"
integrity sha512-AaEC/diS2two2JLsEItGhuAux8UfPo0o34/7l1SIw0t4SYunUYJsxM/Y55OR2ljiVn9ffKR1n1U9IEQhsK80jw==
"@types/axios@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46"
integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=
dependencies:
axios "*"
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@ -1179,11 +1186,40 @@
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
"@types/hoist-non-react-statics@*":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/json-schema@^7.0.3":
version "7.0.4"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
"@types/lifeomic__axios-fetch@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@types/lifeomic__axios-fetch/-/lifeomic__axios-fetch-1.4.0.tgz#c3c6e6fd1af7507cbb992864891a809e1bc1d347"
integrity sha512-i6FGbhL840p71LxT4/6qq7LbWfpO1eMRFIfNAYEFqo3WkDI2O+BrJd7ac+FEBy818u+s6gGh5cqw6d1pmwJ3Dw==
dependencies:
"@types/node-fetch" "*"
axios "^0.19.0"
"@types/node-fetch@*", "@types/node-fetch@^2.5.7":
version "2.5.7"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*":
version "14.0.12"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.12.tgz#9c1d8ffb8084e8936603a6122a7649e40e68e04b"
integrity sha512-/sjzehvjkkpvLpYtN6/2dv5kg41otMGuHQUt9T2aiAuIfleCQRQHXXzF1eAw/qkZTj5Kcf4JSTf7EIizHocy6Q==
"@types/node@>=6", "@types/node@^14.0.1":
version "14.0.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.5.tgz#3d03acd3b3414cf67faf999aed11682ed121f22b"
@ -1199,7 +1235,14 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react@^16.9.35":
"@types/react-native@*":
version "0.62.13"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.62.13.tgz#c688c5ae03e426f927f7e1fa1a59cd067f35d1c2"
integrity sha512-hs4/tSABhcJx+J8pZhVoXHrOQD89WFmbs8QiDLNSA9zNrD46pityAuBWuwk1aMjPk9I3vC5ewkJroVRHgRIfdg==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.35":
version "16.9.35"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368"
integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==
@ -1207,6 +1250,16 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/styled-components@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.0.tgz#24d3412ba5395aa06e14fbc93c52f9454cebd0d6"
integrity sha512-ZFlLCuwF5r+4Vb7JUmd+Yr2S0UBdBGmI7ctFTgJMypIp3xOHI4LCFVn2dKMvpk6xDB2hLRykrEWMBwJEpUAUIQ==
dependencies:
"@types/hoist-non-react-statics" "*"
"@types/react" "*"
"@types/react-native" "*"
csstype "^2.2.0"
"@types/swiper@^5.3.1":
version "5.3.1"
resolved "https://registry.yarnpkg.com/@types/swiper/-/swiper-5.3.1.tgz#cc0c7c6f84e330ff50bec0a3ed0d172751e9d1fc"
@ -1836,7 +1889,7 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^0.19.2:
axios@*, axios@^0.19.0, axios@^0.19.2:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
@ -2411,7 +2464,7 @@ color@^3.0.0:
color-convert "^1.9.1"
color-string "^1.5.2"
combined-stream@^1.0.6:
combined-stream@^1.0.6, combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -3545,6 +3598,15 @@ form-data@^2.3.3:
combined-stream "^1.0.6"
mime-types "^2.1.12"
form-data@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"