mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 13:05:25 +02:00
Fix save changes looping issue and authorize all Supabase API calls
This commit is contained in:
+41
-20
@@ -111,7 +111,7 @@ export default function App() {
|
||||
}
|
||||
|
||||
console.log('Fetching synced data from Supabase...');
|
||||
const syncedData = await getAllSyncedRows();
|
||||
const syncedData = await getAllSyncedRows(session?.access_token);
|
||||
|
||||
const articleNoIdx = COLUMNS.ARTICLE_NO;
|
||||
const processedRows = rows.map(row => {
|
||||
@@ -267,7 +267,7 @@ export default function App() {
|
||||
|
||||
// 3. Post-export: Reset pending statuses in Supabase
|
||||
console.log('Resetting pending statuses in Supabase...');
|
||||
resetAllPendingRows().then(success => {
|
||||
resetAllPendingRows(session?.access_token).then(success => {
|
||||
if (success) {
|
||||
console.log('Successfully reset all pending statuses');
|
||||
setRowStatuses({}); // Clear local statuses
|
||||
@@ -319,27 +319,47 @@ export default function App() {
|
||||
console.log('[handleSaveAll] No entries to save, returning');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSavingAll(true);
|
||||
let allSuccess = true;
|
||||
for (const [articleNo, { newData, originalData, articleName }] of entries) {
|
||||
console.log('[handleSaveAll] Saving article:', articleNo);
|
||||
const success = await saveRowToSupabase(articleNo, newData);
|
||||
console.log('[handleSaveAll] Save result for', articleNo, ':', success);
|
||||
if (success) {
|
||||
// Also save to history
|
||||
await saveHistoryEntry(articleNo, articleName, originalData, newData, session?.user?.email || 'unknown');
|
||||
let failedArticles: string[] = [];
|
||||
const token = session?.access_token;
|
||||
|
||||
try {
|
||||
for (const [articleNo, { newData, originalData, articleName }] of entries) {
|
||||
console.log('[handleSaveAll] Saving article:', articleNo);
|
||||
const success = await saveRowToSupabase(articleNo, newData, token);
|
||||
console.log('[handleSaveAll] Save result for', articleNo, ':', success);
|
||||
|
||||
setRowStatuses(prev => ({ ...prev, [articleNo]: 'saved' }));
|
||||
setPendingRows(prev => { const n = { ...prev }; delete n[articleNo]; return n; });
|
||||
} else {
|
||||
setRowStatuses(prev => ({ ...prev, [articleNo]: 'error' }));
|
||||
allSuccess = false;
|
||||
if (success) {
|
||||
// Also save to history
|
||||
await saveHistoryEntry(articleNo, articleName, originalData, newData, session?.user?.email || 'unknown', token);
|
||||
|
||||
setRowStatuses(prev => ({ ...prev, [articleNo]: 'saved' }));
|
||||
setPendingRows(prev => {
|
||||
const n = { ...prev };
|
||||
delete n[articleNo];
|
||||
return n;
|
||||
});
|
||||
} else {
|
||||
setRowStatuses(prev => ({ ...prev, [articleNo]: 'error' }));
|
||||
failedArticles.push(articleNo);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[handleSaveAll] Finished loop. Failed:', failedArticles.length);
|
||||
|
||||
if (failedArticles.length > 0) {
|
||||
alert(`Failed to save ${failedArticles.length} items: ${failedArticles.join(', ')}. Please try again.`);
|
||||
} else {
|
||||
setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[handleSaveAll] Critical error:', err);
|
||||
alert('A critical error occurred while saving. Please check your connection and try again.');
|
||||
} finally {
|
||||
setIsSavingAll(false);
|
||||
console.log('[handleSaveAll] isSavingAll set to false');
|
||||
}
|
||||
console.log('[handleSaveAll] Finished, allSuccess:', allSuccess);
|
||||
if (allSuccess) setAppState(prev => ({ ...prev, hasUnsavedChanges: false }));
|
||||
setIsSavingAll(false);
|
||||
console.log('[handleSaveAll] isSavingAll set to false');
|
||||
};
|
||||
|
||||
const captureState = (message: string) => {
|
||||
@@ -506,6 +526,7 @@ export default function App() {
|
||||
<HistoryView
|
||||
headers={appState.headers}
|
||||
data={appState.data}
|
||||
sessionToken={session?.access_token}
|
||||
onRevert={async (articleNo, revertedData, historyId) => {
|
||||
// Find the row in appState.data and update it
|
||||
const rowIndex = appState.data.findIndex(r => String(r[COLUMNS.ARTICLE_NO]) === articleNo);
|
||||
@@ -528,7 +549,7 @@ export default function App() {
|
||||
}));
|
||||
// Delete the history entry after revert
|
||||
if (historyId) {
|
||||
await deleteHistoryEntry(String(historyId));
|
||||
await deleteHistoryEntry(String(historyId), session?.access_token);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -8,9 +8,10 @@ interface HistoryViewProps {
|
||||
headers: string[];
|
||||
data: ExcelRow[];
|
||||
onRevert: (articleNo: string, oldData: ExcelRow, historyId?: number) => void;
|
||||
sessionToken?: string;
|
||||
}
|
||||
|
||||
export function HistoryView({ headers, data, onRevert }: HistoryViewProps) {
|
||||
export function HistoryView({ headers, data, onRevert, sessionToken }: HistoryViewProps) {
|
||||
const [history, setHistory] = useState<HistoryEntry[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||
@@ -22,7 +23,7 @@ export function HistoryView({ headers, data, onRevert }: HistoryViewProps) {
|
||||
|
||||
const loadHistory = async () => {
|
||||
setLoading(true);
|
||||
const data = await getHistory();
|
||||
const data = await getHistory(sessionToken);
|
||||
setHistory(data);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
+13
-12
@@ -8,14 +8,14 @@ export interface SyncedRow {
|
||||
status?: 'pending' | 'synced';
|
||||
}
|
||||
|
||||
export async function getAllSyncedRows(): Promise<Record<string, SyncedRow>> {
|
||||
export async function getAllSyncedRows(token?: string): Promise<Record<string, SyncedRow>> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${SUPABASE_URL}/rest/v1/products?select=product_id,data,status&order=updated_at.desc`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -33,7 +33,7 @@ export async function getAllSyncedRows(): Promise<Record<string, SyncedRow>> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow): Promise<boolean> {
|
||||
export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow, token?: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${SUPABASE_URL}/rest/v1/products`,
|
||||
@@ -42,7 +42,7 @@ export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow): P
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`,
|
||||
'Prefer': 'resolution=merge-duplicates'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
@@ -76,7 +76,8 @@ export async function saveHistoryEntry(
|
||||
articleName: string,
|
||||
oldData: ExcelRow,
|
||||
newData: ExcelRow,
|
||||
changedBy: string
|
||||
changedBy: string,
|
||||
token?: string
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
@@ -86,7 +87,7 @@ export async function saveHistoryEntry(
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`,
|
||||
'Prefer': 'return=minimal'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
@@ -107,14 +108,14 @@ export async function saveHistoryEntry(
|
||||
}
|
||||
}
|
||||
|
||||
export async function getHistory(): Promise<HistoryEntry[]> {
|
||||
export async function getHistory(token?: string): Promise<HistoryEntry[]> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${SUPABASE_URL}/rest/v1/products_history?select=*&order=changed_at.desc&limit=100`,
|
||||
{
|
||||
headers: {
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -127,7 +128,7 @@ export async function getHistory(): Promise<HistoryEntry[]> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteHistoryEntry(id: string): Promise<boolean> {
|
||||
export async function deleteHistoryEntry(id: string, token?: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${SUPABASE_URL}/rest/v1/products_history?id=eq.${encodeURIComponent(id)}`,
|
||||
@@ -135,7 +136,7 @@ export async function deleteHistoryEntry(id: string): Promise<boolean> {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -147,7 +148,7 @@ export async function deleteHistoryEntry(id: string): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function resetAllPendingRows(): Promise<boolean> {
|
||||
export async function resetAllPendingRows(token?: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${SUPABASE_URL}/rest/v1/products?status=eq.pending`,
|
||||
@@ -156,7 +157,7 @@ export async function resetAllPendingRows(): Promise<boolean> {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': SUPABASE_KEY,
|
||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
||||
'Authorization': `Bearer ${token || SUPABASE_KEY}`,
|
||||
'Prefer': 'return=minimal'
|
||||
},
|
||||
body: JSON.stringify({ status: 'synced' })
|
||||
|
||||
Reference in New Issue
Block a user