Skip to content

Commit d3dc5c3

Browse files
committed
Add autoMapSelectValues flag and automatic matching.
1 parent 8eacb23 commit d3dc5c3

File tree

7 files changed

+25
-15
lines changed

7 files changed

+25
-15
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ Common date-time formats can be viewed [here](https://docs.sheetjs.com/docs/csf/
203203
maxFileSize?: number
204204
// Automatically map imported headers to specified fields if possible. Default: true
205205
autoMapHeaders?: boolean
206+
// When field type is "select", automatically match values if possible. Default: true
207+
autoMapSelectValues?: boolean
206208
// Headers matching accuracy: 1 for strict and up for more flexible matching. Default: 2
207209
autoMapDistance?: number
208210
```

src/ReactSpreadsheetImport.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const defaultTheme = themeOverrides
1111

1212
export const defaultRSIProps: Partial<RsiProps<any>> = {
1313
autoMapHeaders: true,
14+
autoMapSelectValues: false,
1415
allowInvalidSubmit: true,
1516
autoMapDistance: 2,
1617
translations: translations,

src/steps/MatchColumnsStep/MatchColumnsStep.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export type Columns<T extends string> = Column<T>[]
6565
export const MatchColumnsStep = <T extends string>({ data, headerValues, onContinue }: MatchColumnsProps<T>) => {
6666
const toast = useToast()
6767
const dataExample = data.slice(0, 2)
68-
const { fields, autoMapHeaders, autoMapDistance, translations } = useRsi<T>()
68+
const { fields, autoMapHeaders, autoMapSelectValues, autoMapDistance, translations } = useRsi<T>()
6969
const [isLoading, setIsLoading] = useState(false)
7070
const [columns, setColumns] = useState<Columns<T>>(
7171
// Do not remove spread, it indexes empty array elements, otherwise map() skips over them
@@ -81,7 +81,7 @@ export const MatchColumnsStep = <T extends string>({ data, headerValues, onConti
8181
columns.map<Column<T>>((column, index) => {
8282
columnIndex === index ? setColumn(column, field, data) : column
8383
if (columnIndex === index) {
84-
return setColumn(column, field, data)
84+
return setColumn(column, field, data, autoMapSelectValues)
8585
} else if (index === existingFieldIndex) {
8686
toast({
8787
status: "warning",
@@ -153,7 +153,7 @@ export const MatchColumnsStep = <T extends string>({ data, headerValues, onConti
153153

154154
useEffect(() => {
155155
if (autoMapHeaders) {
156-
setColumns(getMatchedColumns(columns, fields, data, autoMapDistance))
156+
setColumns(getMatchedColumns(columns, fields, data, autoMapDistance, autoMapSelectValues))
157157
}
158158
// eslint-disable-next-line react-hooks/exhaustive-deps
159159
}, [])

src/steps/MatchColumnsStep/components/TemplateColumn.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import type { Styles } from "./ColumnGrid"
2222
const getAccordionTitle = <T extends string>(fields: Fields<T>, column: Column<T>, translations: Translations) => {
2323
const fieldLabel = fields.find((field) => "value" in column && field.key === column.value)!.label
2424
return `${translations.matchColumnsStep.matchDropdownTitle} ${fieldLabel} (${
25-
"matchedOptions" in column && column.matchedOptions.length
25+
"matchedOptions" in column && column.matchedOptions.filter((option) => !option.value).length
2626
} ${translations.matchColumnsStep.unmatched})`
2727
}
2828

src/steps/MatchColumnsStep/utils/getMatchedColumns.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const getMatchedColumns = <T extends string>(
1010
fields: Fields<T>,
1111
data: MatchColumnsProps<T>["data"],
1212
autoMapDistance: number,
13+
autoMapSelectValues?: boolean,
1314
) =>
1415
columns.reduce<Column<T>[]>((arr, column) => {
1516
const autoMatch = findMatch(column.header, fields, autoMapDistance)
@@ -21,18 +22,18 @@ export const getMatchedColumns = <T extends string>(
2122
return lavenstein(duplicate.value, duplicate.header) < lavenstein(autoMatch, column.header)
2223
? [
2324
...arr.slice(0, duplicateIndex),
24-
setColumn(arr[duplicateIndex], field, data),
25+
setColumn(arr[duplicateIndex], field, data, autoMapSelectValues),
2526
...arr.slice(duplicateIndex + 1),
2627
setColumn(column),
2728
]
2829
: [
2930
...arr.slice(0, duplicateIndex),
3031
setColumn(arr[duplicateIndex]),
3132
...arr.slice(duplicateIndex + 1),
32-
setColumn(column, field, data),
33+
setColumn(column, field, data, autoMapSelectValues),
3334
]
3435
} else {
35-
return [...arr, setColumn(column, field, data)]
36+
return [...arr, setColumn(column, field, data, autoMapSelectValues)]
3637
}
3738
} else {
3839
return [...arr, column]

src/steps/MatchColumnsStep/utils/setColumn.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import type { Field } from "../../../types"
2-
import { Column, ColumnType, MatchColumnsProps } from "../MatchColumnsStep"
2+
import { Column, ColumnType, MatchColumnsProps, MatchedOptions } from "../MatchColumnsStep"
33
import { uniqueEntries } from "./uniqueEntries"
44

55
export const setColumn = <T extends string>(
66
oldColumn: Column<T>,
77
field?: Field<T>,
88
data?: MatchColumnsProps<T>["data"],
9+
autoMapSelectValues?: boolean,
910
): Column<T> => {
1011
switch (field?.fieldType.type) {
1112
case "select":
12-
const uniqueData = uniqueEntries(data || [], oldColumn.index)
13-
const matchedOptions = uniqueData?.map(option => {
14-
const value = field.fieldType.options.find(o => o.value == option.value || o.label == option.entry)?.value
15-
return value ? {...option, value} as MatchedOptions<T> : option as MatchedOptions<T>
16-
})
17-
const allMatched = matchedOptions.filter(o => o.value).length == uniqueData?.length
13+
const options = field.fieldType.options
14+
const uniqueData = uniqueEntries(data || [], oldColumn.index) as MatchedOptions<T>[]
15+
const matchedOptions = autoMapSelectValues
16+
? uniqueData.map((option) => {
17+
const value = options.find((o) => o.value == option.value || o.label == option.entry)?.value
18+
return value ? ({ ...option, value } as MatchedOptions<T>) : (option as MatchedOptions<T>)
19+
})
20+
: uniqueData
21+
const allMatched = matchedOptions.filter((o) => o.value).length == uniqueData?.length
1822

1923
return {
2024
...oldColumn,
2125
type: allMatched ? ColumnType.matchedSelectOptions : ColumnType.matchedSelect,
2226
value: field.key,
23-
matchedOptions
27+
matchedOptions,
2428
}
2529
case "checkbox":
2630
return { index: oldColumn.index, type: ColumnType.matchedCheckbox, value: field.key, header: oldColumn.header }

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export type RsiProps<T extends string> = {
3535
maxFileSize?: number
3636
// Automatically map imported headers to specified fields if possible. Default: true
3737
autoMapHeaders?: boolean
38+
// When field type is "select", automatically match values if possible. Default: false
39+
autoMapSelectValues?: boolean
3840
// Headers matching accuracy: 1 for strict and up for more flexible matching
3941
autoMapDistance?: number
4042
// Initial Step state to be rendered on load

0 commit comments

Comments
 (0)