diff --git a/README.md b/README.md index 2ee2e03e..99980b01 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,13 @@ Example `data`: } ``` +### onHeadersMapped (_function_) +Callback function that fires when headers have been mapped (when you dont want to wait for onComplete and you just want the mapped headers and the original uploaded file). It returns `selectedHeaderRow` which tells which row was selected as a header row in the previous step, `mappedHeaders` an object that contains the mapping definitions and `originalFile` which is the `File` object representing the original uploaded file without any modifications to it. +When `onHeadersMapped` is defined, `onComplete` callback will not be fired. +```jsx +onHeadersMapped={(selectedHeaderRow, mappedHeaders, originalFile) => console.log(mappedHeaders)} +``` + ### darkMode (_boolean_, default: `false`) Toggle between dark mode (`true`) and light mode (`false`). diff --git a/package.json b/package.json index 387d49fe..215c4d84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "csv-import-react", - "version": "1.0.11", + "version": "1.1.2", "description": "Open-source CSV and XLS/XLSX file importer for React and JavaScript", "main": "build/index.js", "module": "build/index.esm.js", diff --git a/src/components/CSVImporter/index.tsx b/src/components/CSVImporter/index.tsx index 2f79feeb..4ad023ed 100644 --- a/src/components/CSVImporter/index.tsx +++ b/src/components/CSVImporter/index.tsx @@ -22,6 +22,7 @@ const CSVImporter = forwardRef((importerProps: CSVImporterProps, forwardRef?: an customStyles, showDownloadTemplateButton, skipHeaderRowSelection, + onHeadersMapped, ...props } = importerProps; const ref = forwardRef ?? useRef(null); diff --git a/src/importer/features/main/index.tsx b/src/importer/features/main/index.tsx index 28c012fb..84bd0dbc 100644 --- a/src/importer/features/main/index.tsx +++ b/src/importer/features/main/index.tsx @@ -25,6 +25,7 @@ export default function Main(props: CSVImporterProps) { modalOnCloseTriggered = () => null, template, onComplete, + onHeadersMapped, customStyles, showDownloadTemplateButton, skipHeaderRowSelection, @@ -40,6 +41,7 @@ export default function Main(props: CSVImporterProps) { // Error handling const [initializationError, setInitializationError] = useState(null); const [dataError, setDataError] = useState(null); + const [originalFile, setOriginalFile] = useState(null); // File data const emptyData = { @@ -87,6 +89,7 @@ export default function Main(props: CSVImporterProps) { setColumnMapping({}); setDataError(null); setStep(StepEnum.Upload); + setOriginalFile(null); }; const requestClose = () => { @@ -118,6 +121,8 @@ export default function Main(props: CSVImporterProps) { setDataError={setDataError} onSuccess={async (file: File) => { setDataError(null); + setOriginalFile(file); + const fileType = file.name.slice(file.name.lastIndexOf(".") + 1); if (!["csv", "xls", "xlsx"].includes(fileType)) { setDataError("Only CSV, XLS, and XLSX files can be uploaded"); @@ -196,6 +201,18 @@ export default function Main(props: CSVImporterProps) { onSuccess={(columnMapping) => { setIsSubmitting(true); setColumnMapping(columnMapping); + if (onHeadersMapped) { + onHeadersMapped(selectedHeaderRow, columnMapping, originalFile) + .then(() => { + setIsSubmitting(false); + goNext(); + }) + .catch((error) => { + console.error("onHeadersMapped error", error); + setDataError("An error occurred while processing the data"); + }); + return; + } // TODO (client-sdk): Move this type, add other data attributes (i.e. column definitions), and move the data processing to a function type MappedRow = { diff --git a/src/types/index.ts b/src/types/index.ts index 1a8961d2..18b03c64 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,5 @@ import { HTMLAttributes } from "react"; +import { TemplateColumnMapping } from "../importer/features/map-columns/types"; type ModalParams = { isModal?: boolean; @@ -14,6 +15,7 @@ export type CSVImporterProps = (HTMLAttributes & HTMLAttribut className?: string; onComplete?: (data: any) => void; waitOnComplete?: boolean; + onHeadersMapped?: (selectedHeaderRow: number | null, mappedHeaders: { [index: number]: TemplateColumnMapping }, originalFile: File | null) => Promise; customStyles?: Record | string; showDownloadTemplateButton?: boolean; skipHeaderRowSelection?: boolean;