Skip to content

Commit

Permalink
refactor: use react-hook-form in all forms (#1049)
Browse files Browse the repository at this point in the history
* refactor: use react-hook-form in update proposal status modal

* refactor: use react-hook-form in grant category section

* refactor: use react-hook-form in http status test form

* refactor: use react-hook-form in team and budget modals

* refactor: use react-hook-form in grant general info submit

* refactor: remove assert function from linked-wearables

* fix: mobile styles

* remove console logs

* add function to get all field props in core unit

* add function to get all field props in other categories
  • Loading branch information
andyesp committed Jun 29, 2023
1 parent 932ef35 commit 861f868
Show file tree
Hide file tree
Showing 30 changed files with 1,160 additions and 1,244 deletions.
33 changes: 33 additions & 0 deletions src/components/Common/Form/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react'
import { Control, Controller, FieldValues, Path, PathValue } from 'react-hook-form'

import {
TextAreaField as DCLTextArea,
TextAreaFieldProps,
} from 'decentraland-ui/dist/components/TextAreaField/TextAreaField'

interface Props<T extends FieldValues> extends TextAreaFieldProps {
control: Control<T>
name: Path<T>
defaultValue?: PathValue<T, Path<T>> | undefined
rules?: any
}

export default function TextArea<T extends FieldValues>({
control,
name,
defaultValue,
rules,
...fieldProps
}: Props<T>) {
return (
<Controller
control={control}
name={name}
defaultValue={defaultValue}
rules={rules}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
render={({ field: { ref, ...field } }) => <DCLTextArea {...field} {...fieldProps} />}
/>
)
}
3 changes: 3 additions & 0 deletions src/components/Common/Text/Text.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
.Text.Text--color-secondary {
color: var(--secondary-text);
}
.Text.Text--color-error {
color: var(--red-800);
}

.Text.Text--style-normal {
font-style: normal;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const DEFAULT_FONT_SIZE: FontSize = 'md'
const DEFAULT_FONT_STYLE: FontStyle = 'normal'
type FontSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type FontWeight = 'bold' | 'semi-bold' | 'normal'
type TextColor = 'default' | 'primary' | 'secondary'
type TextColor = 'default' | 'primary' | 'secondary' | 'error'
type FontStyle = 'normal' | 'italic'

interface Props {
Expand Down
111 changes: 49 additions & 62 deletions src/components/Debug/HttpStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'

import useEditor, { assert, createValidator } from 'decentraland-gatsby/dist/hooks/useEditor'
import { Button } from 'decentraland-ui/dist/components/Button/Button'
import { Field } from 'decentraland-ui/dist/components/Field/Field'

import { HttpStat } from '../../clients/HttpStat'
import useFormatMessage from '../../hooks/useFormatMessage'
import Field from '../Common/Form/Field'
import Label from '../Common/Label'
import ErrorMessage from '../Error/ErrorMessage'
import { ContentSection } from '../Layout/ContentLayout'
Expand All @@ -20,96 +20,83 @@ const initialState: TestState = {
sleepTime: 0,
}

const edit = (state: TestState, props: Partial<TestState>) => {
return {
...state,
...props,
}
}

const MAX_SLEEP_TIME = 300000 // 5 minutes

const validate = createValidator<TestState>({
httpStatus: (state) => ({
httpStatus: assert(state.httpStatus.length === 3, 'error.debug.invalid_http_status'),
}),
sleepTime: (state) => ({
sleepTime: assert(state.sleepTime >= 0 && state.sleepTime <= MAX_SLEEP_TIME, 'error.debug.invalid_sleep_time'),
}),
'*': (state) => ({
httpStatus: assert(state.httpStatus.length === 3, 'error.debug.invalid_http_status'),
sleepTime: assert(state.sleepTime >= 0 && state.sleepTime <= MAX_SLEEP_TIME, 'error.debug.invalid_sleep_time'),
}),
})

interface Props {
className?: string
}

export default function HttpStatus({ className }: Props) {
const t = useFormatMessage()
const [state, editor] = useEditor(edit, validate, initialState)
const [formDisabled, setFormDisabled] = useState(false)
const {
handleSubmit,
formState: { isSubmitting, errors },
control,
} = useForm<TestState>({ defaultValues: initialState, mode: 'onTouched' })
const [error, setError] = useState('')

useEffect(() => {
if (state.validated) {
setFormDisabled(true)
Promise.resolve()
.then(async () => {
return HttpStat.get().fetchResponse(state.value.httpStatus, state.value.sleepTime)
})
.then((result) => {
console.log('result', result)
editor.error({ '*': '' })
setFormDisabled(false)
})
.catch((err) => {
console.error(err, { ...err })
editor.error({ '*': err.body?.error || err.message })
setFormDisabled(false)
})
const onSubmit: SubmitHandler<TestState> = async (data) => {
try {
const result = await HttpStat.get().fetchResponse(data.httpStatus, data.sleepTime)
console.log('result', result)
setFormDisabled(false)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
console.error(err, { ...err })
setError(err.body?.error || err.message)
setFormDisabled(false)
}
}, [editor, state.validated, state.value])
}

return (
<div className={className}>
<form className={className} onSubmit={handleSubmit(onSubmit)}>
<ContentSection>
<Label>{'Http Status'}</Label>
<Field
value={state.value.httpStatus}
onChange={(_, { value }) => editor.set({ httpStatus: value })}
onBlur={() => editor.set({ httpStatus: state.value.httpStatus.trim() })}
error={!!state.error.httpStatus}
name="httpStatus"
control={control}
error={!!errors.httpStatus}
message={errors.httpStatus?.message}
disabled={formDisabled}
message={t(state.error.httpStatus)}
rules={{
required: { value: true, message: t('error.draft.title_empty') },
validate: (value: string) => {
if (value.length !== 3) {
return t('error.debug.invalid_http_status')
}
},
}}
/>
</ContentSection>
<ContentSection>
<Label>{'Sleep'}</Label>
<Field
value={state.value.sleepTime}
onChange={(_, { value }) => editor.set({ sleepTime: value ? Number(value) : undefined })}
onBlur={() => editor.set({ sleepTime: state.value.sleepTime })}
error={!!state.error.sleepTime}
message={t(state.error.sleepTime)}
name="sleepTime"
control={control}
error={!!errors.sleepTime}
message={errors.sleepTime?.message}
disabled={formDisabled}
rules={{
required: { value: true, message: t('error.draft.title_empty') },
validate: (value: string) => {
if (Number(value) >= 0 && Number(value) <= MAX_SLEEP_TIME) {
return t('error.debug.invalid_sleep_time')
}
},
}}
/>
</ContentSection>
<ContentSection className="DebugPage__Submit">
<Button
primary
disabled={state.validated || formDisabled}
loading={state.validated || formDisabled}
onClick={() => editor.validate()}
>
<Button type="submit" primary disabled={formDisabled} loading={isSubmitting}>
{t('page.submit.button_submit')}
</Button>
</ContentSection>
{state.error['*'] && (
{error && (
<ContentSection>
<ErrorMessage label={t('page.debug.error_label')} errorMessage={t(state.error['*']) || state.error['*']} />
<ErrorMessage label={t('page.debug.error_label')} errorMessage={t(error) || error} />
</ContentSection>
)}
</div>
</form>
)
}
Loading

0 comments on commit 861f868

Please sign in to comment.