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

fix(DateTimeControl): use data if present #105

Merged
merged 1 commit into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
63 changes: 56 additions & 7 deletions src/controls/DateTimeControl.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ import { render } from "../common/test-render"
import { dateTimeSchema } from "../testSchemas/dateTimeSchema"
import { UISchema } from "../ui-schema"

const EXAMPLE_DATESTRING = "2021-08-09 12:34:56"
const USER_DATESTRING = EXAMPLE_DATESTRING.replace(" ", "")
const EMPTY_DATESTRING = ""
const INPUT_MASK = "YYYY-MM-DD HH:mm:ss"
const USER_NOTADATESTRING = "not a date"
const EXAMPLE_DATESTRING = "2021-08-09T12:34:56"
const RENDERED_DATESTRING = EXAMPLE_DATESTRING.replace("T", " ")
const USER_DATESTRING = EXAMPLE_DATESTRING.replace("T", "")
const TITLE = dateTimeSchema.properties.dateTime.title
const REQUIRED_TEXT = `${TITLE} is required`

test("renders the date that the user selects", async () => {
render({
Expand All @@ -17,7 +22,7 @@ test("renders the date that the user selects", async () => {
const input = await screen.findByLabelText(TITLE)
await userEvent.type(input, USER_DATESTRING)

await waitFor(() => expect(input).toHaveValue(EXAMPLE_DATESTRING))
await waitFor(() => expect(input).toHaveValue(RENDERED_DATESTRING))
})

test("renders default date when present", async () => {
Expand All @@ -33,7 +38,7 @@ test("renders default date when present", async () => {
},
})
const input = await screen.findByLabelText(TITLE)
expect(input).toHaveValue(EXAMPLE_DATESTRING)
expect(input).toHaveValue(RENDERED_DATESTRING)
})

test("updates jsonforms data as expected", async () => {
Expand All @@ -50,7 +55,7 @@ test("updates jsonforms data as expected", async () => {
await userEvent.click(screen.getByText("Submit"))
await waitFor(() => {
expect(data).toEqual({
dateTime: EXAMPLE_DATESTRING,
dateTime: RENDERED_DATESTRING,
})
})
})
Expand All @@ -65,7 +70,7 @@ test("renders required message if no value and interaction", async () => {
const input = await screen.findByLabelText(TITLE)
await userEvent.clear(input)
await userEvent.tab()
await screen.findByText(`${TITLE} is required`)
await screen.findByText(REQUIRED_TEXT)
})

test(" does not show required message if not requried", async () => {
Expand All @@ -76,7 +81,7 @@ test(" does not show required message if not requried", async () => {
await userEvent.clear(input)
await userEvent.tab()
await waitFor(() => {
expect(screen.queryByText(`${TITLE} is required`)).toBeNull()
expect(screen.queryByText(REQUIRED_TEXT)).toBeNull()
})
})

Expand Down Expand Up @@ -131,3 +136,47 @@ test("renders default props if invalid props are submitted", async () => {
// since our default doesn't show time
await screen.findByText("Today")
})

test("it does not error on failure to parse date", async () => {
render({
schema: {
...dateTimeSchema,
properties: {
dateTime: {
...dateTimeSchema.properties.dateTime,
format: "date-time",
default: EMPTY_DATESTRING,
},
},
},
})
const input = await screen.findByLabelText(TITLE)
await userEvent.type(input, USER_NOTADATESTRING)
await userEvent.tab()
await waitFor(() => {
expect(input).toHaveValue(EMPTY_DATESTRING)
})
})

test("it renders an input mask by default as user types", async () => {
render({
schema: dateTimeSchema,
})
const input = await screen.findByLabelText(TITLE)
await userEvent.click(input)
await waitFor(() => {
expect(input).toHaveValue(INPUT_MASK)
})
})

test("it renders form data for forms with existing values (edit)", async () => {
const data: Record<string, unknown> = {
dateTime: EXAMPLE_DATESTRING,
}
render({
schema: dateTimeSchema,
data,
})
const input = await screen.findByLabelText(TITLE)
expect(input).toHaveValue(RENDERED_DATESTRING)
})
35 changes: 30 additions & 5 deletions src/controls/DateTimeControl.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { memo } from "react"
import { memo, useCallback, useEffect } from "react"
import type { ControlProps as JSFControlProps } from "@jsonforms/core"
import { withJsonFormsControlProps } from "@jsonforms/react"
import { DatePicker, type DatePickerProps, Form } from "antd"
Expand Down Expand Up @@ -26,6 +26,19 @@ function getProps(options: unknown): DateTimeControlOptions {
return DEFAULT_PROPS
}

function getInitialValue(
data: unknown,
schemaDefault: unknown,
): string | undefined {
if (typeof data === "string" && data !== "") {
return data
}
if (typeof schemaDefault === "string" && schemaDefault !== "") {
return schemaDefault
}
return undefined
}

export function DateTimeControl({
handleChange,
path,
Expand All @@ -35,12 +48,25 @@ export function DateTimeControl({
schema,
uischema,
visible,
data,
}: ControlProps) {
const setInitialValue = useCallback(
(value: string | undefined) => {
const coercedValue = value ? dayjs(value) : value
handleChange(path, value)
return coercedValue
},
[handleChange, path],
)
const form = Form.useFormInstance()
useEffect(() => {
form.setFieldValue(
path,
setInitialValue(getInitialValue(data, schema.default)),
)
}, [data, form, path, schema.default, setInitialValue])
if (!visible) return null

const initialValue =
typeof schema.default === "string" ? dayjs(schema.default) : undefined

const rules: Rule[] = [{ required, message: `${label} is required` }]

const formItemProps =
Expand All @@ -60,7 +86,6 @@ export function DateTimeControl({
required={required}
validateTrigger={["onBlur"]}
rules={rules}
initialValue={initialValue}
{...formItemProps}
>
<DatePicker
Expand Down
11 changes: 11 additions & 0 deletions src/stories/controls/DateTimeControl.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,14 @@ export const DefaultValue: Story = {
uiSchema: dateTimeUISchema,
},
}

export const ExistingValue: Story = {
tags: ["autodocs"],
args: {
jsonSchema: dateTimeSchema,
uiSchema: dateTimeUISchema,
data: {
dateTime: "1999-12-31T23:59:59.999Z",
},
},
}
Loading