import {FieldItem, FieldRow, FieldType} from "../fields"; import {CouponsPlus} from "../../globals"; import React from "react"; import {MultiSelectProps} from "../fields/MultiSelect"; //import {type CardType, type fieldMeta} from "../cards"; import {PartialDeep} from "type-fest"; import {ComponentMeta} from "../ComponentsMeta"; import {merge} from "lodash"; import {InclusionValueValidatorFields} from "../InclusionValueValidatorFields"; export type InclusionValueValidatorOptions = { inclusionType: 'allowed' | 'forbidden' | 'allowed-except-forbidden', expectedValues: ExpectedValue[], excludedSubsetValues: string[], // optional only when supportsExcludingSubset is true enableExcludedSubsetValues: boolean, // optional only when supportsExcludingSubset is true } export type InclusionValueValidatorFieldsMeta = { excludedSubsetValues: fieldMeta<{ supportsExcludingSubset: boolean }>, } export const inclusionValueValidatorFieldsMap = ( type: ComponentMeta['type'], id: ComponentMeta['id'], selectExtraFieldProps?: FieldItem>, InclusionValueValidatorOptions>['fieldProps'], expectedValuesKey: string = 'expectedValues', selectExtraFieldOptions: Record = {}, fieldsBetween: FieldRow[] = [], // unused I believe, so deprecated supportedComponents?: { inclusionType?: boolean, expectedValues?: boolean, }, ) => { supportedComponents = merge({inclusionType: true, expectedValues: true}, supportedComponents); // Lazy getter function to avoid circular dependency const getComponentMetaData = () => { return CouponsPlus.components[type][id] as CardType; }; const getInclusionTypeField = () => { const componentMetaData = getComponentMetaData(); // @ts-ignore return componentMetaData?.fields?.['inclusionType']?.meta?.extraLabels as PartialDeep<{ allowed: { placeholder: string, aboveList: string }, forbidden: { placeholder: string, aboveList: string } }>; }; const getExcludedSubsetValuesField = () => { const componentMetaData = getComponentMetaData(); return componentMetaData?.fields?.['excludedSubsetValues']?.meta?.extraLabels as PartialDeep<{ allowed: { placeholder: string, aboveList: string }, }>; }; const getSupportsExcludingSubset = () => { const componentMetaData = getComponentMetaData(); const meta = componentMetaData?.fields?.['excludedSubsetValues']?.meta; // @ts-ignore return meta?.supportsExcludingSubset || false; }; return [ [ { id: 'inclusionType', renderType: FieldType.Custom, fieldProps: (options: InclusionValueValidatorOptions, onUpdate, {componentRuntimeData, field}) => { const componentMetaData = getComponentMetaData(); const inclusionTypeField = getInclusionTypeField(); const expectedValuesMeta = componentMetaData?.fields?.[expectedValuesKey]?.meta; const expectedValuesOptions = expectedValuesMeta?.__allowed || {}; return { component: } } } ], ...[/*supportedComponents.inclusionType && [ {id: 'inclusionType', renderType: FieldType.Tab, fieldProps: {size: 'normal'}}, ], ...fieldsBetween, supportedComponents.expectedValues && [ { id: expectedValuesKey, renderType: FieldType.MultiSelect, // merge here is probably terrible for performance (re-renders) but it will have to do for now fieldProps: (options: InclusionValueValidatorOptions) => { const inclusionTypeField = getInclusionTypeField(); return merge({ SelectSearchProps: { placeholder: () => { if (options.inclusionType === 'allowed') { return inclusionTypeField?.allowed?.placeholder || __('Search items to include...') } return inclusionTypeField?.forbidden?.placeholder || __('Search items to exclude...') }, }, SelectStateProps: { labels: { above: inclusionTypeField?.[options.inclusionType]?.aboveList }, defaultItemOptions: { beforeLabel(): React.ReactNode { if (options.inclusionType === 'forbidden') { return } return } }, } }, (typeof selectExtraFieldProps === 'function' ? selectExtraFieldProps(options) : selectExtraFieldProps) || {} ); }, fieldOptions: selectExtraFieldOptions } as FieldItem, InclusionValueValidatorOptions>, ], [ { id: 'enableExcludedSubsetValues', wrap: Wrapped, renderType: ({inclusionType, expectedValues, enableExcludedSubsetValues}) => { const supportsExcludingSubset = getSupportsExcludingSubset(); return supportsExcludingSubset && inclusionType === 'allowed' && expectedValues.length && !enableExcludedSubsetValues && FieldType.Button; }, fieldProps: { children: __('Exclude items...'), onClick: (updateField: UpdateField, onUpdate) => { updateField(true) } } } ], [ { id: 'excludedSubsetValues', title: __('Excluding items'), renderType: ({inclusionType, excludedSubsetValues, enableExcludedSubsetValues}) => { const supportsExcludingSubset = getSupportsExcludingSubset(); return (supportsExcludingSubset && enableExcludedSubsetValues && inclusionType === 'allowed' && FieldType.MultiSelect); }, wrap: Wrapped, fieldProps: (options: InclusionValueValidatorOptions) => { const excludedSubsetValuesField = getExcludedSubsetValuesField(); return merge({ SelectSearchProps: { placeholder: () => { return excludedSubsetValuesField?.[options.inclusionType]?.placeholder }, }, SelectStateProps: { labels: { above: excludedSubsetValuesField?.[options.inclusionType]?.aboveList }, defaultItemOptions: { beforeLabel(): React.ReactNode { return } }, } }, (typeof selectExtraFieldProps === 'function' ? selectExtraFieldProps(options) : selectExtraFieldProps) || {} ); } } as FieldItem, InclusionValueValidatorOptions>, ],*/] ].filter(field => Array.isArray(field) ? field.length : true); }