From d16235aa4c424235f5be0a833cc48baf1386b6fe Mon Sep 17 00:00:00 2001 From: gitstart-twenty Date: Thu, 22 Aug 2024 14:44:22 +0000 Subject: [PATCH] prevent data loss after go from step 3 to step 2 --- .../components/SpreadsheetImportProvider.tsx | 7 +++- .../MatchColumnsStep/MatchColumnsStep.tsx | 35 ++++++++++------ .../components/SubMatchingSelect.tsx | 1 - .../components/TemplateColumn.tsx | 7 ++-- .../states/initialComputedColumnsState.ts | 41 +++++++++++++++++++ .../components/SpreadsheetImportStepper.tsx | 5 ++- 6 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts diff --git a/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx b/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx index 88041e2718d1..6e93d3dfb650 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/provider/components/SpreadsheetImportProvider.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useSetRecoilState } from 'recoil'; import { spreadsheetImportDialogState } from '@/spreadsheet-import/states/spreadsheetImportDialogState'; +import { matchColumnsState } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState'; import { SpreadsheetImport } from './SpreadsheetImport'; type SpreadsheetImportProviderProps = React.PropsWithChildren; @@ -14,11 +15,15 @@ export const SpreadsheetImportProvider = ( spreadsheetImportDialogState, ); + const setMatchColumnsState = useSetRecoilState(matchColumnsState); + const handleClose = () => { setSpreadsheetImportDialog({ isOpen: false, options: null, }); + + setMatchColumnsState([]); }; return ( diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx index dccc5ed3e735..20b0051c9147 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx @@ -22,8 +22,10 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Modal } from '@/ui/layout/modal/components/Modal'; import { UnmatchColumn } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn'; +import { initialComputedColumnsState } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState'; import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep'; import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType'; +import { useRecoilState } from 'recoil'; import { ColumnGrid } from './components/ColumnGrid'; import { TemplateColumn } from './components/TemplateColumn'; import { UserTableColumn } from './components/UserTableColumn'; @@ -142,13 +144,8 @@ export const MatchColumnsStep = ({ const { fields, autoMapHeaders, autoMapDistance } = useSpreadsheetImportInternal(); const [isLoading, setIsLoading] = useState(false); - const [columns, setColumns] = useState>( - // Do not remove spread, it indexes empty array elements, otherwise map() skips over them - ([...headerValues] as string[]).map((value, index) => ({ - type: ColumnType.empty, - index, - header: value ?? '', - })), + const [columns, setColumns] = useRecoilState( + initialComputedColumnsState(headerValues), ); const { matchColumnsStepHook } = useSpreadsheetImportInternal(); @@ -157,7 +154,7 @@ export const MatchColumnsStep = ({ (columnIndex: number) => { setColumns( columns.map((column, index) => - columnIndex === index ? setIgnoreColumn(column) : column, + columnIndex === index ? setIgnoreColumn(column) : column, ), ); }, @@ -191,7 +188,7 @@ export const MatchColumnsStep = ({ (column) => 'value' in column && column.value === field.key, ); setColumns( - columns.map>((column, index) => { + columns.map>((column, index) => { if (columnIndex === index) { return setColumn(column, field, data); } else if (index === existingFieldIndex) { @@ -207,7 +204,15 @@ export const MatchColumnsStep = ({ ); } }, - [columns, onRevertIgnore, onIgnore, fields, data, enqueueSnackBar], + [ + columns, + onRevertIgnore, + onIgnore, + fields, + setColumns, + data, + enqueueSnackBar, + ], ); const onContinue = useCallback( @@ -306,7 +311,10 @@ export const MatchColumnsStep = ({ ]); useEffect(() => { - if (autoMapHeaders) { + const isInitialColumnsState = columns.every( + (column) => column.type === ColumnType.empty, + ); + if (autoMapHeaders && isInitialColumnsState) { setColumns(getMatchedColumns(columns, fields, data, autoMapDistance)); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -349,7 +357,10 @@ export const MatchColumnsStep = ({ onClick={handleOnContinue} isLoading={isLoading} title="Next Step" - onBack={onBack} + onBack={() => { + onBack?.(); + setColumns([]); + }} /> ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx index cd047740da63..9a7e7e5f556c 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx @@ -37,7 +37,6 @@ const StyledControlContainer = styled.div<{ cursor: string }>` justify-content: space-between; padding: 0 ${({ theme }) => theme.spacing(2)}; width: 100%; - position: relative; `; const StyledLabel = styled.span` diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx index 33416468eea2..265ead428a09 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/TemplateColumn.tsx @@ -14,7 +14,7 @@ const StyledContainer = styled.div` `; type TemplateColumnProps = { - columns: Columns; + columns: Columns; columnIndex: number; onChange: (val: T, index: number) => void; }; @@ -34,14 +34,13 @@ export const TemplateColumn = ({ if ('value' in column) { return column.value === key; } - return false; }) !== -1; return { - icon, + icon: icon, value: key, - label, + label: label, disabled: isSelected, } as const; }); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts new file mode 100644 index 000000000000..ed147aadd6ae --- /dev/null +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts @@ -0,0 +1,41 @@ +import { + Columns, + ColumnType, +} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; +import { ImportedRow } from '@/spreadsheet-import/types'; +import { atom, selectorFamily } from 'recoil'; + +export const matchColumnsState = atom({ + key: 'MatchColumnsState', + default: [] as Columns, +}); + +export const initialComputedColumnsState = selectorFamily< + Columns, + ImportedRow +>({ + key: 'InitialComputedColumnsState', + get: + (headerValues: ImportedRow) => + ({ get }) => { + const currentState = get(matchColumnsState) as Columns; + if (currentState.length === 0) { + // Do not remove spread, it indexes empty array elements, otherwise map() skips over them + const initialState = ([...headerValues] as string[]).map( + (value, index) => ({ + type: ColumnType.empty, + index, + header: value ?? '', + }), + ); + return initialState as Columns; + } else { + return currentState; + } + }, + set: + () => + ({ set }, newValue) => { + set(matchColumnsState, newValue as Columns); + }, +}); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx index 485e64bc1917..7b85b17cdd05 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx @@ -45,6 +45,7 @@ export const SpreadsheetImportStepper = ({ ); const [uploadedFile, setUploadedFile] = useState(null); + const { enqueueSnackBar } = useSnackBar(); const errorToast = useCallback( @@ -106,7 +107,9 @@ export const SpreadsheetImportStepper = ({ setPreviousStepState={setPreviousStepState} currentStepState={currentStepState} nextStep={nextStep} - onBack={onBack} + onBack={() => { + onBack(); + }} errorToast={errorToast} /> );