diff --git a/packages/table/src/declarations.ts b/packages/table/src/declarations.ts index 95143421..c44cb465 100644 --- a/packages/table/src/declarations.ts +++ b/packages/table/src/declarations.ts @@ -108,6 +108,9 @@ export type TRowDef = { evenOddType: 'even' | 'odd'; striped: boolean; }) => CSSProp); + context?: { + [key: string]: unknown; + }; }; export type TCellDef = { diff --git a/packages/table/src/filters/DateFilter/DateFilter.tsx b/packages/table/src/filters/DateFilter/DateFilter.tsx index 4afb6731..fd49c10d 100644 --- a/packages/table/src/filters/DateFilter/DateFilter.tsx +++ b/packages/table/src/filters/DateFilter/DateFilter.tsx @@ -1,36 +1,131 @@ import * as React from 'react'; import { DateTimeFloatingPicker } from '@devoinc/genesys-ui-datetime'; -import { SelectControl } from '@devoinc/genesys-ui'; - import { - AdvancedFilter, - BasicFilter, - DATE_OPTIONS, - FilterContainer, -} from '../common'; -import type { TFilter } from '../../declarations'; + HFlex, + IconButton, + Menu, + Popover, +} from '@devoinc/genesys-ui'; +import { GIExitClose, GIFilter } from '@devoinc/genesys-icons'; + +import { DATE_OPTIONS, FilterContainer } from '../common'; +import type { TFilter, TFilterContext } from '../../declarations'; +import type { TDateFilterValue } from './declarations'; + +export const DateFilter: React.FC = ({ colDef, onChange }) => { + const context = colDef?.context as TFilterContext; + const filterValue = context?.filterValue as TDateFilterValue; + const value = filterValue?.value ?? null; + const secondValue = filterValue?.secondValue ?? null; + const operator = filterValue?.operator ?? 'equals'; + return ( + + + { + onChange( + { + value: newValue, + secondValue, + operator, + }, + 'date', + ); + }} + /> + + {operator === 'between' && ( + + { + onChange( + { + value, + secondValue: newSecondValue, + operator, + }, + 'date', + ); + }} + /> + + )} + + {(context?.showReset ?? true) && + (value !== null || operator !== 'equals') && ( + + } + onClick={() => { + onChange( + { + value: null, + operator: 'equals', + } as TDateFilterValue, + 'number', + ); + }} + size="sm" + colorScheme="quiet" + /> + + )} -export const DateFilter: React.FC = ({ colDef }) => ( - - - undefined} - onCancel={() => undefined} - /> - - - setValue(opt.value)} - options={DATE_OPTIONS} - // value={value} - /> - undefined} - onCancel={() => undefined} - /> - - -); + {(context?.showAdvancedFilter ?? true) && ( + + + {({ toggle, ref, isOpened }) => ( + } + onClick={toggle} + ref={ref} + state={isOpened ? 'expanded' : undefined} + size="sm" + colorScheme="quiet" + /> + )} + {({ setOpened }) => ( + + + {DATE_OPTIONS.map((option) => ( + { + onChange( + { + value, + secondValue, + operator: option.value, + } as TDateFilterValue, + 'date', + ); + setOpened(false); + }} + key={option.value} + state={operator === option.value ? 'selected' : 'enabled'} + name="options" + value={option.value} + label={option.label} + /> + ))} + + + )} + + + )} + + ); +}; diff --git a/packages/table/src/filters/DateFilter/declarations.ts b/packages/table/src/filters/DateFilter/declarations.ts new file mode 100644 index 00000000..9575b956 --- /dev/null +++ b/packages/table/src/filters/DateFilter/declarations.ts @@ -0,0 +1,12 @@ +export type TDateFilterValue = { + value: number | Date; + secondValue?: number | Date; + operator: + | 'equals' + | 'notEquals' + | 'greater' + | 'greaterOrEqual' + | 'less' + | 'lessOrEqual' + | 'between'; +}; diff --git a/packages/table/stories/table/Filters.mdx b/packages/table/src/filters/Filters.mdx similarity index 100% rename from packages/table/stories/table/Filters.mdx rename to packages/table/src/filters/Filters.mdx diff --git a/packages/table/stories/table/Filters.stories.tsx b/packages/table/src/filters/Filters.stories.tsx similarity index 64% rename from packages/table/stories/table/Filters.stories.tsx rename to packages/table/src/filters/Filters.stories.tsx index 95ff8f94..586d7e9e 100644 --- a/packages/table/stories/table/Filters.stories.tsx +++ b/packages/table/src/filters/Filters.stories.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; import { Meta, StoryObj } from '@storybook/react'; -import { InputControl, Menu } from '@devoinc/genesys-ui'; +import { Menu } from '@devoinc/genesys-ui'; import { type TContextOptions, type TFilterContext, - filterDataByText, filterDataByFilterStruct, useFilterStruct, updateColDefsWithFilterStruct, @@ -27,16 +26,76 @@ export default meta; type Story = StoryObj; const data = [ - { text: 'Christine Jimenez', num: 60, bool: false, option: 'A' }, - { text: 'Ina Osborne', num: 20, bool: true, option: 'B' }, - { text: 'Jimmy Hogan', num: 20, bool: true, option: 'C' }, - { text: 'Myra Bell', num: 57, bool: true, option: 'C' }, - { text: 'Jane Padilla', num: 46, bool: false, option: 'B' }, - { text: 'Isabelle Gardner', num: 31, bool: true, option: 'A' }, - { text: 'Sean Parsons', num: 31, bool: true, option: 'A' }, - { text: 'Alvin Castro', num: 55, bool: false, option: 'B' }, - { text: 'Lawrence Holland', num: 56, bool: false, option: 'B' }, - { text: 'Brandon Robertson', num: 41, bool: true, option: 'C' }, + { + text: 'Christine Jimenez', + num: 60, + date: new Date(2024, 9, 1, 0, 0, 0), + bool: false, + option: 'A', + }, + { + text: 'Ina Osborne', + num: 20, + date: new Date(2024, 9, 2, 0, 0, 0), + bool: true, + option: 'B', + }, + { + text: 'Jimmy Hogan', + num: 20, + date: new Date(2024, 9, 3, 0, 0, 0), + bool: true, + option: 'C', + }, + { + text: 'Myra Bell', + num: 57, + date: new Date(2024, 9, 4, 0, 0, 0), + bool: true, + option: 'C', + }, + { + text: 'Jane Padilla', + num: 46, + date: new Date(2024, 9, 5, 0, 0, 0), + bool: false, + option: 'B', + }, + { + text: 'Isabelle Gardner', + num: 31, + date: new Date(2024, 9, 6, 0, 0, 0), + bool: true, + option: 'A', + }, + { + text: 'Sean Parsons', + num: 31, + date: new Date(2024, 9, 7, 0, 0, 0), + bool: true, + option: 'A', + }, + { + text: 'Alvin Castro', + num: 55, + date: new Date(2024, 9, 8, 0, 0, 0), + bool: false, + option: 'B', + }, + { + text: 'Lawrence Holland', + num: 56, + date: new Date(2024, 9, 9, 0, 0, 0), + bool: false, + option: 'B', + }, + { + text: 'Brandon Robertson', + num: 41, + date: new Date(2024, 9, 10, 0, 0, 0), + bool: true, + option: 'C', + }, ]; const colDefs = [ @@ -55,6 +114,15 @@ const colDefs = [ showReset: true, } as TFilterContext, }, + { + id: 'date', + headerName: 'Date', + preset: 'date', + context: { + showAdvancedFilter: true, + showReset: true, + } as TFilterContext, + }, { id: 'bool', headerName: 'Boolean', @@ -193,73 +261,3 @@ const FilterAndBulkActionsTable = () => { export const FiltersAndBulkActions: Story = { render: () => , }; - -const GlobalTextFilterTable = () => { - - const colDefs = [ - { - id: 'text', - headerName: 'Text', - preset: 'text', - }, - { - id: 'num', - headerName: 'Number', - preset: 'number', - context: { - showAdvancedFilter: true, - showReset: true, - } as TFilterContext, - }, - { - id: 'bool', - headerName: 'Boolean', - preset: 'boolean', - }, - { - id: 'option', - headerName: 'Options', - preset: 'options', - context: { - options: { - A: { label: 'Option A' }, - B: { label: 'Option B' }, - C: { label: 'Option C' }, - }, - } as TContextOptions, - }, - ]; - - const [ textFilter, setTextFilter ] = React.useState(undefined); - const { filterStruct, onFilter } = useFilterStruct(); - const dataFiltered = [...data] - .filter(filterDataByText(textFilter, colDefs)) - .filter(filterDataByFilterStruct(filterStruct)); - - return ( - <> - { - setTextFilter(ev.target.value); - }} - /> - { - onFilter(curColDef.id, value, type); - }} - colDefs={updateColDefsWithFilterStruct(colDefs, filterStruct)} - data={dataFiltered} - /> - - ); -}; - -export const GlobalTextFilter: Story = { - render: () => , -}; - diff --git a/packages/table/src/filters/index.ts b/packages/table/src/filters/index.ts index ea3dc60e..0799925e 100644 --- a/packages/table/src/filters/index.ts +++ b/packages/table/src/filters/index.ts @@ -1,4 +1,5 @@ export * from './BooleanFilter'; +export * from './DateFilter'; export * from './TextFilter'; export * from './NumberFilter'; export * from './OptionsFilter'; diff --git a/packages/table/src/presets/column/date.ts b/packages/table/src/presets/column/date.ts index dc00269f..c2dd9350 100644 --- a/packages/table/src/presets/column/date.ts +++ b/packages/table/src/presets/column/date.ts @@ -4,6 +4,7 @@ import { TColDef } from '../../declarations'; import { TextRenderer } from '../../renderers'; import { dateFormatter } from '../../valueFormatters'; import { DateEditor } from '../../editors'; +// import { DateFilter } from '../../filters'; export const date: TColDef = { id: 'date', @@ -11,8 +12,9 @@ export const date: TColDef = { valueFormatter: dateFormatter, cellEditor: DateEditor, context: { - formatDate: 'dd/MM/yyyy HH:mm:ss', + formatDate: 'yyyy-MM-dd HH:mm:ss', tz: 'Europe/Madrid', locale: enUS, }, + // cellFilter: DateFilter, }; diff --git a/packages/table/src/presets/helpers/mergePresets.ts b/packages/table/src/presets/helpers/mergePresets.ts index b08a7df0..bd78d6f7 100644 --- a/packages/table/src/presets/helpers/mergePresets.ts +++ b/packages/table/src/presets/helpers/mergePresets.ts @@ -14,7 +14,16 @@ export const mergePresets = defaultDefinitions: TDefaultColDef | TDefaultRowDef, ) => () => - definitions.map((row) => { - const preset = presets.find((element) => element.id === row.preset); - return { ...defaultDefinitions, ...preset, ...row }; + definitions.map((rowOrCol: TRowDef | TColDef) => { + const preset = presets.find((element) => element.id === rowOrCol.preset); + return { + ...defaultDefinitions, + ...preset, + ...rowOrCol, + context: { + ...defaultDefinitions?.context, + ...preset?.context, + ...rowOrCol?.context, + }, + }; }); diff --git a/packages/table/src/valueFormatters/date/date.tsx b/packages/table/src/valueFormatters/date/date.tsx index b65d6d47..41d80830 100644 --- a/packages/table/src/valueFormatters/date/date.tsx +++ b/packages/table/src/valueFormatters/date/date.tsx @@ -8,12 +8,11 @@ export interface DateContext { locale?: Locale; } -// prettier-ignore export const dateFormatter = (value: unknown, context: DateContext): string => !isValid(value) || (typeof value === 'number' && value < 0) ? String(value) : format( - utcToZonedTime(value as string | number | Date, context.tz), - context?.formatDate ?? 'PPpp', - { locale: context?.locale || enUS }, - ); + utcToZonedTime(value as string | number | Date, context.tz), + context?.formatDate ?? 'PPpp', + { locale: context?.locale || enUS }, + );