Skip to content

Commit

Permalink
chore: Let FormView handle initial / default data based on the schema
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Nov 13, 2024
1 parent 2c28dd9 commit 589aa0e
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 4 deletions.
64 changes: 60 additions & 4 deletions packages/ssi-react/src/components/views/FormView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {CSSProperties, FC, ReactElement} from 'react'
import {CSSProperties, ReactElement, useEffect, useState} from 'react'
import {JsonForms} from '@jsonforms/react'
import {
JsonFormsCellRendererRegistryEntry,
Expand All @@ -12,6 +12,7 @@ import {materialCells} from '@jsonforms/material-renderers'
import {jsonFormsMaterialRenderers} from '../../../renders/jsonFormsRenders'
import {JSONFormState} from '../../../types'
import Ajv from 'ajv'
import {DateFormat, formatDateToISO} from '../../../helpers/date/DateHelper'

type Props<DataType = Record<any, any>> = {
schema: JsonSchema
Expand All @@ -28,7 +29,43 @@ type Props<DataType = Record<any, any>> = {
config?: any
}

const FormView: FC<Props> = (props: Props<any>): ReactElement => {
const initializeDefaultValues = (schema: JsonSchema, currentData: Record<string, any> = {}): Record<string, any> => {
const result = {...currentData}

if (!schema.properties) {
return result
}

Object.entries(schema.properties).forEach(([key, property]) => {
if (typeof property === 'object') {
// Handle const values
if (property.const && (!(key in result) || !result[key])) {
result[key] = property.const
}

// Handle default values
if (property.default && (!(key in result) || !result[key])) {
if (property.format?.startsWith('date') || property.format?.startsWith('time')) {
result[key] = formatDateToISO(property.default, property.format as DateFormat)
} else {
result[key] = property.default
}
}

// Recursively handle nested objects
if (property.properties) {
if (!result[key]) {
result[key] = {}
}
result[key] = initializeDefaultValues(property as JsonSchema, result[key])
}
}
})

return result
}

const FormView = (props: Props): ReactElement => {
const {
data,
schema,
Expand All @@ -44,16 +81,35 @@ const FormView: FC<Props> = (props: Props<any>): ReactElement => {
config,
} = props

const [formData, setFormData] = useState<Record<string, any>>(data ?? {})

useEffect(() => {
// Initialize or update form data with schema defaults
const initializedData = initializeDefaultValues(schema, formData)
setFormData(initializedData)
}, [schema])

const onFormStateChanged = (state: JSONFormState): void => {
void onFormStateChange?.(state)
const updatedData = initializeDefaultValues(schema, state.data)

// Only update if data actually changed to avoid loops
if (JSON.stringify(updatedData) !== JSON.stringify(state.data)) {
setFormData(updatedData)
void onFormStateChange?.({
...state,
data: updatedData,
})
} else {
void onFormStateChange?.(state)
}
}

return (
<div style={style}>
<JsonForms
schema={schema}
uischema={uiSchema}
data={data}
data={formData}
renderers={renderers}
cells={cells}
onChange={onFormStateChanged}
Expand Down
56 changes: 56 additions & 0 deletions packages/ssi-react/src/helpers/date/DateHelper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export type DateFormat = 'date-time' | 'date' | 'time' | undefined

export const formatDate = (dateString?: string, format: DateFormat = 'date-time'): string => {
const userDateTimeOpts = Intl.DateTimeFormat().resolvedOptions()

if (!dateString) {
return ''
}

const date = dateString === 'now' ? new Date() : new Date(dateString)
if (isNaN(date.getTime())) {
console.error('Invalid date:', dateString)
return 'Invalid date'
}

const formatOptions: Intl.DateTimeFormatOptions = {
timeZone: userDateTimeOpts.timeZone
}

if (format === 'date-time') {
formatOptions.dateStyle = 'short'
formatOptions.timeStyle = 'short'
} else if (format === 'date') {
formatOptions.dateStyle = 'short'
} else if (format === 'time') {
formatOptions.timeStyle = 'short'
}

return new Intl.DateTimeFormat(
userDateTimeOpts.locale,
formatOptions
).format(date)
}


export const formatDateToISO = (dateString?: string, format: DateFormat = 'date-time'): string => {
if (!dateString) {
return ''
}

const date = dateString === 'now' ? new Date() : new Date(dateString)
if (isNaN(date.getTime())) {
console.error('Invalid date:', dateString)
return 'Invalid date'
}

const isoString = date.toISOString()

if (format === 'date-time') {
return isoString.slice(0, 19).replace('T', ' ') // YYYY-MM-DD HH:mm:ss
} else if (format === 'date') {
return isoString.slice(0, 10) // YYYY-MM-DD
} else {
return isoString.slice(11, 19) // HH:mm:ss
}
}

0 comments on commit 589aa0e

Please sign in to comment.