import { CellValue, ColumnType, ISelect, ITypeOptions, Language, LookupCellValue, SelectColor, } from '../../types'; import { exhaustiveSwitch, isNotNullable } from '../../typeUtils'; import { transformCellValueToString, transformCellValueToStringArray, } from './transformCellValueToString'; import { ICollaboratorsById } from './types'; import groupBy from 'lodash/groupBy'; import mapValues from 'lodash/mapValues'; import uniq from 'lodash/uniq'; export const transformCellValueToSelectOptionId = ({ originCellValue, originTypeOptions, targetTypeOptions, opts, }: { originCellValue: CellValue; originTypeOptions: ITypeOptions; targetTypeOptions: Pick< ITypeOptions, 'options' >; opts?: { locale?: Language; collaboratorsById?: ICollaboratorsById; }; }) => { const originColumnType = originTypeOptions.type; const originLookUpColumnType = originColumnType === ColumnType.LOOKUP && (originTypeOptions as ITypeOptions).lookupColumnType; if ( originColumnType === ColumnType.SELECT || originColumnType === ColumnType.MULTI_SELECT || (originColumnType === ColumnType.LOOKUP && (originLookUpColumnType === ColumnType.SELECT || originLookUpColumnType === ColumnType.MULTI_SELECT)) ) { if ( originColumnType === ColumnType.MULTI_SELECT || originColumnType === ColumnType.LOOKUP ) { const multiSelectCellValue = originCellValue as CellValue; if (multiSelectCellValue.length < 1) { return { optionId: null, optionNotFound: false, }; } } const originSelectOption = (() => { switch (originColumnType) { case ColumnType.SELECT: return originCellValue as CellValue; case ColumnType.MULTI_SELECT: // When converting MULTI_SELECT -> SELECT, we convert the first of the // selected options and ignore the rest. return (originCellValue as CellValue)[0]; case ColumnType.LOOKUP: return ( originCellValue as LookupCellValue< ColumnType.SELECT | ColumnType.MULTI_SELECT > )[0]; default: return exhaustiveSwitch({ switchValue: originColumnType, returnValue: null, }); } })(); if ( targetTypeOptions.options.find( ({ optionId: targetOptionId }) => targetOptionId === originSelectOption ) ) { return { optionId: originSelectOption, optionNotFound: false }; } const groupedTargetOptions = groupOptionsByNameAndColor( targetTypeOptions.options ); const selectTypeOptions = ( originColumnType === ColumnType.LOOKUP ? (originTypeOptions as ITypeOptions) .lookupTypeOptions : originTypeOptions ) as ITypeOptions; const targetOptionId = mapOriginOptionIdToTargetOptionId({ originOptionId: originSelectOption, originOptions: selectTypeOptions.options, groupedTargetOptions, }); return { optionId: targetOptionId, optionNotFound: targetOptionId === null, }; } const stringValue = transformCellValueToString({ cellValue: originCellValue, typeOptions: originTypeOptions, opts, }); if (stringValue === null) { return { optionId: null, optionNotFound: false, }; } const targetOption = targetTypeOptions.options.find( (option) => option.name.trim() === stringValue.trim() ); return { optionId: targetOption?.optionId ?? null, optionNotFound: !targetOption, }; }; export const transformCellValueToSelectOptionIdArray = ({ originCellValue, originTypeOptions, targetTypeOptions, opts = {}, }: { originCellValue: CellValue; originTypeOptions: ITypeOptions; targetTypeOptions: Pick< ITypeOptions, 'options' >; opts?: { locale?: Language; collaboratorsById?: ICollaboratorsById; }; }) => { const originColumnType = originTypeOptions.type; const originLookUpColumnType = originColumnType === ColumnType.LOOKUP && (originTypeOptions as ITypeOptions).lookupColumnType; if ( originColumnType === ColumnType.SELECT || originColumnType === ColumnType.MULTI_SELECT || (originColumnType === ColumnType.LOOKUP && (originLookUpColumnType === ColumnType.SELECT || originLookUpColumnType === ColumnType.MULTI_SELECT)) ) { const originSelectOptions = (() => { switch (originColumnType) { case ColumnType.SELECT: return [originCellValue as CellValue]; case ColumnType.MULTI_SELECT: return originCellValue as CellValue; case ColumnType.LOOKUP: return originCellValue as LookupCellValue< ColumnType.SELECT | ColumnType.MULTI_SELECT >; default: return exhaustiveSwitch({ switchValue: originColumnType, returnValue: [], }); } })(); const targetSelectOptionIds = new Set( targetTypeOptions.options.map(({ optionId }) => optionId) ); if ( originSelectOptions.every((originSelectOption) => targetSelectOptionIds.has(originSelectOption) ) ) { return { optionIds: originSelectOptions, optionNotFound: false, }; } const groupedTargetOptions = groupOptionsByNameAndColor( targetTypeOptions.options ); const selectTypeOptions = ( originColumnType === ColumnType.LOOKUP ? (originTypeOptions as ITypeOptions) .lookupTypeOptions : originTypeOptions ) as ITypeOptions; const targetOptionIds = uniq( originSelectOptions .map((optionId) => mapOriginOptionIdToTargetOptionId({ originOptionId: optionId, originOptions: selectTypeOptions.options, groupedTargetOptions, }) ) .filter(isNotNullable) ); return { optionIds: targetOptionIds.length === 0 ? null : targetOptionIds, optionNotFound: targetOptionIds.length < originSelectOptions.length, }; } const stringValues = uniq( transformCellValueToStringArray({ cellValue: originCellValue, typeOptions: originTypeOptions, opts, }) ); if (stringValues.length === 0) { return { optionIds: null, optionNotFound: false, }; } const targetOptionIds = stringValues .map((stringValue) => targetTypeOptions.options.find((option) => option.name.trim() === stringValue.trim()) ) .filter(isNotNullable) .map(({ optionId }) => optionId); return { optionIds: targetOptionIds.length === 0 ? null : targetOptionIds, optionNotFound: targetOptionIds.length < stringValues.length, }; }; const mapOriginOptionIdToTargetOptionId = ({ originOptionId, originOptions, groupedTargetOptions, }: { originOptionId: string; originOptions: ISelect[]; groupedTargetOptions: GroupedSelectOptions; }) => { const originOption = originOptions.find( ({ optionId }) => optionId === originOptionId ); if (!originOption) { return null; } const targetOption = mapOriginOptionToTargetOption({ originOption, groupedTargetOptions, }); if (!targetOption) { return null; } return targetOption.optionId; }; type GroupedSelectOptions = { [name: string]: { [key in SelectColor]?: ISelect[]; }; }; const mapOriginOptionToTargetOption = (args: { originOption: ISelect; groupedTargetOptions: GroupedSelectOptions; }) => { return mapOptionOnNameOnly(args); }; const mapOptionOnNameOnly = ({ originOption, groupedTargetOptions, }: { originOption: ISelect; groupedTargetOptions: GroupedSelectOptions; }) => { return ( Object.values(groupedTargetOptions[originOption.name.trim()] ?? {})[0]?.[0] ?? null ); }; const groupOptionsByNameAndColor = ( targetOptions: ISelect[] ): GroupedSelectOptions => { const groupByColor = (selectOptions: ISelect[]) => groupBy(selectOptions, (option) => option.color); const groupedByName = groupBy(targetOptions, (option) => option.name.trim()); const groupedByNameAndColor = mapValues(groupedByName, groupByColor); return groupedByNameAndColor; };