Fixed other two components

This commit is contained in:
Roman Krček
2025-07-17 21:00:47 +02:00
parent ffa427d42c
commit 4f119dc121
2 changed files with 135 additions and 87 deletions

View File

@@ -695,13 +695,23 @@
{/if} {/if}
<!-- Navigation --> <!-- Navigation -->
<div class="flex justify-end"> <!-- Navigation -->
<div class="flex justify-between">
<button
onclick={() => currentStep.set(2)}
class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg font-medium hover:bg-gray-300"
>
← Back to Sheet Selection
</button>
<button <button
onclick={handleContinue} onclick={handleContinue}
disabled={!mappingComplete} disabled={!mappingComplete}
class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed" class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
> >
{mappingComplete ? 'Continue →' : 'Complete mapping to continue'} {mappingComplete
? 'Continue →'
: 'Select a column mapping'}
</button> </button>
</div> </div>
</div> </div>

View File

@@ -2,6 +2,7 @@
import { selectedSheet, columnMapping, rawSheetData, filteredSheetData, currentStep, sheetData } from '$lib/stores'; import { selectedSheet, columnMapping, rawSheetData, filteredSheetData, currentStep, sheetData } from '$lib/stores';
import type { RowData } from '$lib/stores'; import type { RowData } from '$lib/stores';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { getSheetNames, getSheetData } from '$lib/google';
let searchTerm = ''; let searchTerm = '';
let sortColumn = ''; let sortColumn = '';
@@ -11,6 +12,7 @@
let processedData: any[] = []; let processedData: any[] = [];
let filteredData: any[] = []; let filteredData: any[] = [];
let headers: string[] = []; let headers: string[] = [];
let isLoading = false;
$: { $: {
// Filter data based on search term // Filter data based on search term
@@ -46,7 +48,23 @@
processSheetData(); processSheetData();
}); });
function processSheetData() { // Fetch raw sheet data from Google Sheets if not already loaded
async function fetchRawSheetData() {
if (!$rawSheetData || $rawSheetData.length === 0) {
if (!$selectedSheet) return;
const sheetNames = await getSheetNames($selectedSheet.spreadsheetId);
if (sheetNames.length === 0) return;
const sheetName = sheetNames[0];
const range = `${sheetName}!A:Z`;
const data = await getSheetData($selectedSheet.spreadsheetId, range);
rawSheetData.set(data);
}
}
async function processSheetData() {
isLoading = true;
try {
await fetchRawSheetData();
if (!$rawSheetData || $rawSheetData.length === 0 || !$columnMapping) { if (!$rawSheetData || $rawSheetData.length === 0 || !$columnMapping) {
return; return;
} }
@@ -108,6 +126,9 @@
); );
updateSelectAllState(); updateSelectAllState();
} finally {
isLoading = false;
}
} }
function toggleRowSelection(rowIndex: number) { function toggleRowSelection(rowIndex: number) {
@@ -193,6 +214,8 @@
const row = processedData.find(r => r._rowIndex === rowIndex); const row = processedData.find(r => r._rowIndex === rowIndex);
return row && row._isValid; return row && row._isValid;
}).length; }).length;
// Allow proceeding only if at least one valid row is selected
$: canProceed = selectedValidCount > 0;
</script> </script>
<div class="p-6"> <div class="p-6">
@@ -244,17 +267,40 @@
</div> </div>
<!-- Stats --> <!-- Stats -->
<div class="mt-4 flex flex-wrap gap-4 text-sm text-gray-600"> <div class="mt-4 flex items-center flex-wrap gap-4 text-sm text-gray-600">
<span>Total rows: {processedData.length}</span> <span>Total rows: {processedData.length}</span>
<span>Valid rows: {processedData.filter(row => row._isValid).length}</span> <span>Valid rows: {processedData.filter(row => row._isValid).length}</span>
<span class="text-orange-600">Already printed: {processedData.filter(row => isRowAlreadyPrinted(row)).length}</span> <span class="text-orange-600">Printed: {processedData.filter(row => isRowAlreadyPrinted(row)).length}</span>
<span>Filtered rows: {filteredData.length}</span> <span>Filtered rows: {filteredData.length}</span>
<span class="font-medium text-blue-600">Selected: {selectedValidCount}</span> <span class="font-medium text-blue-600">Selected: {selectedValidCount}</span>
<button
onclick={processSheetData}
disabled={isLoading}
class="ml-auto inline-flex items-center px-3 py-1 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-wait"
>
{#if isLoading}
<svg class="h-4 w-4 mr-2 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
</svg>
Refreshing...
{:else}
Refresh Data
{/if}
</button>
</div> </div>
</div> </div>
<!-- Data Table --> <!-- Data Table -->
<div class="bg-white border border-gray-200 rounded-lg overflow-hidden mb-6"> <div class="bg-white border border-gray-200 rounded-lg overflow-hidden mb-6 relative">
{#if isLoading}
<div class="absolute inset-0 flex items-center justify-center bg-white bg-opacity-75 z-10">
<svg class="h-10 w-10 text-blue-600 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
</svg>
</div>
{/if}
{#if filteredData.length === 0} {#if filteredData.length === 0}
<div class="text-center py-12"> <div class="text-center py-12">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -275,16 +321,16 @@
<input <input
type="checkbox" type="checkbox"
bind:checked={selectAll} bind:checked={selectAll}
on:change={toggleSelectAll} onchange={toggleSelectAll}
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
/> />
</th> </th>
<!-- Column Headers --> <!-- Column Headers -->
{#each headers as header} {#each headers.filter(h => h !== 'alreadyPrinted') as header}
<th <th
class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100"
on:click={() => handleSort(header)} onclick={() => handleSort(header)}
> >
<div class="flex items-center space-x-1"> <div class="flex items-center space-x-1">
<span>{getFieldLabel(header)}</span> <span>{getFieldLabel(header)}</span>
@@ -316,34 +362,18 @@
<input <input
type="checkbox" type="checkbox"
checked={selectedRows.has(row._rowIndex)} checked={selectedRows.has(row._rowIndex)}
on:change={() => toggleRowSelection(row._rowIndex)} onchange={() => toggleRowSelection(row._rowIndex)}
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
disabled={isRowAlreadyPrinted(row)}
/> />
{#if isRowAlreadyPrinted(row)}
<div class="text-xs text-orange-600 mt-1">Already printed</div>
{/if}
{:else} {:else}
<div class="w-4 h-4 bg-gray-200 rounded"></div> <div class="w-4 h-4 bg-gray-200 rounded"></div>
{/if} {/if}
</td> </td>
<!-- Data Columns --> <!-- Data Columns -->
{#each headers as header} {#each headers.filter(h => h !== 'alreadyPrinted') as header}
<td class="px-3 py-4 text-sm text-gray-900 max-w-xs truncate"> <td class="px-3 py-4 text-sm text-gray-900 max-w-xs truncate">
{#if header === 'alreadyPrinted'}
{#if isRowAlreadyPrinted(row)}
<span class="inline-flex px-2 py-1 text-xs font-medium bg-orange-100 text-orange-800 rounded-full">
Already Printed
</span>
{:else}
<span class="inline-flex px-2 py-1 text-xs font-medium bg-gray-100 text-gray-600 rounded-full">
Not Printed
</span>
{/if}
{:else}
{row[header] || ''} {row[header] || ''}
{/if}
</td> </td>
{/each} {/each}
@@ -390,13 +420,21 @@
{/if} {/if}
<!-- Navigation --> <!-- Navigation -->
<div class="flex justify-end"> <div class="flex justify-between">
<button <button
on:click={handleContinue} onclick={() => currentStep.set(3)}
disabled={selectedValidCount === 0} class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg font-medium hover:bg-gray-300"
>
← Back to Colum Selection
</button>
<button
onclick={handleContinue}
disabled={!canProceed}
class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed" class="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
> >
{selectedValidCount > 0 ? `Continue with ${selectedValidCount} ${selectedValidCount === 1 ? 'row' : 'rows'} ` : 'Select rows to continue'} {canProceed
? `Continue with ${selectedValidCount} ${selectedValidCount === 1 ? 'row' : 'rows'} `
: 'Select rows to continue'}
</button> </button>
</div> </div>
</div> </div>