diff --git a/src/stories/Table.stories.tsx b/src/stories/Table.stories.tsx index 10286ea5..135ecf73 100644 --- a/src/stories/Table.stories.tsx +++ b/src/stories/Table.stories.tsx @@ -2,7 +2,7 @@ import { Box, ChakraProvider, Checkbox, extendTheme, Input, Select, Switch } fro import { EditableTable } from "../components/EditableTable" import type { ChangeEvent } from "react" import { colorSchemeOverrides, themeOverrides } from "../theme" -import type { Field, Fields, Info } from "../types" +import type { Field, Fields, Info, InitHook, RowHook, TableHook } from "../types" import type { Column, FormatterProps } from "react-data-grid" import { useRowSelection } from "react-data-grid" import { useMemo, useState } from "react" @@ -10,7 +10,9 @@ export default { title: "Validation table", } -type Errors = { [id: string]: { [key: string]: Info } } +type Meta = { __index: number; __errors?: Error | null } +type Error = { [key: string]: Info } +type Errors = { [id: string]: Error } const SELECT_COLUMN_KEY = "select-row" @@ -111,8 +113,29 @@ const fields: Fields = [ }, ] -const runValidation = >(data: T[], fields: Fields): Errors => { +const addErrorsAndRunHooks = >( + data: (T & Meta)[], + fields: Fields, + rowHook?: RowHook, + tableHook?: TableHook, +): (T & Meta)[] => { let errors: Errors = {} + + const addHookError = (rowIndex: number, fieldKey: keyof T, error: Info) => { + errors[rowIndex] = { + ...errors[rowIndex], + [fieldKey]: error, + } + } + + if (tableHook) { + data = addIndexes(tableHook(data, addHookError)) + } + + if (rowHook) { + data = addIndexes(data.map((value, index) => rowHook(value, (...props) => addHookError(index, ...props), data))) + } + fields.forEach((field) => { field.validations?.forEach((validation) => { switch (validation.rule) { @@ -165,27 +188,52 @@ const runValidation = >(data } }) }) - return errors + + return data.map((value, index) => { + if (errors[index]) { + return { ...value, __errors: errors[index] } + } + if (!errors[index] && value?.__errors) { + return { ...value, __errors: null } + } + return value + }) } -const addIndexes = (arr: T[]) => arr.map((val, index) => ({ ...val, __index: index })) +const addIndexes = (arr: T[]): (T & { __index: number })[] => + arr.map((value, index) => { + if ("__index" in value) { + return value as T & { __index: number } + } + return { ...value, __index: index } + }) const theme = extendTheme(colorSchemeOverrides, themeOverrides) +const defaultInitialHook = (rows: T): T => rows + interface Props { fields: Fields initialData: T[] + rowHook?: RowHook + tableHook?: TableHook + initialHook?: InitHook } -const TableComponent = ({ fields, initialData }: Props) => { - const [data, setData] = useState<(T & { __index: number })[]>(addIndexes(initialData)) - const [errors, setErrors] = useState(runValidation(data, fields)) +const TableComponent = ({ + fields, + initialData, + rowHook, + tableHook, + initialHook = defaultInitialHook, +}: Props) => { + const [data, setData] = useState<(T & Meta)[]>( + addErrorsAndRunHooks(addIndexes(initialHook(initialData)), fields, rowHook, tableHook), + ) const [selectedRows, setSelectedRows] = useState>(new Set()) const updateRow = (rows: typeof data) => { - setData(rows) - const a = runValidation(rows, fields) - setErrors(a) + setData(addErrorsAndRunHooks(rows, fields, rowHook, tableHook)) } const columns = useMemo( () => [ @@ -253,7 +301,7 @@ const TableComponent = ({ fields, initialData }: Props) => { row[column.key] ), cellClass: (row: typeof data[number]) => { - switch (errors[row.__index]?.[column.key]?.level) { + switch (row.__errors?.[column.key]?.level) { case "error": return "rdg-cell-error" case "warning": @@ -286,7 +334,26 @@ const TableComponent = ({ fields, initialData }: Props) => { export const Table = () => (
- + { + if (row.second !== "one") { + addError("second", { + level: "error", + message: "Whaaaat", + }) + } + return {...row, test: '123123'} + }} + tableHook={(rows, addError) => { + addError(2, "bool", { + level: "error", + message: "Error you in particular", + }) + return rows + }} + />
) diff --git a/src/types.ts b/src/types.ts index ed793c65..564703c9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -90,12 +90,9 @@ export type RegexValidation = { level?: ErrorLevel } -export type RowHook = (row: T, table: T[], addError: (fieldKey: keyof T, error: Info) => void) => Promise -export type TableHook = ( - table: T[], - addError: (fieldKey: keyof T, rowIndex: number, error: Info) => void, -) => Promise -export type InitHook = (table: T[]) => Promise +export type RowHook = (row: T, addError: (fieldKey: keyof T, error: Info) => void, table: T[]) => T +export type TableHook = (table: T[], addError: (rowIndex: number, fieldKey: keyof T, error: Info) => void) => T[] +export type InitHook = (table: T[]) => T[] export type ErrorLevel = "info" | "warning" | "error"