import { ColumnStyleWidth, ColumnWidths, sourceTypes, ColumnAlignments, ColumnAlignment, columnTypeDefaultAlignment, } from '@adalo/constants' import _ from 'lodash' import { IObject } from 'interfaces' import { Platform } from 'react-native' import type { CellData, BindingDataItem, CellStyle, TableSort, TableState, FieldValue, Field, } from './TableTypes' export const formatLocation = (field: CellData): string => { if (!field.value) { return '' } const bindingFormat = field.binding?.format?.locationFormat ?? '' if ( typeof bindingFormat !== 'string' || !bindingFormat.length || bindingFormat.length === 0 ) { return '' } const { value } = field const keyPath = bindingFormat?.split('.') ?? '' return _.get(value, keyPath, '') } const getBindingDataItemValue = ( bindingDataItem: BindingDataItem, field: Field ): FieldValue => { const list = _.get(bindingDataItem, `${field.fieldId}_value`, undefined) const count = _.get(bindingDataItem, `${field.fieldId}_count`, undefined) // 1:m, m:m if (field.binding.source.type === sourceTypes.COUNT) { if (typeof count === 'number') { return count } else if (typeof list !== 'undefined' && Array.isArray(list)) { // Depending on how Runner calculates its dependencies, the "count" may be // return as an array of objects which we can get the length of return list.length } // m:1 } else if ( typeof list === 'object' && typeof field.binding.source.fieldId !== 'undefined' ) { return _.get(list, field.binding.source.fieldId, '') } else if (typeof field.binding.source.fieldId !== 'undefined') { return _.get(bindingDataItem, field.binding.source.fieldId, '') } // fallback return _.get(bindingDataItem, field.fieldId, '') } export const getBindingData = ( object: IObject, bindingData: BindingDataItem[] ): TableState => { const fields = object?.attributes.fields if (!fields || !Array.isArray(fields) || fields.length === 0) { return { columns: [], data: [] } } const tableSort = object.dataBinding?.source?.sort as TableSort const columns = fields.map(field => { const { label, binding } = field let sort = null if (tableSort && tableSort.fieldId === binding.source.fieldId) { sort = tableSort.direction } return { label, style: getColumnStyle(field), sort, } }) const data = bindingData.map(bindingDataItem => { const cells = fields.map(field => ({ fieldId: field.fieldId, type: field.binding.source.dataType, value: getBindingDataItemValue(bindingDataItem, field), label: field.label, binding: field.binding, style: getColumnStyle(field), })) const { id } = bindingDataItem return { id, cells } }) return { columns, data } } export const getColumnTypeDefaultAlignment = ( fieldType?: Field['type'] ): ColumnAlignment => { if (typeof fieldType === 'string') { return columnTypeDefaultAlignment[fieldType] ?? ColumnAlignments.center } return ColumnAlignments.center } export const getFieldColumnAlignment = ( field?: Partial ): ColumnAlignment => { if (field?.binding?.format?.columnAlignment) { return field?.binding?.format?.columnAlignment } return getColumnTypeDefaultAlignment(field?.type) } const flexMap = { [ColumnWidths.narrow]: 1, [ColumnWidths.standard]: 2, [ColumnWidths.wide]: 4, } as const type AlignItems = CellStyle['alignItems'] const alignmentMap: Record = { [ColumnAlignments.left]: 'flex-start', [ColumnAlignments.center]: 'center', [ColumnAlignments.right]: 'flex-end', } export const getColumnStyleAlignItemProp = ( columnAlignment: ColumnAlignment ): AlignItems => { const alignItems = alignmentMap[columnAlignment] ?? 'center' // default to 'center' return alignItems } export const getColumnStyle = (field?: Partial): CellStyle => { const columnWidth = field?.binding?.format?.columnWidth ?? ColumnWidths.standard const columnAlignment = getFieldColumnAlignment(field) const alignItems = getColumnStyleAlignItemProp(columnAlignment) return { [getColumnStyleWidthProp()]: ColumnStyleWidth[columnWidth], flex: flexMap[columnWidth], alignItems, } } export const getShouldFreezeFirstColumn = (obj: IObject) => Boolean(obj.attributes?.fields?.[0]?.binding?.format?.shouldFreezeFirstColumn) export const getColumnStyleWidthProp = () => Platform.OS === 'web' ? 'minWidth' : 'width' export const getStyleWidthValue = (style: CellStyle) => style[getColumnStyleWidthProp()] ?? 0