Properly extract full upc when excel shows it in scientific notation
This commit is contained in:
@@ -1021,7 +1021,7 @@ const MatchColumnsStepComponent = <T extends string>({
|
||||
|
||||
setColumns(
|
||||
columns.map<Column<T>>((column, index) => {
|
||||
if (columnIndex === index) {
|
||||
if (column.index === columnIndex) {
|
||||
// Set the new column value
|
||||
const updatedColumn = setColumn(column, field as Field<T>, data, autoMapSelectValues);
|
||||
|
||||
@@ -1143,15 +1143,15 @@ const MatchColumnsStepComponent = <T extends string>({
|
||||
|
||||
const onIgnore = useCallback(
|
||||
(columnIndex: number) => {
|
||||
setColumns(columns.map((column, index) => (columnIndex === index ? setIgnoreColumn<T>(column) : column)))
|
||||
setColumns(columns.map((column) => (column.index === columnIndex ? setIgnoreColumn<T>(column) : column)))
|
||||
},
|
||||
[columns, setColumns],
|
||||
)
|
||||
|
||||
const onToggleAiSupplemental = useCallback(
|
||||
(columnIndex: number) => {
|
||||
setColumns(columns.map((column, index) => {
|
||||
if (columnIndex !== index) return column;
|
||||
setColumns(columns.map((column) => {
|
||||
if (column.index !== columnIndex) return column;
|
||||
|
||||
if (column.type === ColumnType.aiSupplemental) {
|
||||
return { type: ColumnType.empty, index: column.index, header: column.header } as Column<T>;
|
||||
@@ -1168,7 +1168,7 @@ const MatchColumnsStepComponent = <T extends string>({
|
||||
|
||||
const onRevertIgnore = useCallback(
|
||||
(columnIndex: number) => {
|
||||
setColumns(columns.map((column, index) => (columnIndex === index ? setColumn(column) : column)))
|
||||
setColumns(columns.map((column) => (column.index === columnIndex ? setColumn(column) : column)))
|
||||
},
|
||||
[columns, setColumns],
|
||||
)
|
||||
@@ -1177,7 +1177,7 @@ const MatchColumnsStepComponent = <T extends string>({
|
||||
(value: string, columnIndex: number, entry: string) => {
|
||||
setColumns(
|
||||
columns.map((column, index) =>
|
||||
columnIndex === index && "matchedOptions" in column
|
||||
column.index === columnIndex && "matchedOptions" in column
|
||||
? setSubColumn(column as MatchedSelectColumn<T> | MatchedSelectOptionsColumn<T> | MatchedMultiSelectColumn<T>, entry, value)
|
||||
: column,
|
||||
),
|
||||
|
||||
@@ -4,8 +4,8 @@ import { normalizeCheckboxValue } from "./normalizeCheckboxValue"
|
||||
|
||||
export const normalizeTableData = <T extends string>(columns: Columns<T>, data: RawData[], fields: Fields<T>) =>
|
||||
data.map((row) =>
|
||||
columns.reduce((acc, column, index) => {
|
||||
const curr = row[index]
|
||||
columns.reduce((acc, column) => {
|
||||
const curr = row[column.index]
|
||||
switch (column.type) {
|
||||
case ColumnType.matchedCheckbox: {
|
||||
const field = fields.find((field) => field.key === column.value)!
|
||||
|
||||
@@ -1,16 +1,153 @@
|
||||
import * as XLSX from "xlsx"
|
||||
import type { CellObject } from "xlsx"
|
||||
import type { RawData } from "../types"
|
||||
|
||||
const SCIENTIFIC_NOTATION_REGEX = /^[+-]?(?:\d+\.?\d*|\d*\.?\d+)e[+-]?\d+$/i
|
||||
|
||||
const convertScientificToDecimalString = (input: string): string => {
|
||||
const match = input.toLowerCase().match(/^([+-]?)(\d+)(?:\.(\d+))?e([+-]?\d+)$/)
|
||||
if (!match) return input
|
||||
|
||||
const [, sign, integerPart, fractionalPart = "", exponentPart] = match
|
||||
const exponent = parseInt(exponentPart, 10)
|
||||
|
||||
if (Number.isNaN(exponent)) return input
|
||||
|
||||
const digits = `${integerPart}${fractionalPart}`
|
||||
|
||||
if (exponent >= 0) {
|
||||
const decimalIndex = integerPart.length + exponent
|
||||
if (decimalIndex >= digits.length) {
|
||||
const zerosToAppend = decimalIndex - digits.length
|
||||
return `${sign}${digits}${"0".repeat(zerosToAppend)}`
|
||||
}
|
||||
|
||||
const whole = digits.slice(0, decimalIndex) || "0"
|
||||
const fraction = digits.slice(decimalIndex).replace(/0+$/, "")
|
||||
return fraction ? `${sign}${whole}.${fraction}` : `${sign}${whole}`
|
||||
}
|
||||
|
||||
const decimalIndex = integerPart.length + exponent
|
||||
if (decimalIndex <= 0) {
|
||||
const zerosToPrepend = Math.abs(decimalIndex)
|
||||
const fractionDigits = `${"0".repeat(zerosToPrepend)}${digits}`.replace(/0+$/, "")
|
||||
return fractionDigits ? `${sign}0.${fractionDigits}` : "0"
|
||||
}
|
||||
|
||||
const whole = digits.slice(0, decimalIndex) || "0"
|
||||
const fractionDigits = digits.slice(decimalIndex).replace(/0+$/, "")
|
||||
return fractionDigits ? `${sign}${whole}.${fractionDigits}` : `${sign}${whole}`
|
||||
}
|
||||
|
||||
const numberToPlainString = (value: number): string => {
|
||||
if (!Number.isFinite(value)) return ""
|
||||
const stringified = value.toString()
|
||||
return SCIENTIFIC_NOTATION_REGEX.test(stringified) ? convertScientificToDecimalString(stringified) : stringified
|
||||
}
|
||||
|
||||
const normalizeFromCell = (cell: CellObject | undefined): string | undefined => {
|
||||
if (!cell) return undefined
|
||||
|
||||
const { v, w } = cell
|
||||
const cellType = (cell.t as string) || ""
|
||||
|
||||
if (typeof w === "string" && w.trim() !== "") {
|
||||
const trimmed = w.trim()
|
||||
return SCIENTIFIC_NOTATION_REGEX.test(trimmed) ? convertScientificToDecimalString(trimmed) : trimmed
|
||||
}
|
||||
|
||||
switch (cellType) {
|
||||
case "n":
|
||||
if (typeof v === "number") return numberToPlainString(v)
|
||||
if (typeof v === "string") {
|
||||
const trimmed = v.trim()
|
||||
return SCIENTIFIC_NOTATION_REGEX.test(trimmed) ? convertScientificToDecimalString(trimmed) : trimmed
|
||||
}
|
||||
return v === undefined || v === null ? "" : String(v)
|
||||
case "s":
|
||||
case "str":
|
||||
return typeof v === "string" ? v : v === undefined || v === null ? "" : String(v)
|
||||
case "b":
|
||||
return v ? "TRUE" : "FALSE"
|
||||
case "d":
|
||||
if (v instanceof Date) return v.toISOString()
|
||||
if (typeof v === "number") {
|
||||
const date = XLSX.SSF.parse_date_code(v)
|
||||
if (date) {
|
||||
const year = date.y.toString().padStart(4, "0")
|
||||
const month = date.m.toString().padStart(2, "0")
|
||||
const day = date.d.toString().padStart(2, "0")
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
}
|
||||
return v === undefined || v === null ? "" : String(v)
|
||||
default:
|
||||
return v === undefined || v === null ? "" : String(v)
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeCellValue = (value: unknown, cell: CellObject | undefined): string => {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
const fallback = normalizeFromCell(cell)
|
||||
return fallback !== undefined ? fallback : ""
|
||||
}
|
||||
|
||||
if (typeof value === "number") {
|
||||
return numberToPlainString(value)
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim()
|
||||
if (trimmed === "") {
|
||||
const fallback = normalizeFromCell(cell)
|
||||
return fallback !== undefined ? fallback : ""
|
||||
}
|
||||
return SCIENTIFIC_NOTATION_REGEX.test(trimmed) ? convertScientificToDecimalString(trimmed) : value
|
||||
}
|
||||
|
||||
if (typeof value === "boolean") {
|
||||
return value ? "TRUE" : "FALSE"
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString()
|
||||
}
|
||||
|
||||
const fallback = normalizeFromCell(cell)
|
||||
return fallback !== undefined ? fallback : String(value)
|
||||
}
|
||||
|
||||
export const mapWorkbook = (workbook: XLSX.WorkBook, sheetName?: string): RawData[] => {
|
||||
// Use the provided sheetName or default to the first sheet
|
||||
const sheetToUse = sheetName || workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[sheetToUse]
|
||||
|
||||
const data = XLSX.utils.sheet_to_json<string[]>(worksheet, {
|
||||
const rangeRef = worksheet["!ref"] || "A1"
|
||||
const sheetRange = XLSX.utils.decode_range(rangeRef)
|
||||
|
||||
const sheetData = XLSX.utils.sheet_to_json<unknown[]>(worksheet, {
|
||||
header: 1,
|
||||
raw: false,
|
||||
raw: true,
|
||||
defval: "",
|
||||
blankrows: true,
|
||||
})
|
||||
|
||||
return data
|
||||
const columnCount = Math.max(
|
||||
sheetRange.e.c - sheetRange.s.c + 1,
|
||||
...sheetData.map((row) => row.length),
|
||||
)
|
||||
|
||||
return sheetData.map((row, rowIndex) => {
|
||||
const sheetRow = sheetRange.s.r + rowIndex
|
||||
const normalizedRow: string[] = []
|
||||
|
||||
for (let columnOffset = 0; columnOffset < columnCount; columnOffset++) {
|
||||
const sheetColumn = sheetRange.s.c + columnOffset
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: sheetRow, c: sheetColumn })
|
||||
const cell = worksheet[cellAddress] as CellObject | undefined
|
||||
const value = row[columnOffset]
|
||||
normalizedRow.push(normalizeCellValue(value, cell))
|
||||
}
|
||||
|
||||
return normalizedRow as RawData
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user