Skip to content

Commit 10b15d9

Browse files
committed
feat/navigation
- todo: fix tests
1 parent 08ed7a3 commit 10b15d9

12 files changed

Lines changed: 121 additions & 59 deletions

File tree

src/components/ContinueButton.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ import { Button, ModalFooter } from "@chakra-ui/react"
22

33
type ContinueButtonProps = {
44
onContinue: (val: any) => void
5+
onBack: () => void
56
title: string
7+
backTitle: string
68
isLoading?: boolean
79
}
810

9-
export const ContinueButton = ({ onContinue, title, isLoading }: ContinueButtonProps) => (
10-
<ModalFooter>
11+
export const ContinueButton = ({ onContinue, onBack, title, backTitle, isLoading }: ContinueButtonProps) => (
12+
<ModalFooter justifyContent="space-between">
13+
<Button size="lg" w="21rem" onClick={onBack} isLoading={isLoading}>
14+
{backTitle}
15+
</Button>
1116
<Button size="lg" w="21rem" onClick={onContinue} isLoading={isLoading}>
1217
{title}
1318
</Button>

src/hooks/useRsiInitialStep.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/steps/MatchColumnsStep/MatchColumnsStep.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type MatchColumnsProps<T extends string> = {
1717
data: RawData[]
1818
headerValues: RawData
1919
onContinue: (data: any[], rawData: RawData[], columns: Columns<T>) => void
20+
onBack: () => void
2021
}
2122

2223
export enum ColumnType {
@@ -62,7 +63,12 @@ export type Column<T extends string> =
6263

6364
export type Columns<T extends string> = Column<T>[]
6465

65-
export const MatchColumnsStep = <T extends string>({ data, headerValues, onContinue }: MatchColumnsProps<T>) => {
66+
export const MatchColumnsStep = <T extends string>({
67+
data,
68+
headerValues,
69+
onContinue,
70+
onBack,
71+
}: MatchColumnsProps<T>) => {
6672
const toast = useToast()
6773
const dataExample = data.slice(0, 2)
6874
const { fields, autoMapHeaders, autoMapDistance, translations } = useRsi<T>()
@@ -169,6 +175,7 @@ export const MatchColumnsStep = <T extends string>({ data, headerValues, onConti
169175
<ColumnGrid
170176
columns={columns}
171177
onContinue={handleOnContinue}
178+
onBack={onBack}
172179
isLoading={isLoading}
173180
userColumn={(column) => (
174181
<UserTableColumn

src/steps/MatchColumnsStep/components/ColumnGrid.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ColumnGridProps<T extends string> = {
1111
userColumn: (column: Column<T>) => React.ReactNode
1212
templateColumn: (column: Column<T>) => React.ReactNode
1313
onContinue: (val: Record<string, string>[]) => void
14+
onBack: () => void
1415
isLoading: boolean
1516
}
1617

@@ -21,6 +22,7 @@ export const ColumnGrid = <T extends string>({
2122
userColumn,
2223
templateColumn,
2324
onContinue,
25+
onBack,
2426
isLoading,
2527
}: ColumnGridProps<T>) => {
2628
const { translations } = useRsi()
@@ -66,7 +68,9 @@ export const ColumnGrid = <T extends string>({
6668
<ContinueButton
6769
isLoading={isLoading}
6870
onContinue={onContinue}
71+
onBack={onBack}
6972
title={translations.matchColumnsStep.nextButtonTitle}
73+
backTitle={translations.matchColumnsStep.backButtonTitle}
7074
/>
7175
</>
7276
)

src/steps/SelectHeaderStep/SelectHeaderStep.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import type { RawData } from "../../types"
99
type SelectHeaderProps = {
1010
data: RawData[]
1111
onContinue: (headerValues: RawData, data: RawData[]) => Promise<void>
12+
onBack: () => void
1213
}
1314

14-
export const SelectHeaderStep = ({ data, onContinue }: SelectHeaderProps) => {
15+
export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps) => {
1516
const styles = useStyleConfig(
1617
"SelectHeaderStep",
1718
) as (typeof themeOverrides)["components"]["SelectHeaderStep"]["baseStyle"]
@@ -36,7 +37,9 @@ export const SelectHeaderStep = ({ data, onContinue }: SelectHeaderProps) => {
3637
</ModalBody>
3738
<ContinueButton
3839
onContinue={handleContinue}
40+
onBack={onBack}
3941
title={translations.selectHeaderStep.nextButtonTitle}
42+
backTitle={translations.selectHeaderStep.backButtonTitle}
4043
isLoading={isLoading}
4144
/>
4245
</>

src/steps/SelectHeaderStep/tests/SelectHeaderStep.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ describe("Select header step tests", () => {
2828
const selectRowIndex = 2
2929

3030
const onContinue = jest.fn()
31+
const onBack = jest.fn()
3132
render(
3233
<Providers theme={defaultTheme} rsiValues={mockRsiValues}>
3334
<ModalWrapper isOpen={true} onClose={() => {}}>
34-
<SelectHeaderStep data={data} onContinue={onContinue} />
35+
<SelectHeaderStep data={data} onContinue={onContinue} onBack={onBack} />
3536
</ModalWrapper>
3637
</Providers>,
3738
)

src/steps/SelectSheetStep/SelectSheetStep.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import type { themeOverrides } from "../../theme"
77
type SelectSheetProps = {
88
sheetNames: string[]
99
onContinue: (sheetName: string) => Promise<void>
10+
onBack: () => void
1011
}
1112

12-
export const SelectSheetStep = ({ sheetNames, onContinue }: SelectSheetProps) => {
13+
export const SelectSheetStep = ({ sheetNames, onContinue, onBack }: SelectSheetProps) => {
1314
const [isLoading, setIsLoading] = useState(false)
1415
const { translations } = useRsi()
1516
const [value, setValue] = useState(sheetNames[0])
@@ -42,7 +43,9 @@ export const SelectSheetStep = ({ sheetNames, onContinue }: SelectSheetProps) =>
4243
<ContinueButton
4344
isLoading={isLoading}
4445
onContinue={() => handleOnContinue(value)}
46+
onBack={onBack}
4547
title={translations.uploadStep.selectSheet.nextButtonTitle}
48+
backTitle={translations.uploadStep.selectSheet.backButtonTitle}
4649
/>
4750
</>
4851
)

src/steps/Steps.tsx

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,57 @@
1-
import { UploadFlow } from "./UploadFlow"
1+
import { StepState, StepType, UploadFlow } from "./UploadFlow"
22
import { ModalHeader } from "@chakra-ui/react"
33
import { useSteps, Step, Steps as Stepper } from "chakra-ui-steps"
44
import { CgCheck } from "react-icons/cg"
5+
56
import { useRsi } from "../hooks/useRsi"
6-
import { useRsiInitialStep } from "../hooks/useRsiInitialStep"
7+
import { useRef, useState } from "react"
8+
import { steps, stepTypeToStepIndex, stepIndexToStepType } from "../utils/steps"
79

810
const CheckIcon = ({ color }: { color: string }) => <CgCheck size="2.25rem" color={color} />
911

1012
export const Steps = () => {
1113
const { initialStepState, translations } = useRsi()
1214

13-
const { steps, initialStep } = useRsiInitialStep(initialStepState?.type)
15+
const initialStep = stepTypeToStepIndex(initialStepState?.type)
1416

15-
const { nextStep, activeStep } = useSteps({
17+
const { nextStep, activeStep, setStep } = useSteps({
1618
initialStep,
1719
})
1820

21+
const [state, setState] = useState<StepState>(initialStepState || { type: StepType.upload })
22+
23+
const history = useRef<StepState[]>([])
24+
25+
const onClickStep = (stepIndex: number) => {
26+
const type = stepIndexToStepType(stepIndex)
27+
const historyIdx = history.current.findIndex((v) => v.type === type)
28+
if (historyIdx === -1) return
29+
const nextHistory = history.current.slice(0, historyIdx + 1)
30+
history.current = nextHistory
31+
setState(nextHistory[nextHistory.length - 1])
32+
setStep(stepIndex)
33+
}
34+
35+
const onBack = () => {
36+
onClickStep(activeStep - 1)
37+
}
38+
39+
const onNext = (v: StepState) => {
40+
history.current.push(state)
41+
setState(v)
42+
v.type !== StepType.selectSheet && nextStep()
43+
}
44+
1945
return (
2046
<>
2147
<ModalHeader display={["none", "none", "block"]}>
22-
<Stepper activeStep={activeStep} checkIcon={CheckIcon}>
48+
<Stepper activeStep={activeStep} checkIcon={CheckIcon} onClickStep={onClickStep}>
2349
{steps.map((key) => (
2450
<Step label={translations[key].title} key={key} />
2551
))}
2652
</Stepper>
2753
</ModalHeader>
28-
<UploadFlow nextStep={nextStep} />
54+
<UploadFlow state={state} onNext={onNext} onBack={onBack} />
2955
</>
3056
)
3157
}

src/steps/UploadFlow.tsx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ export type StepState =
4141
}
4242

4343
interface Props {
44-
nextStep: () => void
44+
state: StepState
45+
onNext: (v: StepState) => void
46+
onBack: () => void
4547
}
4648

47-
export const UploadFlow = ({ nextStep }: Props) => {
48-
const { initialStepState } = useRsi()
49-
const [state, setState] = useState<StepState>(initialStepState || { type: StepType.upload })
49+
export const UploadFlow = ({ state, onNext, onBack }: Props) => {
5050
const [uploadedFile, setUploadedFile] = useState<File | null>(null)
5151
const { maxRecords, translations, uploadStepHook, selectHeaderStepHook, matchColumnsStepHook } = useRsi()
5252
const toast = useToast()
@@ -78,16 +78,15 @@ export const UploadFlow = ({ nextStep }: Props) => {
7878
}
7979
try {
8080
const mappedWorkbook = await uploadStepHook(mapWorkbook(workbook))
81-
setState({
81+
onNext({
8282
type: StepType.selectHeader,
8383
data: mappedWorkbook,
8484
})
85-
nextStep()
8685
} catch (e) {
8786
errorToast((e as Error).message)
8887
}
8988
} else {
90-
setState({ type: StepType.selectSheet, workbook })
89+
onNext({ type: StepType.selectSheet, workbook })
9190
}
9291
}}
9392
/>
@@ -103,15 +102,15 @@ export const UploadFlow = ({ nextStep }: Props) => {
103102
}
104103
try {
105104
const mappedWorkbook = await uploadStepHook(mapWorkbook(state.workbook, sheetName))
106-
setState({
105+
onNext({
107106
type: StepType.selectHeader,
108107
data: mappedWorkbook,
109108
})
110-
nextStep()
111109
} catch (e) {
112110
errorToast((e as Error).message)
113111
}
114112
}}
113+
onBack={onBack}
115114
/>
116115
)
117116
case StepType.selectHeader:
@@ -121,16 +120,16 @@ export const UploadFlow = ({ nextStep }: Props) => {
121120
onContinue={async (...args) => {
122121
try {
123122
const { data, headerValues } = await selectHeaderStepHook(...args)
124-
setState({
123+
onNext({
125124
type: StepType.matchColumns,
126125
data,
127126
headerValues,
128127
})
129-
nextStep()
130128
} catch (e) {
131129
errorToast((e as Error).message)
132130
}
133131
}}
132+
onBack={onBack}
134133
/>
135134
)
136135
case StepType.matchColumns:
@@ -141,19 +140,19 @@ export const UploadFlow = ({ nextStep }: Props) => {
141140
onContinue={async (values, rawData, columns) => {
142141
try {
143142
const data = await matchColumnsStepHook(values, rawData, columns)
144-
setState({
143+
onNext({
145144
type: StepType.validateData,
146145
data,
147146
})
148-
nextStep()
149147
} catch (e) {
150148
errorToast((e as Error).message)
151149
}
152150
}}
151+
onBack={onBack}
153152
/>
154153
)
155154
case StepType.validateData:
156-
return <ValidationStep initialData={state.data} file={uploadedFile!} />
155+
return <ValidationStep initialData={state.data} file={uploadedFile!} onBack={onBack} />
157156
default:
158157
return <Progress isIndeterminate />
159158
}

src/steps/ValidationStep/ValidationStep.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ import type { RowsChangeData } from "react-data-grid"
1414
type Props<T extends string> = {
1515
initialData: Data<T>[]
1616
file: File
17+
onBack: () => void
1718
}
1819

19-
export const ValidationStep = <T extends string>({ initialData, file }: Props<T>) => {
20+
export const ValidationStep = <T extends string>({ initialData, file, onBack }: Props<T>) => {
2021
const { translations, fields, onClose, onSubmit, rowHook, tableHook } = useRsi<T>()
2122
const styles = useStyleConfig(
2223
"ValidationStep",
@@ -50,12 +51,15 @@ export const ValidationStep = <T extends string>({ initialData, file }: Props<T>
5051

5152
const updateRow = useCallback(
5253
(rows: typeof data, changedData?: RowsChangeData<(typeof data)[number]>) => {
53-
const changes = changedData?.indexes.reduce((acc, index) => {
54-
// when data is filtered val !== actual index in data
55-
const realIndex = data.findIndex((value) => value.__index === rows[index].__index)
56-
acc[realIndex] = rows[index]
57-
return acc
58-
}, {} as Record<number, (typeof data)[number]>)
54+
const changes = changedData?.indexes.reduce(
55+
(acc, index) => {
56+
// when data is filtered val !== actual index in data
57+
const realIndex = data.findIndex((value) => value.__index === rows[index].__index)
58+
acc[realIndex] = rows[index]
59+
return acc
60+
},
61+
{} as Record<number, (typeof data)[number]>,
62+
)
5963
const newData = Object.assign([], data, changes)
6064
updateData(newData)
6165
},
@@ -151,7 +155,12 @@ export const ValidationStep = <T extends string>({ initialData, file }: Props<T>
151155
}}
152156
/>
153157
</ModalBody>
154-
<ContinueButton onContinue={onContinue} title={translations.validationStep.nextButtonTitle} />
158+
<ContinueButton
159+
onContinue={onContinue}
160+
onBack={onBack}
161+
title={translations.validationStep.nextButtonTitle}
162+
backTitle={translations.validationStep.backButtonTitle}
163+
/>
155164
</>
156165
)
157166
}

0 commit comments

Comments
 (0)