Fixed: In CSV import now users are able to come back to the previous step. (#5625)
Users now can make a back transition from the current step state. - Added a `BackButton` component to `spreadsheet-import` in order to use it within the step state components. - Used the prebuilt `prevStep` from `useStepBar` and passed it as a prop to the `Uploadflow` to get the previous state as activestep. - Added a `previousState` to set the previous state with the required key data. - Added a `handleOnBack` function in `Uploadflow` to set the correct state and call the `prevStep` function to make the transition. - Added a callback function `onBack` and passed it as props to each step state component. fixes: #5564 https://github.com/twentyhq/twenty/assets/140178357/be7e1a0a-0fb8-41f2-a207-dfc3208ca6f0 --------- Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
committed by
GitHub
parent
a12c1aad5e
commit
c7f2150ac7
@ -16,22 +16,22 @@ const StyledButton = styled(MainButton)`
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
type ContinueButtonProps = {
|
||||
onContinue: (val: any) => void;
|
||||
type StepNavigationButtonProps = {
|
||||
onClick: () => void;
|
||||
title: string;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
export const ContinueButton = ({
|
||||
onContinue,
|
||||
export const StepNavigationButton = ({
|
||||
onClick,
|
||||
title,
|
||||
isLoading,
|
||||
}: ContinueButtonProps) => (
|
||||
}: StepNavigationButtonProps) => (
|
||||
<StyledFooter>
|
||||
<StyledButton
|
||||
Icon={isLoading ? CircularProgressBar : undefined}
|
||||
title={title}
|
||||
onClick={!isLoading ? onContinue : undefined}
|
||||
onClick={!isLoading ? onClick : undefined}
|
||||
/>
|
||||
</StyledFooter>
|
||||
);
|
||||
@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ContinueButton } from '@/spreadsheet-import/components/ContinueButton';
|
||||
import { Heading } from '@/spreadsheet-import/components/Heading';
|
||||
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
|
||||
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
|
||||
import { Field, RawData } from '@/spreadsheet-import/types';
|
||||
import { findUnmatchedRequiredFields } from '@/spreadsheet-import/utils/findUnmatchedRequiredFields';
|
||||
@ -49,6 +49,7 @@ export type MatchColumnsStepProps<T extends string> = {
|
||||
data: RawData[];
|
||||
headerValues: RawData;
|
||||
onContinue: (data: any[], rawData: RawData[], columns: Columns<T>) => void;
|
||||
onBack: () => void;
|
||||
};
|
||||
|
||||
export enum ColumnType {
|
||||
@ -112,6 +113,7 @@ export const MatchColumnsStep = <T extends string>({
|
||||
data,
|
||||
headerValues,
|
||||
onContinue,
|
||||
onBack,
|
||||
}: MatchColumnsStepProps<T>) => {
|
||||
const { enqueueDialog } = useDialogManager();
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
@ -284,11 +286,12 @@ export const MatchColumnsStep = <T extends string>({
|
||||
)}
|
||||
/>
|
||||
</StyledContent>
|
||||
<ContinueButton
|
||||
<StepNavigationButton
|
||||
onClick={handleOnContinue}
|
||||
isLoading={isLoading}
|
||||
onContinue={handleOnContinue}
|
||||
title="Next"
|
||||
/>
|
||||
<StepNavigationButton onClick={onBack} title="Back" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ContinueButton } from '@/spreadsheet-import/components/ContinueButton';
|
||||
import { Heading } from '@/spreadsheet-import/components/Heading';
|
||||
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
|
||||
import { RawData } from '@/spreadsheet-import/types';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
|
||||
@ -21,11 +21,13 @@ const StyledTableContainer = styled.div`
|
||||
type SelectHeaderStepProps = {
|
||||
data: RawData[];
|
||||
onContinue: (headerValues: RawData, data: RawData[]) => Promise<void>;
|
||||
onBack: () => void;
|
||||
};
|
||||
|
||||
export const SelectHeaderStep = ({
|
||||
data,
|
||||
onContinue,
|
||||
onBack,
|
||||
}: SelectHeaderStepProps) => {
|
||||
const [selectedRows, setSelectedRows] = useState<ReadonlySet<number>>(
|
||||
new Set([0]),
|
||||
@ -53,11 +55,12 @@ export const SelectHeaderStep = ({
|
||||
/>
|
||||
</StyledTableContainer>
|
||||
</Modal.Content>
|
||||
<ContinueButton
|
||||
onContinue={handleContinue}
|
||||
<StepNavigationButton
|
||||
onClick={handleContinue}
|
||||
title="Next"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<StepNavigationButton onClick={onBack} title="Back" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ContinueButton } from '@/spreadsheet-import/components/ContinueButton';
|
||||
import { Heading } from '@/spreadsheet-import/components/Heading';
|
||||
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
|
||||
import { Radio } from '@/ui/input/components/Radio';
|
||||
import { RadioGroup } from '@/ui/input/components/RadioGroup';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
@ -27,11 +27,13 @@ const StyledRadioContainer = styled.div`
|
||||
type SelectSheetStepProps = {
|
||||
sheetNames: string[];
|
||||
onContinue: (sheetName: string) => Promise<void>;
|
||||
onBack: () => void;
|
||||
};
|
||||
|
||||
export const SelectSheetStep = ({
|
||||
sheetNames,
|
||||
onContinue,
|
||||
onBack,
|
||||
}: SelectSheetStepProps) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@ -58,11 +60,12 @@ export const SelectSheetStep = ({
|
||||
</RadioGroup>
|
||||
</StyledRadioContainer>
|
||||
</StyledContent>
|
||||
<ContinueButton
|
||||
<StepNavigationButton
|
||||
onClick={() => handleOnContinue(value)}
|
||||
isLoading={isLoading}
|
||||
onContinue={() => handleOnContinue(value)}
|
||||
title="Next"
|
||||
/>
|
||||
<StepNavigationButton onClick={onBack} title="Back" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -35,7 +35,7 @@ export const Steps = () => {
|
||||
initialStepState?.type,
|
||||
);
|
||||
|
||||
const { nextStep, activeStep } = useStepBar({
|
||||
const { nextStep, prevStep, activeStep } = useStepBar({
|
||||
initialStep,
|
||||
});
|
||||
|
||||
@ -48,7 +48,7 @@ export const Steps = () => {
|
||||
))}
|
||||
</StepBar>
|
||||
</StyledHeader>
|
||||
<UploadFlow nextStep={nextStep} />
|
||||
<UploadFlow nextStep={nextStep} prevStep={prevStep} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -59,14 +59,18 @@ export type StepState =
|
||||
|
||||
interface UploadFlowProps {
|
||||
nextStep: () => void;
|
||||
prevStep: () => void;
|
||||
}
|
||||
|
||||
export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
export const UploadFlow = ({ nextStep, prevStep }: UploadFlowProps) => {
|
||||
const theme = useTheme();
|
||||
const { initialStepState } = useSpreadsheetImportInternal();
|
||||
const [state, setState] = useState<StepState>(
|
||||
initialStepState || { type: StepType.upload },
|
||||
);
|
||||
const [previousState, setPreviousState] = useState<StepState>(
|
||||
initialStepState || { type: StepType.upload },
|
||||
);
|
||||
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
|
||||
const {
|
||||
maxRecords,
|
||||
@ -87,6 +91,11 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
[enqueueSnackBar],
|
||||
);
|
||||
|
||||
const onBack = useCallback(() => {
|
||||
setState(previousState);
|
||||
prevStep();
|
||||
}, [prevStep, previousState]);
|
||||
|
||||
switch (state.type) {
|
||||
case StepType.upload:
|
||||
return (
|
||||
@ -138,6 +147,7 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
} else {
|
||||
setState({ type: StepType.selectSheet, workbook });
|
||||
}
|
||||
setPreviousState(state);
|
||||
nextStep();
|
||||
}}
|
||||
/>
|
||||
@ -164,10 +174,12 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
type: StepType.selectHeader,
|
||||
data: mappedWorkbook,
|
||||
});
|
||||
setPreviousState(state);
|
||||
} catch (e) {
|
||||
errorToast((e as Error).message);
|
||||
}
|
||||
}}
|
||||
onBack={onBack}
|
||||
/>
|
||||
);
|
||||
case StepType.selectHeader:
|
||||
@ -184,11 +196,13 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
data,
|
||||
headerValues,
|
||||
});
|
||||
setPreviousState(state);
|
||||
nextStep();
|
||||
} catch (e) {
|
||||
errorToast((e as Error).message);
|
||||
}
|
||||
}}
|
||||
onBack={onBack}
|
||||
/>
|
||||
);
|
||||
case StepType.matchColumns:
|
||||
@ -203,11 +217,13 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
type: StepType.validateData,
|
||||
data,
|
||||
});
|
||||
setPreviousState(state);
|
||||
nextStep();
|
||||
} catch (e) {
|
||||
errorToast((e as Error).message);
|
||||
}
|
||||
}}
|
||||
onBack={onBack}
|
||||
/>
|
||||
);
|
||||
case StepType.validateData:
|
||||
@ -223,6 +239,10 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
|
||||
type: StepType.loading,
|
||||
})
|
||||
}
|
||||
onBack={() => {
|
||||
onBack();
|
||||
setPreviousState(initialStepState || { type: StepType.upload });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case StepType.loading:
|
||||
|
||||
@ -4,8 +4,8 @@ import { RowsChangeData } from 'react-data-grid';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconTrash } from 'twenty-ui';
|
||||
|
||||
import { ContinueButton } from '@/spreadsheet-import/components/ContinueButton';
|
||||
import { Heading } from '@/spreadsheet-import/components/Heading';
|
||||
import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton';
|
||||
import { Table } from '@/spreadsheet-import/components/Table';
|
||||
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
|
||||
import { Data } from '@/spreadsheet-import/types';
|
||||
@ -64,12 +64,14 @@ type ValidationStepProps<T extends string> = {
|
||||
initialData: Data<T>[];
|
||||
file: File;
|
||||
onSubmitStart?: () => void;
|
||||
onBack: () => void;
|
||||
};
|
||||
|
||||
export const ValidationStep = <T extends string>({
|
||||
initialData,
|
||||
file,
|
||||
onSubmitStart,
|
||||
onBack,
|
||||
}: ValidationStepProps<T>) => {
|
||||
const { enqueueDialog } = useDialogManager();
|
||||
const { fields, onClose, onSubmit, rowHook, tableHook } =
|
||||
@ -238,7 +240,8 @@ export const ValidationStep = <T extends string>({
|
||||
/>
|
||||
</StyledScrollContainer>
|
||||
</StyledContent>
|
||||
<ContinueButton onContinue={onContinue} title="Confirm" />
|
||||
<StepNavigationButton onClick={onContinue} title="Confirm" />
|
||||
<StepNavigationButton onClick={onBack} title="Back" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -67,6 +67,7 @@ export const Default = () => (
|
||||
headerValues={mockData[0] as string[]}
|
||||
data={mockData.slice(1)}
|
||||
onContinue={() => null}
|
||||
onBack={() => null}
|
||||
/>
|
||||
</ModalWrapper>
|
||||
</Providers>
|
||||
|
||||
@ -26,6 +26,7 @@ export const Default = () => (
|
||||
<SelectHeaderStep
|
||||
data={headerSelectionTableFields}
|
||||
onContinue={() => Promise.resolve()}
|
||||
onBack={() => Promise.resolve()}
|
||||
/>
|
||||
</ModalWrapper>
|
||||
</Providers>
|
||||
|
||||
@ -25,6 +25,7 @@ export const Default = () => (
|
||||
<SelectSheetStep
|
||||
sheetNames={sheetNames}
|
||||
onContinue={() => Promise.resolve()}
|
||||
onBack={() => Promise.resolve()}
|
||||
/>
|
||||
</ModalWrapper>
|
||||
</Providers>
|
||||
|
||||
@ -25,7 +25,11 @@ export const Default = () => (
|
||||
<DialogManagerScope dialogManagerScopeId="dialog-manager">
|
||||
<Providers values={mockRsiValues}>
|
||||
<ModalWrapper isOpen={true} onClose={() => null}>
|
||||
<ValidationStep initialData={editableTableInitialData} file={file} />
|
||||
<ValidationStep
|
||||
initialData={editableTableInitialData}
|
||||
file={file}
|
||||
onBack={() => Promise.resolve()}
|
||||
/>
|
||||
</ModalWrapper>
|
||||
</Providers>
|
||||
</DialogManagerScope>
|
||||
|
||||
Reference in New Issue
Block a user