feat: persist edits to Supabase database

This commit is contained in:
christian.vidal
2026-03-27 12:23:35 +01:00
parent a5ac3ba359
commit f43d8f367e
2 changed files with 100 additions and 3 deletions
+31 -3
View File
@@ -8,6 +8,7 @@ import { DataCompleteness } from './components/DataCompleteness';
import { MatrixView } from './components/MatrixView';
import { UploadReload } from './components/UploadReload';
import { EditPanel } from './components/EditPanel';
import { getAllSyncedRows, saveRowToSupabase } from './lib/supabase';
export default function App() {
const [appState, setAppState] = useState<AppState>({
@@ -60,9 +61,22 @@ export default function App() {
const data = XLSX.utils.sheet_to_json<any[]>(ws, { header: 1 });
if (data.length > 0) {
const rawHeaders = data[0];
const rawRows = data.slice(1);
// Apply Supabase overrides
console.log("Applying Supabase overrides...");
const syncedData = await getAllSyncedRows();
const articleNoIdx = COLUMNS.ARTICLE_NO;
const processedRows = rawRows.map(row => {
const articleNo = String(row[articleNoIdx]);
return syncedData[articleNo] || row;
});
setAppState({
headers: data[0],
data: data.slice(1),
headers: rawHeaders,
data: processedRows,
fileName: 'Data-Matrix.xlsx (Cloud Sync)',
fileDate: new Date(),
hasUnsavedChanges: false
@@ -132,7 +146,8 @@ export default function App() {
setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
};
const handleSaveRow = (rowIndex: number, updatedRow: ExcelRow) => {
const handleSaveRow = async (rowIndex: number, updatedRow: ExcelRow) => {
// 1. Update UI state
setAppState(prev => {
const newData = [...prev.data];
newData[rowIndex] = updatedRow;
@@ -143,6 +158,19 @@ export default function App() {
};
});
setEditingRowIndex(null);
// 2. Persist to Supabase
const articleNo = String(updatedRow[COLUMNS.ARTICLE_NO]);
console.log(`Saving article ${articleNo} to Supabase...`);
const success = await saveRowToSupabase(articleNo, updatedRow);
if (success) {
console.log(`Successfully saved ${articleNo}`);
setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
} else {
console.error(`Failed to save ${articleNo} to Supabase`);
alert("Error saving to database. Local changes will be lost on refresh if not saved.");
}
};
const stats = useMemo(() => {
+69
View File
@@ -0,0 +1,69 @@
import { ExcelRow } from '../types';
const SUPABASE_URL = 'https://hwithddwaapyhnfwcesj.supabase.co';
const SUPABASE_KEY = 'sb_publishable_fGXkh0bSrAOqSk2jWKAzSg_NJD9YPCv';
export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow) {
try {
const response = await fetch(`${SUPABASE_URL}/rest/v1/products_sync?id=eq.${encodeURIComponent(articleNo)}`, {
method: 'PATCH',
headers: {
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`,
'Content-Type': 'application/json',
'Prefer': 'resolution=merge-duplicates'
},
body: JSON.stringify({
id: articleNo,
data: rowData,
updated_at: new Date().toISOString()
})
});
if (response.status === 204 || response.ok) {
// If PATCH didn't find the record, try UPSERT
const upsertResponse = await fetch(`${SUPABASE_URL}/rest/v1/products_sync`, {
method: 'POST',
headers: {
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`,
'Content-Type': 'application/json',
'Prefer': 'resolution=merge-duplicates'
},
body: JSON.stringify({
id: articleNo,
data: rowData,
updated_at: new Date().toISOString()
})
});
return upsertResponse.ok;
}
return true;
} catch (error) {
console.error('Error saving to Supabase:', error);
return false;
}
}
export async function getAllSyncedRows(): Promise<Record<string, ExcelRow>> {
try {
const response = await fetch(`${SUPABASE_URL}/rest/v1/products_sync`, {
headers: {
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`
}
});
if (!response.ok) return {};
const data = await response.json();
const result: Record<string, ExcelRow> = {};
data.forEach((item: any) => {
result[item.id] = item.data;
});
return result;
} catch (error) {
console.error('Error fetching from Supabase:', error);
return {};
}
}