Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(v2): add (and render) public form date field #3393

Merged
merged 20 commits into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b76a580
feat: add date validation fn
karrui Feb 8, 2022
07fcfc5
feat: add initial DateField with validation
karrui Feb 8, 2022
d89fdba
fix(fieldValidation): no future validation should also accept today
karrui Feb 8, 2022
d13fa6e
feat(DateField): disable dates that are unavailable
karrui Feb 8, 2022
b4dd71b
feat: add story for date field
karrui Feb 8, 2022
84cff69
feat: allow closing of datepicker when tapping out
karrui Feb 8, 2022
9d0d033
test(DateField): add unit tests
karrui Feb 8, 2022
cdade0d
feat(story): update story to show validation errors
karrui Feb 8, 2022
301f763
feat(PublicForm): render Date field
karrui Feb 8, 2022
30c5a25
feat: add common date utility functions for date field validation
karrui Feb 16, 2022
9d48409
style(Button): add inputAttached variant for input buttons
karrui Feb 16, 2022
b179c93
style(DateInput): use new inputAttached variant
karrui Feb 16, 2022
24cf653
style(DateInput): add zIndex=1 so error border fully surrounds input
karrui Feb 16, 2022
993e22d
style(CalendarHeader): make monthyear select flush with dates
karrui Feb 16, 2022
e5de2b0
fix: correct width of day row in calendar
karrui Feb 16, 2022
0d775d6
feat: remove datepicker's unnatural tab indices
karrui Feb 18, 2022
64a3f2c
style(Calendar): update styles of spacing in calendar header
karrui Feb 18, 2022
244f35d
Merge branch 'form-v2/develop' into form-v2/date-field-component
karrui Feb 18, 2022
42cec83
feat: remove default return from FormField component
karrui Feb 18, 2022
a37a903
feat(Date): remove unused imports
karrui Feb 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions frontend/src/components/DatePicker/DateInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { ComponentWithAs, forwardRef } from '@chakra-ui/system'
import { format } from 'date-fns'

import { BxCalendar } from '~assets/icons'
import { useIsMobile } from '~hooks/useIsMobile'
import IconButton from '~components/IconButton'

import Input, { InputProps } from '../Input'
Expand All @@ -39,8 +38,6 @@ export const DateInput = forwardRef<DateInputProps, 'input'>(
({ onChange, value = '', isDateUnavailable, ...props }, ref) => {
const initialFocusRef = useRef<HTMLInputElement>(null)

const isMobile = useIsMobile()

const handleDatepickerSelection = useCallback(
(d: Date) => {
onChange?.(format(d, 'yyyy-MM-dd'))
Expand Down Expand Up @@ -76,9 +73,6 @@ export const DateInput = forwardRef<DateInputProps, 'input'>(
<Popover
placement="bottom-start"
initialFocusRef={initialFocusRef}
// Prevent mobile taps to close popover when doing something like
// changing months in the selector.
closeOnBlur={!isMobile}
karrui marked this conversation as resolved.
Show resolved Hide resolved
isLazy
>
{({ isOpen }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FormColorTheme } from '~shared/types/form'
import {
AttachmentField,
CheckboxField,
DateField,
DecimalField,
EmailField,
HomeNoField,
Expand All @@ -32,6 +33,10 @@ interface FormFieldProps {

export const FormField = ({ field, colorTheme }: FormFieldProps) => {
switch (field.fieldType) {
case BasicField.Date:
return (
<DateField key={field._id} schema={field} colorTheme={colorTheme} />
)
case BasicField.Section:
return (
<SectionField key={field._id} schema={field} colorTheme={colorTheme} />
Expand Down
158 changes: 158 additions & 0 deletions frontend/src/templates/Field/Date/DateField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useEffect, useState } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { Text } from '@chakra-ui/react'
import { Meta, Story } from '@storybook/react'
import { addDays, lightFormat } from 'date-fns'

import { BasicField, DateSelectedValidation } from '~shared/types/field'

import { mockDateDecorator } from '~utils/storybook'
import Button from '~components/Button'

import {
DateField as DateFieldComponent,
DateFieldProps,
DateFieldSchema,
} from './DateField'

const MOCKED_TODAY_DATE = '2021-12-13'

export default {
title: 'Templates/Field/DateField',
component: DateFieldComponent,
decorators: [mockDateDecorator],
parameters: {
// Exported for testing
test: {
MOCKED_TODAY_DATE,
},
mockdate: new Date(MOCKED_TODAY_DATE),
docs: {
// Required in this story due to react-hook-form conflicting with
// Storybook somehow.
// See https://github.com/storybookjs/storybook/issues/12747.
source: {
type: 'code',
},
},
},
} as Meta

const baseSchema: DateFieldSchema = {
dateValidation: {
customMaxDate: null,
customMinDate: null,
selectedDateValidation: null,
},
title: 'Date field snapshot',
description: '',
required: true,
disabled: false,
fieldType: BasicField.Date,
_id: '611b94dfbb9e300012f702a7',
}

interface StoryDateFieldProps extends DateFieldProps {
defaultValue?: string
}

const Template: Story<StoryDateFieldProps> = ({ defaultValue, ...args }) => {
const formMethods = useForm({
defaultValues: {
[args.schema._id]: defaultValue,
},
})

const [submitValues, setSubmitValues] = useState<string>()

const onSubmit = (values: Record<string, string>) => {
setSubmitValues(values[args.schema._id] || 'Nothing was selected')
}

useEffect(() => {
if (defaultValue !== undefined) {
formMethods.trigger()
}
}, [])

return (
<FormProvider {...formMethods}>
<form onSubmit={formMethods.handleSubmit(onSubmit)} noValidate>
<DateFieldComponent {...args} />
<Button
mt="1rem"
type="submit"
isLoading={formMethods.formState.isSubmitting}
loadingText="Submitting"
>
Submit
</Button>
{submitValues && <Text>You have submitted: {submitValues}</Text>}
</form>
</FormProvider>
)
}

export const ValidationRequired = Template.bind({})
ValidationRequired.args = {
schema: baseSchema,
defaultValue: '',
}

export const ValidationOptional = Template.bind({})
ValidationOptional.args = {
schema: {
...baseSchema,
required: false,
description: 'Date field is optional',
},
defaultValue: '',
}

export const ValidationNoFuture = Template.bind({})
ValidationNoFuture.args = {
schema: {
...baseSchema,
description: 'Future dates are disallowed',
dateValidation: {
customMaxDate: null,
customMinDate: null,
selectedDateValidation: DateSelectedValidation.NoFuture,
},
},
defaultValue: lightFormat(
addDays(new Date(MOCKED_TODAY_DATE), 10),
'yyyy-MM-dd',
),
}

export const ValidationNoPast = Template.bind({})
ValidationNoPast.args = {
schema: {
...baseSchema,
description: 'Past dates are disallowed',
dateValidation: {
customMaxDate: null,
customMinDate: null,
selectedDateValidation: DateSelectedValidation.NoPast,
},
},
defaultValue: lightFormat(
addDays(new Date(MOCKED_TODAY_DATE), -10),
'yyyy-MM-dd',
),
}

export const ValidationCustomRange = Template.bind({})
ValidationCustomRange.args = {
schema: {
...baseSchema,
description: 'Only 12 December to 25 December 2021 is allowed',
dateValidation: {
customMaxDate: new Date('2021-12-25'),
customMinDate: new Date('2021-12-12'),
selectedDateValidation: DateSelectedValidation.Custom,
},
},
defaultValue: '2021-12-26',
}
Loading