diff --git a/src/lib/components/Wizard.svelte b/src/lib/components/Wizard.svelte index 5b7a100..d6bbc2f 100644 --- a/src/lib/components/Wizard.svelte +++ b/src/lib/components/Wizard.svelte @@ -3,18 +3,21 @@ import StepAuth from './wizard/StepAuth.svelte'; import StepSheetSearch from './wizard/StepSheetSearch.svelte'; import StepColumnMap from './wizard/StepColumnMap.svelte'; + import StepRowFilter from './wizard/StepRowFilter.svelte'; // Additional steps to be added as they are implemented const steps = [ StepAuth, StepSheetSearch, - StepColumnMap + StepColumnMap, + StepRowFilter ]; const stepTitles = [ 'Authenticate', 'Select Sheet', - 'Map Columns' + 'Map Columns', + 'Filter Rows' ]; function goToPreviousStep() { diff --git a/src/lib/components/wizard/StepColumnMap.svelte b/src/lib/components/wizard/StepColumnMap.svelte index 01f1412..3795593 100644 --- a/src/lib/components/wizard/StepColumnMap.svelte +++ b/src/lib/components/wizard/StepColumnMap.svelte @@ -17,7 +17,8 @@ { key: 'surname', label: 'Last Name', required: true }, { key: 'nationality', label: 'Nationality', required: true }, { key: 'birthday', label: 'Birthday', required: true }, - { key: 'pictureUrl', label: 'Photo URL', required: true } + { key: 'pictureUrl', label: 'Photo URL', required: true }, + { key: 'alreadyPrinted', label: 'Already Printed', required: false } ]; let mappedIndices = { @@ -25,7 +26,8 @@ surname: -1, nationality: -1, birthday: -1, - pictureUrl: -1 + pictureUrl: -1, + alreadyPrinted: -1 }; // Load available sheets when component mounts @@ -63,7 +65,8 @@ surname: -1, nationality: -1, birthday: -1, - pictureUrl: -1 + pictureUrl: -1, + alreadyPrinted: -1 }; mappingComplete = false; @@ -112,7 +115,8 @@ surname: -1, nationality: -1, birthday: -1, - pictureUrl: -1 + pictureUrl: -1, + alreadyPrinted: -1 }; // Auto-mapping patterns @@ -121,7 +125,8 @@ surname: /last[\s_-]*name|surname|family[\s_-]*name|nachname/i, nationality: /nationality|country|nation/i, birthday: /birth|date[\s_-]*of[\s_-]*birth|birthday|dob/i, - pictureUrl: /photo|picture|image|url|avatar/i + pictureUrl: /photo|picture|image|url|avatar/i, + alreadyPrinted: /already[\s_-]*printed|printed|status/i }; sheetHeaders.forEach((header, index) => { @@ -133,6 +138,27 @@ } }); + // If "Already Printed" column wasn't found, try to find the first empty column + if (mappedIndices.alreadyPrinted === -1 && previewData.length > 0) { + // Check up to 26 columns (A-Z) or the number of headers, whichever is larger + const maxColumns = Math.max(sheetHeaders.length, 26); + + for (let colIndex = 0; colIndex < maxColumns; colIndex++) { + // Check if this column is empty (all preview rows are empty for this column) + const isEmpty = previewData.every(row => !row[colIndex] || String(row[colIndex]).trim() === ''); + + // Also check if this column isn't already mapped to another field + const isAlreadyMapped = Object.entries(mappedIndices).some(([field, index]) => + field !== 'alreadyPrinted' && index === colIndex + ); + + if (isEmpty && !isAlreadyMapped) { + mappedIndices.alreadyPrinted = colIndex; + break; + } + } + } + updateMappingStatus(); } @@ -156,7 +182,8 @@ surname: savedSheet.columnMapping.surname ?? -1, nationality: savedSheet.columnMapping.nationality ?? -1, birthday: savedSheet.columnMapping.birthday ?? -1, - pictureUrl: savedSheet.columnMapping.pictureUrl ?? -1 + pictureUrl: savedSheet.columnMapping.pictureUrl ?? -1, + alreadyPrinted: savedSheet.columnMapping.alreadyPrinted ?? -1 }; updateMappingStatus(); @@ -173,7 +200,16 @@ } function updateMappingStatus() { - mappingComplete = Object.values(mappedIndices).every(index => index !== -1); + // Only check required fields for completion + const requiredIndices = { + name: mappedIndices.name, + surname: mappedIndices.surname, + nationality: mappedIndices.nationality, + birthday: mappedIndices.birthday, + pictureUrl: mappedIndices.pictureUrl + }; + + mappingComplete = Object.values(requiredIndices).every(index => index !== -1); // Update the column mapping store columnMapping.set({ @@ -181,7 +217,8 @@ surname: mappedIndices.surname, nationality: mappedIndices.nationality, birthday: mappedIndices.birthday, - pictureUrl: mappedIndices.pictureUrl + pictureUrl: mappedIndices.pictureUrl, + alreadyPrinted: mappedIndices.alreadyPrinted }); } @@ -204,7 +241,8 @@ surname: mappedIndices.surname, nationality: mappedIndices.nationality, birthday: mappedIndices.birthday, - pictureUrl: mappedIndices.pictureUrl + pictureUrl: mappedIndices.pictureUrl, + alreadyPrinted: mappedIndices.alreadyPrinted }; if (sheetIndex !== -1) { @@ -370,8 +408,13 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md bg-white text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" > - {#each sheetHeaders as header, index} - + {#each Array.from({length: Math.max(sheetHeaders.length, 26)}, (_, i) => i) as index} + {/each} @@ -387,10 +430,10 @@
|
- {header}
+ {sheetHeaders[index] || `Column ${String.fromCharCode(65 + index)}`}
{#if Object.values(mappedIndices).includes(index)}
{requiredFields.find(f => mappedIndices[f.key] === index)?.label}
@@ -403,10 +446,10 @@
{#each previewData as row}
- {cell}
+ {row[index] || ''}
|
{/each}
-
diff --git a/src/lib/stores.ts b/src/lib/stores.ts
index 0c67e0a..4bebbea 100644
--- a/src/lib/stores.ts
+++ b/src/lib/stores.ts
@@ -9,6 +9,9 @@ export const session = writable<{
// Raw sheet data after import
export const rawSheetData = writableFilter Rows-Row filtering functionality will be implemented here. +
+
+
+
+
+ + Filter and Select Rows ++ ++ Review your data and select which rows you want to include in the card generation. + Only rows with all required fields will be available for selection. + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Total rows: {processedData.length}
+ Valid rows: {processedData.filter(row => row._isValid).length}
+ Already printed: {processedData.filter(row => isRowAlreadyPrinted(row)).length}
+ Filtered rows: {filteredData.length}
+ Selected: {selectedValidCount}
+
+
+ {#if filteredData.length === 0}
+
+
+
+ {#if selectedValidCount > 0}
+
+
+
+ {:else}
+ No data found++ {searchTerm ? 'No rows match your search criteria.' : 'No data available to display.'} + +
+
+ {/if}
+
+
+ {/if}
+
+
+
+
+
+ {selectedValidCount} {selectedValidCount === 1 ? 'row' : 'rows'} selected for card generation
+
+
+
+
+
+ |
|---|