diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 0e8ba3a..6519c4d 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -3,8 +3,10 @@
- This code is written in Svelte 5
- It's important to only use modern Svelte 5 syntax, runes, and features.
- Do not use $:, do not use eventDispatching as they are both deprecated
- - User $effect, $state, $derived
+ - Use $effect, $state, $derived, eg. let { value } = $state(initialValue);
- Pass fucntions as props instead od dispatching events
+ - Mixing old (on:click) and new syntaxes for event handling is not allowed. Use only the onclick syntax
+ - when setting state entity, simply od variable = newValue, do not use setState or similar methods like $state.
- Use styling from ".github/styling.md" for any UI components.
- Refer to the ".github/core-instructions.md" for the overall structure of the application.
- Generate ".github/done.md" file to see what is done and what is not. Check it when you start and finish a task.
diff --git a/src/lib/components/Wizard.svelte b/src/lib/components/Wizard.svelte
index 13af3c4..bab8fcc 100644
--- a/src/lib/components/Wizard.svelte
+++ b/src/lib/components/Wizard.svelte
@@ -22,12 +22,6 @@
'Filter Rows',
'Review Photos'
];
-
- function goToPreviousStep() {
- if ($currentStep > 1) {
- currentStep.update(n => n - 1);
- }
- }
@@ -55,17 +49,6 @@
-
-
-
-
-
-
+
diff --git a/src/lib/components/wizard/StepColumnMap.svelte b/src/lib/components/wizard/StepColumnMap.svelte
index 3795593..5ec41fe 100644
--- a/src/lib/components/wizard/StepColumnMap.svelte
+++ b/src/lib/components/wizard/StepColumnMap.svelte
@@ -2,15 +2,48 @@
import { selectedSheet, columnMapping, rawSheetData, currentStep } from '$lib/stores';
import { getSheetNames, getSheetData } from '$lib/google';
import { onMount } from 'svelte';
+
+ // Type definitions for better TypeScript support
+ interface ColumnMappingType {
+ name: number;
+ surname: number;
+ nationality: number;
+ birthday: number;
+ pictureUrl: number;
+ alreadyPrinted: number;
+ [key: string]: number; // Index signature to allow string indexing
+ }
+
+ interface SheetInfoType {
+ id?: string;
+ spreadsheetId?: string;
+ name: string;
+ sheetName?: string;
+ sheetMapping?: string;
+ columnMapping?: ColumnMappingType;
+ lastUsed?: string;
+ }
- let isLoadingSheets = false;
- let isLoadingData = false;
- let availableSheets: string[] = [];
- let selectedSheetName = '';
- let error = '';
- let sheetHeaders: string[] = [];
- let previewData: string[][] = [];
- let mappingComplete = false;
+ let isLoadingSheets = $state(false);
+ let isLoadingData = $state(false);
+ let availableSheets = $state([]);
+ let selectedSheetName = $state('');
+ let error = $state('');
+ let sheetHeaders = $state([]);
+ let previewData = $state([]);
+ let mappingComplete = $state(false);
+ let hasSavedMapping = $state(false);
+ let showMappingEditor = $state(false);
+ let savedSheetInfo = $state(null);
+
+ let mappedIndices = $state({
+ name: -1,
+ surname: -1,
+ nationality: -1,
+ birthday: -1,
+ pictureUrl: -1,
+ alreadyPrinted: -1
+ });
const requiredFields = [
{ key: 'name', label: 'First Name', required: true },
@@ -21,30 +54,123 @@
{ key: 'alreadyPrinted', label: 'Already Printed', required: false }
];
- let mappedIndices = {
- name: -1,
- surname: -1,
- nationality: -1,
- birthday: -1,
- pictureUrl: -1,
- alreadyPrinted: -1
- };
-
- // Load available sheets when component mounts
+ // Load available sheets when component mounts
onMount(async () => {
if ($selectedSheet) {
+ console.log('Selected sheet on mount:', $selectedSheet);
+
+ // Check if we already have saved mapping data
+ const recentSheetsData = localStorage.getItem('esn-recent-sheets');
+
+ if (recentSheetsData) {
+ try {
+ const recentSheets = JSON.parse(recentSheetsData);
+ if (recentSheets && recentSheets.length > 0) {
+ // Find a sheet that matches the current spreadsheet
+ const savedSheet = recentSheets.find((sheet: SheetInfoType) =>
+ (sheet.id === $selectedSheet.spreadsheetId || sheet.spreadsheetId === $selectedSheet.spreadsheetId)
+ );
+
+ if (savedSheet) {
+ console.log('Found saved sheet configuration:', savedSheet);
+ // We have a saved sheet for this spreadsheet
+ selectedSheetName = savedSheet.sheetName || savedSheet.sheetMapping || '';
+ savedSheetInfo = savedSheet;
+
+ if (savedSheet.columnMapping) {
+ // Set the mapped indices from saved data
+ mappedIndices = {
+ name: savedSheet.columnMapping.name ?? -1,
+ surname: savedSheet.columnMapping.surname ?? -1,
+ nationality: savedSheet.columnMapping.nationality ?? -1,
+ birthday: savedSheet.columnMapping.birthday ?? -1,
+ pictureUrl: savedSheet.columnMapping.pictureUrl ?? -1,
+ alreadyPrinted: savedSheet.columnMapping.alreadyPrinted ?? -1
+ };
+
+ hasSavedMapping = true;
+ updateMappingStatus();
+ columnMapping.set(mappedIndices);
+
+ // Don't load sheet data immediately for better performance
+ // We'll load it when needed (when editing or continuing)
+
+ return; // Skip loading available sheets since we're using saved data
+ }
+ }
+ }
+ } catch (err) {
+ console.error('Error parsing saved sheets data:', err);
+ }
+ }
+
+ // If no saved data was found or it couldn't be used, load sheets as usual
await loadAvailableSheets();
+ } else {
+ console.error('No spreadsheet selected on mount');
}
});
- async function loadAvailableSheets() {
- if (!$selectedSheet) return;
+ // Load sheet data quietly (for previously saved sheets)
+ async function loadSheetDataQuietly(sheetName: string) {
+ if (!$selectedSheet || !sheetName) {
+ console.error('Cannot load sheet data: missing selectedSheet or sheetName', {
+ selectedSheet: $selectedSheet,
+ sheetName: sheetName
+ });
+ return;
+ }
+ try {
+ console.log('Loading sheet data quietly for spreadsheet:', $selectedSheet.spreadsheetId, 'sheet:', sheetName);
+
+ // Make sure we verify the sheet exists before trying to load it
+ if (availableSheets.length === 0) {
+ // We need to load available sheets first
+ await loadAvailableSheets();
+
+ // If after loading sheets, we still don't have the sheet, show the editor
+ if (!availableSheets.includes(sheetName)) {
+ console.warn(`Sheet "${sheetName}" not found in spreadsheet, showing editor`);
+ showMappingEditor = true;
+ return;
+ }
+ }
+
+ // Fetch first 10 rows for headers only
+ const range = `${sheetName}!A1:Z10`;
+ const data = await getSheetData($selectedSheet.spreadsheetId, range);
+
+ if (data && data.length > 0) {
+ console.log('Loaded sheet data with', data.length, 'rows');
+ sheetHeaders = data[0];
+ previewData = data.slice(1, Math.min(4, data.length)); // Get up to 3 rows for preview
+ // Don't set the rawSheetData here as that will be loaded in the next step
+ } else {
+ console.warn(`No data returned for sheet "${sheetName}", showing editor`);
+ showMappingEditor = true;
+ }
+ } catch (err) {
+ console.error('Error loading sheet data quietly:', err, 'for sheet:', sheetName);
+ // If there's an error, show the full editor so the user can select a sheet
+ showMappingEditor = true;
+ }
+ }
+
+ async function loadAvailableSheets() {
+ if (!$selectedSheet) {
+ console.error('Cannot load available sheets: no sheet selected');
+ return;
+ }
+
+ console.log('Loading available sheets for spreadsheet:', $selectedSheet.spreadsheetId);
isLoadingSheets = true;
error = '';
try {
- availableSheets = await getSheetNames($selectedSheet.id);
+ const sheetNames = await getSheetNames($selectedSheet.spreadsheetId);
+ console.log('Loaded sheet names:', sheetNames);
+ availableSheets = sheetNames;
// Don't auto-select any sheet - let user choose
} catch (err) {
console.error('Error loading sheet names:', err);
@@ -55,7 +181,9 @@
}
function handleSheetSelect(sheetName: string) {
+ console.log('Sheet selected:', sheetName);
selectedSheetName = sheetName;
+
// Clear any previous data when selecting a new sheet
rawSheetData.set([]);
sheetHeaders = [];
@@ -69,6 +197,8 @@
alreadyPrinted: -1
};
mappingComplete = false;
+ hasSavedMapping = false;
+ showMappingEditor = true;
// Load sheet data
if (sheetName) {
@@ -77,20 +207,25 @@
}
async function loadSheetData(sheetName: string) {
- if (!$selectedSheet) return;
+ if (!$selectedSheet) {
+ console.error('Cannot load sheet data: no sheet selected');
+ return;
+ }
+ console.log('Loading sheet data for spreadsheet:', $selectedSheet.spreadsheetId, 'sheet:', sheetName);
isLoadingData = true;
error = '';
try {
// Fetch first 10 rows for headers and preview
const range = `${sheetName}!A1:Z10`;
- const data = await getSheetData($selectedSheet.id, range);
+ const data = await getSheetData($selectedSheet.spreadsheetId, range);
if (data && data.length > 0) {
+ console.log('Loaded sheet data with', data.length, 'rows');
sheetHeaders = data[0];
previewData = data.slice(1, Math.min(4, data.length)); // Get up to 3 rows for preview
- rawSheetData.set(data);
+ // We don't need to set all the raw data here
// Try to auto-map columns
autoMapColumns();
@@ -99,6 +234,7 @@
loadSavedColumnMapping();
} else {
error = 'The selected sheet appears to be empty.';
+ console.warn('Sheet is empty');
}
} catch (err) {
console.error('Error loading sheet data:', err);
@@ -120,7 +256,7 @@
};
// Auto-mapping patterns
- const patterns = {
+ const patterns: Record = {
name: /first[\s_-]*name|name|given[\s_-]*name|vorname/i,
surname: /last[\s_-]*name|surname|family[\s_-]*name|nachname/i,
nationality: /nationality|country|nation/i,
@@ -159,11 +295,15 @@
}
}
+ console.log('Auto-mapped columns:', mappedIndices);
updateMappingStatus();
}
function loadSavedColumnMapping() {
- if (!$selectedSheet || !selectedSheetName) return;
+ if (!$selectedSheet || !selectedSheetName) {
+ console.log('Cannot load saved column mapping: missing selectedSheet or selectedSheetName');
+ return;
+ }
try {
const recentSheetsKey = 'esn-recent-sheets';
@@ -171,11 +311,14 @@
if (existingData) {
const recentSheets = JSON.parse(existingData);
- const savedSheet = recentSheets.find(sheet =>
- sheet.id === $selectedSheet.id && sheet.sheetName === selectedSheetName
+ const savedSheet = recentSheets.find((sheet: SheetInfoType) =>
+ (sheet.id === $selectedSheet.spreadsheetId || sheet.spreadsheetId === $selectedSheet.spreadsheetId) &&
+ (sheet.sheetName === selectedSheetName || sheet.sheetMapping === selectedSheetName)
);
if (savedSheet && savedSheet.columnMapping) {
+ console.log('Found saved column mapping for current sheet:', savedSheet.columnMapping);
+
// Override auto-mapping with saved mapping
mappedIndices = {
name: savedSheet.columnMapping.name ?? -1,
@@ -186,7 +329,11 @@
alreadyPrinted: savedSheet.columnMapping.alreadyPrinted ?? -1
};
+ hasSavedMapping = true;
+ savedSheetInfo = savedSheet;
updateMappingStatus();
+ } else {
+ console.log('No saved column mapping found for the current sheet');
}
}
} catch (err) {
@@ -194,7 +341,7 @@
}
}
- function handleColumnMapping(field: string, index: number) {
+ function handleColumnMapping(field: keyof ColumnMappingType, index: number) {
mappedIndices[field] = index;
updateMappingStatus();
}
@@ -210,6 +357,7 @@
};
mappingComplete = Object.values(requiredIndices).every(index => index !== -1);
+ console.log('Mapping complete:', mappingComplete);
// Update the column mapping store
columnMapping.set({
@@ -232,8 +380,9 @@
let recentSheets = existingData ? JSON.parse(existingData) : [];
// Find the current sheet in recent sheets and update its column mapping
- const sheetIndex = recentSheets.findIndex(sheet =>
- sheet.id === $selectedSheet.id && sheet.sheetName === selectedSheetName
+ const sheetIndex = recentSheets.findIndex((sheet: SheetInfoType) =>
+ (sheet.id === $selectedSheet.spreadsheetId || sheet.spreadsheetId === $selectedSheet.spreadsheetId) &&
+ (sheet.sheetName === selectedSheetName || sheet.sheetMapping === selectedSheetName)
);
const columnMappingData = {
@@ -249,12 +398,16 @@
// Update existing entry
recentSheets[sheetIndex].columnMapping = columnMappingData;
recentSheets[sheetIndex].lastUsed = new Date().toISOString();
+
+ // Ensure we have consistent property names
+ recentSheets[sheetIndex].spreadsheetId = recentSheets[sheetIndex].spreadsheetId || recentSheets[sheetIndex].id;
+ recentSheets[sheetIndex].sheetMapping = recentSheets[sheetIndex].sheetMapping || recentSheets[sheetIndex].sheetName;
} else {
// Add new entry
const newEntry = {
- id: $selectedSheet.id,
+ spreadsheetId: $selectedSheet.spreadsheetId,
name: $selectedSheet.name,
- sheetName: selectedSheetName,
+ sheetMapping: selectedSheetName,
columnMapping: columnMappingData,
lastUsed: new Date().toISOString()
};
@@ -274,6 +427,34 @@
currentStep.set(4); // Move to next step
}
+
+ async function handleShowEditor() {
+ showMappingEditor = true;
+
+ // Load available sheets if they haven't been loaded yet
+ if (availableSheets.length === 0) {
+ await loadAvailableSheets();
+ }
+
+ // Ensure we have sheet data if a sheet is already selected
+ if (selectedSheetName && sheetHeaders.length === 0) {
+ // Load the sheet data but keep mappings intact
+ try {
+ isLoadingData = true;
+ const range = `${selectedSheetName}!A1:Z10`;
+ const data = await getSheetData($selectedSheet.spreadsheetId, range);
+
+ if (data && data.length > 0) {
+ sheetHeaders = data[0];
+ previewData = data.slice(1, Math.min(4, data.length));
+ }
+ } catch (err) {
+ console.error('Error loading sheet data for editor:', err);
+ } finally {
+ isLoadingData = false;
+ }
+ }
+ }
@@ -287,201 +468,236 @@
First, select which sheet contains your member data, then map the columns to the required fields.