UNPKG

subhasmitalmg-react-spreadsheet-import

Version:

React spreadsheet import for xlsx and csv files with column matching and validation steps

102 lines (99 loc) 5.73 kB
import { jsxs, Fragment, jsx } from 'react/jsx-runtime'; import { useState, useCallback, useMemo, useEffect } from 'react'; import { useToast } from '@chakra-ui/react'; import { UserTableColumn } from './components/UserTableColumn.js'; import { useRsi } from '../../hooks/useRsi.js'; import { TemplateColumn } from './components/TemplateColumn.js'; import { ColumnGrid } from './components/ColumnGrid.js'; import { setColumn } from './utils/setColumn.js'; import { setIgnoreColumn } from './utils/setIgnoreColumn.js'; import { setSubColumn } from './utils/setSubColumn.js'; import { normalizeTableData } from './utils/normalizeTableData.js'; import { getMatchedColumns } from './utils/getMatchedColumns.js'; import { UnmatchedFieldsAlert } from '../../components/Alerts/UnmatchedFieldsAlert.js'; import { findUnmatchedRequiredFields } from './utils/findUnmatchedRequiredFields.js'; var ColumnType; (function (ColumnType) { ColumnType[ColumnType["empty"] = 0] = "empty"; ColumnType[ColumnType["ignored"] = 1] = "ignored"; ColumnType[ColumnType["matched"] = 2] = "matched"; ColumnType[ColumnType["matchedCheckbox"] = 3] = "matchedCheckbox"; ColumnType[ColumnType["matchedSelect"] = 4] = "matchedSelect"; ColumnType[ColumnType["matchedSelectOptions"] = 5] = "matchedSelectOptions"; })(ColumnType || (ColumnType = {})); const MatchColumnsStep = ({ data, headerValues, onContinue }) => { const toast = useToast(); const dataExample = data.slice(0, 2); const { fields, autoMapHeaders, autoMapSelectValues, autoMapDistance, translations } = useRsi(); const [isLoading, setIsLoading] = useState(false); const [columns, setColumns] = useState( // Do not remove spread, it indexes empty array elements, otherwise map() skips over them [...headerValues].map((value, index) => ({ type: ColumnType.empty, index, header: value ?? "" }))); const [showUnmatchedFieldsAlert, setShowUnmatchedFieldsAlert] = useState(false); const onChange = useCallback((value, columnIndex) => { const field = fields.find((field) => field.key === value); const existingFieldIndex = columns.findIndex((column) => "value" in column && column.value === field.key); setColumns(columns.map((column, index) => { columnIndex === index ? setColumn(column, field, data) : column; if (columnIndex === index) { return setColumn(column, field, data, autoMapSelectValues); } else if (index === existingFieldIndex) { toast({ status: "warning", variant: "left-accent", position: "bottom-left", title: translations.matchColumnsStep.duplicateColumnWarningTitle, description: translations.matchColumnsStep.duplicateColumnWarningDescription, isClosable: true, }); return setColumn(column); } else { return column; } })); }, [ autoMapSelectValues, columns, data, fields, toast, translations.matchColumnsStep.duplicateColumnWarningDescription, translations.matchColumnsStep.duplicateColumnWarningTitle, ]); const onIgnore = useCallback((columnIndex) => { setColumns(columns.map((column, index) => (columnIndex === index ? setIgnoreColumn(column) : column))); }, [columns, setColumns]); const onRevertIgnore = useCallback((columnIndex) => { setColumns(columns.map((column, index) => (columnIndex === index ? setColumn(column) : column))); }, [columns, setColumns]); const onSubChange = useCallback((value, columnIndex, entry) => { setColumns(columns.map((column, index) => columnIndex === index && "matchedOptions" in column ? setSubColumn(column, entry, value) : column)); }, [columns, setColumns]); const unmatchedRequiredFields = useMemo(() => findUnmatchedRequiredFields(fields, columns), [fields, columns]); const handleOnContinue = useCallback(async () => { if (unmatchedRequiredFields.length > 0) { setShowUnmatchedFieldsAlert(true); } else { setIsLoading(true); await onContinue(normalizeTableData(columns, data, fields), data, columns); setIsLoading(false); } }, [unmatchedRequiredFields.length, onContinue, columns, data, fields]); const handleAlertOnContinue = useCallback(async () => { setShowUnmatchedFieldsAlert(false); setIsLoading(true); await onContinue(normalizeTableData(columns, data, fields), data, columns); setIsLoading(false); }, [onContinue, columns, data, fields]); useEffect(() => { if (autoMapHeaders) { setColumns(getMatchedColumns(columns, fields, data, autoMapDistance, autoMapSelectValues)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (jsxs(Fragment, { children: [jsx(UnmatchedFieldsAlert, { isOpen: showUnmatchedFieldsAlert, onClose: () => setShowUnmatchedFieldsAlert(false), fields: unmatchedRequiredFields, onConfirm: handleAlertOnContinue }), jsx(ColumnGrid, { columns: columns, onContinue: handleOnContinue, isLoading: isLoading, userColumn: (column) => (jsx(UserTableColumn, { column: column, onIgnore: onIgnore, onRevertIgnore: onRevertIgnore, entries: dataExample.map((row) => row[column.index]) })), templateColumn: (column) => jsx(TemplateColumn, { column: column, onChange: onChange, onSubChange: onSubChange }) })] })); }; export { ColumnType, MatchColumnsStep };