diff --git a/src/pages/tools/csv/swap-csv-columns/index.tsx b/src/pages/tools/csv/swap-csv-columns/index.tsx index 0190347..06bb838 100644 --- a/src/pages/tools/csv/swap-csv-columns/index.tsx +++ b/src/pages/tools/csv/swap-csv-columns/index.tsx @@ -11,8 +11,10 @@ import CheckboxWithDesc from '@components/options/CheckboxWithDesc'; import SimpleRadio from '@components/options/SimpleRadio'; import TextFieldWithDesc from '@components/options/TextFieldWithDesc'; import { csvColumnsSwap } from './service'; +import { getCsvHeaders } from '@utils/csv'; +import { InitialValuesType } from './types'; -const initialValues = { +const initialValues: InitialValuesType = { fromPositionStatus: true, toPositionStatus: true, fromPosition: '1', @@ -25,7 +27,7 @@ const initialValues = { commentCharacter: '#', emptyLines: true }; -type InitialValuesType = typeof initialValues; + const exampleCards: CardExampleType[] = [ { title: 'Move the Key Column to the First Position', @@ -48,8 +50,8 @@ Utah,Zion Park`, toPositionStatus: true, fromPosition: '1', toPosition: '2', - fromHeader: '', - toHeader: '', + fromHeader: 'park_name', + toHeader: 'location', emptyValuesFilling: false, customFiller: '*', deleteComment: false, @@ -120,7 +122,7 @@ Xiaomi,13 Ultra,Android,6.6″,$849`, fromPosition: '1', toPosition: '4', fromHeader: 'ScreenSize', - toHeader: 'Function', + toHeader: 'OS', emptyValuesFilling: true, customFiller: 'x', deleteComment: true, @@ -137,25 +139,16 @@ export default function CsvToTsv({ const [input, setInput] = useState(''); const [result, setResult] = useState(''); - const compute = (optionsValues: typeof initialValues, input: string) => { - setResult( - csvColumnsSwap( - input, - optionsValues.fromPositionStatus, - optionsValues.fromPosition, - optionsValues.toPositionStatus, - optionsValues.toPosition, - optionsValues.fromHeader, - optionsValues.toHeader, - optionsValues.emptyValuesFilling, - optionsValues.customFiller, - optionsValues.deleteComment, - optionsValues.commentCharacter, - optionsValues.emptyLines - ) - ); + const compute = (optionsValues: InitialValuesType, input: string) => { + setResult(csvColumnsSwap(input, optionsValues)); }; + const headers = getCsvHeaders(input); + const headerOptions = headers.map((item) => ({ + label: `${item}`, + value: item + })); + const getGroups: GetGroupsType = ({ values, updateField @@ -175,18 +168,21 @@ export default function CsvToTsv({ value={values.fromPosition} onOwnChange={(val) => updateField('fromPosition', val)} type="number" + inputProps={{ min: 1, max: headers.length }} /> )} + updateField('fromPositionStatus', false)} title="Set Column-From Header" checked={!values.fromPositionStatus} /> {!values.fromPositionStatus && ( - updateField('fromHeader', val)} + updateField('fromHeader', value)} + description={'Header of the first column you want to swap.'} /> )} @@ -207,6 +203,7 @@ export default function CsvToTsv({ value={values.toPosition} onOwnChange={(val) => updateField('toPosition', val)} type="number" + inputProps={{ min: 1, max: headers.length }} /> )} {!values.toPositionStatus && ( - updateField('toHeader', val)} + updateField('toHeader', value)} + description={'Header of the second column you want to swap..'} /> )} @@ -261,7 +259,7 @@ export default function CsvToTsv({ title="Delete Comments" description="if checked, comments given by the following character will be deleted" /> - {!values.emptyValuesFilling && ( + {values.deleteComment && ( header === fromHeader) + 1; + const from = options.fromPositionStatus + ? Number(options.fromPosition) + : headerRow.findIndex((header) => header === options.fromHeader) + 1; - const to = toPositionStatus - ? Number(toPosition) - : headerRow.findIndex((header) => header === toHeader) + 1; + const to = options.toPositionStatus + ? Number(options.toPosition) + : headerRow.findIndex((header) => header === options.toHeader) + 1; if (from <= 0 || to <= 0) throw new Error('Invalid column positions. Check headers or positions.'); @@ -37,44 +33,28 @@ function swap(lines: string[][], from: number, to: number): string[][] { }); } -export function csvColumnsSwap( - input: string, - fromPositionStatus: boolean, - fromPosition: string | '', - toPositionStatus: boolean, - toPosition: string | '', - fromHeader: string | '', - toHeader: string | '', - emptyValuesFilling: boolean, - customFiller: string | '', - deleteComment: boolean, - commentCharacter: string | '', - emptyLines: boolean -) { +export function csvColumnsSwap(input: string, options: InitialValuesType) { if (!input) { return ''; } // split csv input and remove comments - const rows = splitCsv(input, deleteComment, commentCharacter, emptyLines); + const rows = splitCsv( + input, + options.deleteComment, + options.commentCharacter, + options.emptyLines + ); const columnCount = Math.max(...rows.map((row) => row.length)); for (let i = 0; i < rows.length; i++) { for (let j = 0; j < columnCount; j++) { if (!rows[i][j]) { - rows[i][j] = emptyValuesFilling ? '' : customFiller; + rows[i][j] = options.emptyValuesFilling ? '' : options.customFiller; } } } - const positions = retrieveFromAndTo( - rows[0], - fromPositionStatus, - toPositionStatus, - fromPosition, - toPosition, - fromHeader, - toHeader - ); + const positions = retrieveFromAndTo(rows[0], options); const result = swap(rows, positions[0], positions[1]); return result.join('\n'); diff --git a/src/pages/tools/csv/swap-csv-columns/types.ts b/src/pages/tools/csv/swap-csv-columns/types.ts new file mode 100644 index 0000000..79a625d --- /dev/null +++ b/src/pages/tools/csv/swap-csv-columns/types.ts @@ -0,0 +1,13 @@ +export type InitialValuesType = { + fromPositionStatus: boolean; + fromPosition: string | ''; + toPositionStatus: boolean; + toPosition: string | ''; + fromHeader: string | ''; + toHeader: string | ''; + emptyValuesFilling: boolean; + customFiller: string | ''; + deleteComment: boolean; + commentCharacter: string | ''; + emptyLines: boolean; +}; diff --git a/src/utils/csv.ts b/src/utils/csv.ts index 9ecca3e..4830b1f 100644 --- a/src/utils/csv.ts +++ b/src/utils/csv.ts @@ -13,7 +13,7 @@ export function splitCsv( let rows = input.split('\n').map((row) => row.split(',')); // Remove comments if deleteComment is true - if (deleteComment) { + if (deleteComment && commentCharacter) { rows = rows.filter((row) => !row[0].trim().startsWith(commentCharacter)); } @@ -24,3 +24,13 @@ export function splitCsv( return rows; } + +/** + * get the headers from a CSV string . + * @param {string} input - The CSV input string. + * @returns {string[]} - The CSV header as a 1D array. + */ +export function getCsvHeaders(csvString: string): string[] { + const rows = csvString.split('\n').map((row) => row.split(',')); + return rows.length > 0 ? rows[0].map((header) => header.trim()) : []; +}