Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
import type { ColumnFormat } from "$lib/types/columnModel";

// 🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️ This is FORMATTING only
type FormatT = 'string' | 'number' | 'date' | 'gps';
export function formatValue(format: FormatT, value: any): string {
if (format === "date") { return formatDate(value); }
if (format == "gps") { return formatGps(value); }
if (format === "number") { return formatNumber(value); }
if (format === "string") { return formatString(value); }
return value;
}

function formatGps(value: any): string {
return "Gps:" + value;
}

function formatNumber(value: any): string {
return "Number: " + value;
}

function formatString(value: any): string {
return "String: " + value;
}



function numberFormat(value: number): string {
return new Intl.NumberFormat('en-US', {
style: 'decimal',
minimumFractionDigits: 0,
maximumFractionDigits: 2
}).format(value);
}

function formatDate(value: string): string {
return new Date(value).toLocaleDateString('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
}

// 🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️🔉️ This is detection only

// 👍️🌲️👍️🌲️👍️🌲️👍️🌲️👍️🌲️NUMBERS🌲️🌲️🌲️🌲️🌲️🌲️🌲️
// Number detection with debug
Expand All @@ -16,6 +59,7 @@
return false;
}


// 🌲️🌲️🌲️🌲️🌲️🌲️🌲️DATES🌲️🌲️🌲️🌲️🌲️🌲️🌲️
function isDate(value: any): boolean {
if (typeof value === 'number') {
Expand Down Expand Up @@ -47,15 +91,16 @@
/^\d{1,2}(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{4}$/i
];
return DATE_FORMATS.some((format) => format.test(value));
// print as JavaScript data string
}
return false;
}

// 3 Apr 2025 8:55 AM New function
export function detectFormat(columnData: Array<string | number | null>, currentColumnHeader: string, selectedFormat: string) {
export function detectFormat(columnData: Array<string | number | null>, currentColumnHeader: string): ColumnFormat {
console.log('Checking column format for:', currentColumnHeader);
// Reset detected format for new column
selectedFormat = 'string';
let selectedFormat: ColumnFormat = 'string';
// Get first 3 non-empty values
const sampleValues = columnData
.filter((val: string | number | null) => val !== null && val !== '')
Expand All @@ -67,19 +112,13 @@

// If majority format
if (dateCount >= Math.ceil(sampleValues.length / 2)) {
if (selectedFormat !== 'date') {
// console.log(`Setting format to 'date' (${dateCount}/${sampleValues.length} dates)`);
selectedFormat = 'date';
}
} else if (numberCount >= Math.ceil(sampleValues.length / 2)) {
if (selectedFormat !== 'number') {
// console.log(`Setting format to 'number' (${numberCount}/${sampleValues.length} numbers)`);
selectedFormat = 'number';
}
} else {
console.log(
`No majority format - keeping as '${selectedFormat}' (${numberCount} numbers, ${dateCount} dates)`
);
}
return selectedFormat;
};
};
22 changes: 12 additions & 10 deletions src/lib/transferComponents/newTableData.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import type { ColumnRep } from '$lib/types/columnModel';
import FormatSelectorComponent from './FormatSelectorComponent.svelte';
import { importedData } from '$lib/transferComponents/modelState.svelte';

<<<<<<< HEAD
import {formatValue} from "./newFormatDetection.svelte";

=======
import {formatValue} from './newFormatDetection.svelte'
>>>>>>> 9d97b0f (Introduce some reactivity and state modifications.)
let columnFormats = $state<Record<string, string>>({});

// Number formatting function
Expand All @@ -27,18 +32,18 @@
// then run detection and formatting for that type on the columnRep

// Whenever select dropdown changes, this updates. Handle format changes
export function formatEvent(
export function formatEvent(column: ColumnRep,
event: CustomEvent<{ destinationFormat: string; headerName: string }>
) {
// this is dropdown value user chose.
const selectedFormat = event.detail.destinationFormat;
const selectedFormat = event.detail.destinationFormat as 'string' | 'number' | 'date' | 'gps';
console.log(`Called from format event from table: ${selectedFormat}`);
// Update column format in state
// might be better to update main model
column.type = selectedFormat;
columnFormats[event.detail.headerName] = selectedFormat;
console.log('calling column formats', columnFormats);
}

</script>

{#if importedData.columns.length > 0}
Expand All @@ -47,9 +52,9 @@
{#each importedData.columns as column}
<FormatSelectorComponent
columnData={getColumnData(column)}
currentFormat={columnFormats[column.headerName] || 'string'}
currentFormat={column.type}
currentColumnHeader={column.headerName}
onformatchange={formatEvent}
onformatchange={(event) => formatEvent(column, event)}
/>
{/each}
</div>
Expand All @@ -66,10 +71,7 @@
<tr>
{#each importedData.columns as column, columnIndex}
<td>
{columnFormats[column.headerName] === 'number' &&
typeof column.values[rowIndex] === 'number'
? numberFormat(column.values[rowIndex] as number)
: (column.values[rowIndex] ?? '')}
{formatValue(column.type, column.values[rowIndex])}
</td>
{/each}
</tr>
Expand Down
9 changes: 8 additions & 1 deletion src/lib/transferComponents/transferCSVImporter.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!--
<!--
Svelte 5 $dispatch documentation reference:
https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Component-events
Components should accept callback props - which means you then pass functions as properties to these components
Expand All @@ -7,6 +7,7 @@ Components should accept callback props - which means you then pass functions as
import Papa from 'papaparse';
import type { ColumnRep } from '$lib/types/columnModel';
import { BaseColumnModel } from '$lib/types/columnModel';
import { detectFormat } from '$lib/transferComponents/newFormatDetection.svelte'

const { onprocessed } = $props<{
onprocessed: (data: ColumnRep[]) => void;
Expand Down Expand Up @@ -80,7 +81,13 @@ Components should accept callback props - which means you then pass functions as
values
};
});
// 3 Apr 2025 9:03 AM TO DO: here loop through columnData and call detectFormat for each column
// then update currentFormat and type. -> update those types.
// Before the onprocessed call
for (let i = 0; i < columnData.length; ++i) {
const detectedFormat = detectFormat(columnData[i].values, columnData[i].headerName);
columnData[i].type = detectedFormat;
}
console.log('Dispatching processed data:', columnData);
onprocessed?.(columnData);
// Dispatch the transformed data
Expand Down
19 changes: 10 additions & 9 deletions src/lib/types/columnModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ export interface ColumnDef {
};
}

export type ColumnFormat = 'string' | 'number' | 'date' | 'gps';
export interface ColumnRep extends ColumnDef {
/** The column name/header from the imported data */
headerName: string;
type: 'string' | 'number' | 'date' | 'gps';
type: ColumnFormat;
/** The actual data values for this column */
values: Array<string | number | null>;
/** Optional validation errors by row index */
Expand All @@ -68,8 +69,8 @@ export class BaseColumnModel implements ColumnDef {
isMerged?: boolean;
mergedFrom?: string[];
isGpsSource?: boolean;
type: 'string' | 'number' | 'date' | 'gps' = 'string';
currentFormat: 'string' | 'number' | 'date' | 'gps' = 'string';
type: ColumnFormat = 'string';
currentFormat: ColumnFormat = 'string';
selectFormatCoercion?: selectFormatCoercion;
cellValidation?: CellValidationState[];
dbMapping?: {
Expand All @@ -87,7 +88,7 @@ export class BaseColumnModel implements ColumnDef {
this.isMapped = false;
this.isFormatted = false;
}
changeFormat(newType: 'string' | 'number' | 'date' | 'gps', changedBy: 'auto' | 'user' = 'user') {
changeFormat(newType: ColumnFormat, changedBy: 'auto' | 'user' = 'user') {
if (this.type !== newType) {
this.selectFormatCoercion = {
originalFormat: this.type,
Expand All @@ -112,8 +113,8 @@ export class BaseColumnModel implements ColumnDef {
}

interface selectFormatCoercion {
originalFormat: 'string' | 'number' | 'date' | 'gps';
coercedFormat: 'string' | 'number' | 'date' | 'gps';
originalFormat: ColumnFormat;
coercedFormat: ColumnFormat;
timestamp: Date;
changedBy: 'auto' | 'user';
userSelected: boolean; // Add this to track manual selections
Expand Down Expand Up @@ -162,7 +163,7 @@ export class NumberColumnModel extends BaseColumnModel implements NumberColumn {
precision?: number;
useThousandsSeparator?: boolean;
};
currentFormat: 'string' | 'number' | 'date' | 'gps' = 'number';
currentFormat: ColumnFormat = 'number';
validation?: {
min?: number;
max?: number;
Expand Down Expand Up @@ -209,7 +210,7 @@ export class DateColumnModel extends BaseColumnModel implements DateColumn {
format?: {
dateFormat?: string;
};
currentFormat: 'string' | 'number' | 'date' | 'gps' = 'date';
currentFormat: ColumnFormat = 'date';

constructor(headerName: string, dateFormat?: string) {
super(headerName);
Expand Down Expand Up @@ -250,7 +251,7 @@ export class GpsColumnModel extends BaseColumnModel implements GpsColumn {
gpsFormat?: 'DMS' | 'DD';
precision?: number;
};
currentFormat: 'string' | 'number' | 'date' | 'gps' = 'gps';
currentFormat: ColumnFormat = 'gps';

constructor(name: string, gpsFormat: 'DMS' | 'DD' = 'DD', precision: number = 7) {
super(name);
Expand Down