fix:
This commit is contained in:
250
src/App.js
250
src/App.js
@@ -188,205 +188,6 @@ function App() {
|
|||||||
[handleUnauthorized, session?.token]
|
[handleUnauthorized, session?.token]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchConfig = useCallback(
|
|
||||||
async (tokenOverride, { silent = false } = {}) => {
|
|
||||||
const tokenToUse = tokenOverride || session?.token;
|
|
||||||
if (!tokenToUse) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!silent) {
|
|
||||||
setStatus('');
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
setError('');
|
|
||||||
try {
|
|
||||||
const response = await authorizedFetch('/api/config', {}, tokenToUse);
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
setConfig(Array.isArray(data) ? data : []);
|
|
||||||
if (!silent) {
|
|
||||||
setStatus('Konfiguration aktualisiert.');
|
|
||||||
setTimeout(() => setStatus(''), 3000);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
setError(`Fehler beim Laden der Konfiguration: ${err.message}`);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[session?.token, authorizedFetch]
|
|
||||||
);
|
|
||||||
|
|
||||||
const fetchStoresList = useCallback(async () => {
|
|
||||||
if (!session?.token) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setStatus('');
|
|
||||||
setError('');
|
|
||||||
try {
|
|
||||||
const response = await authorizedFetch('/api/stores');
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
setStores(Array.isArray(data) ? data : []);
|
|
||||||
setStatus('Betriebe aktualisiert.');
|
|
||||||
setTimeout(() => setStatus(''), 3000);
|
|
||||||
} catch (err) {
|
|
||||||
setError(`Fehler beim Laden der Betriebe: ${err.message}`);
|
|
||||||
}
|
|
||||||
}, [session?.token, authorizedFetch]);
|
|
||||||
|
|
||||||
const syncStoresWithProgress = useCallback(
|
|
||||||
async ({ block = false, reason = 'manual', startJob = true, reuseOverlay = false } = {}) => {
|
|
||||||
if (!session?.token) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!reuseOverlay) {
|
|
||||||
startSyncProgress('Betriebe werden geprüft...', 5, block);
|
|
||||||
} else {
|
|
||||||
updateSyncProgress('Betriebe werden geprüft...', 35);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let jobStarted = false;
|
|
||||||
const triggerRefresh = async () => {
|
|
||||||
const response = await authorizedFetch('/api/stores/refresh', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ force: true, reason })
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP ${response.status}`);
|
|
||||||
}
|
|
||||||
await response.json();
|
|
||||||
jobStarted = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (startJob) {
|
|
||||||
await triggerRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
let completed = false;
|
|
||||||
while (!completed) {
|
|
||||||
const statusResp = await authorizedFetch('/api/stores/refresh/status');
|
|
||||||
if (!statusResp.ok) {
|
|
||||||
throw new Error(`HTTP ${statusResp.status}`);
|
|
||||||
}
|
|
||||||
const statusData = await statusResp.json();
|
|
||||||
const job = statusData.job;
|
|
||||||
if (job?.status === 'running') {
|
|
||||||
const total = job.total || 0;
|
|
||||||
const processed = job.processed || 0;
|
|
||||||
const percent = total > 0 ? Math.min(95, 10 + Math.round((processed / total) * 80)) : undefined;
|
|
||||||
const message = job.currentStore
|
|
||||||
? `Prüfe ${job.currentStore} (${processed}/${total || '?'})`
|
|
||||||
: 'Betriebe werden geprüft...';
|
|
||||||
updateSyncProgress(message, percent);
|
|
||||||
} else if (!job) {
|
|
||||||
if (statusData.storesFresh) {
|
|
||||||
updateSyncProgress('Betriebe aktuell.', 90);
|
|
||||||
completed = true;
|
|
||||||
} else if (!jobStarted) {
|
|
||||||
await triggerRefresh();
|
|
||||||
await delay(500);
|
|
||||||
} else {
|
|
||||||
updateSyncProgress('Warte auf Rückmeldung...', undefined);
|
|
||||||
}
|
|
||||||
} else if (job.status === 'done') {
|
|
||||||
updateSyncProgress('Synchronisierung abgeschlossen', 95);
|
|
||||||
completed = true;
|
|
||||||
} else if (job.status === 'error') {
|
|
||||||
throw new Error(job.error || 'Unbekannter Fehler beim Prüfen der Betriebe.');
|
|
||||||
}
|
|
||||||
if (!completed) {
|
|
||||||
await delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchStoresList();
|
|
||||||
await fetchConfig(undefined, { silent: true });
|
|
||||||
setStatus('Betriebe aktualisiert.');
|
|
||||||
setTimeout(() => setStatus(''), 3000);
|
|
||||||
} catch (err) {
|
|
||||||
setError(`Aktualisieren der Betriebe fehlgeschlagen: ${err.message}`);
|
|
||||||
} finally {
|
|
||||||
if (!reuseOverlay) {
|
|
||||||
finishSyncProgress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
session?.token,
|
|
||||||
authorizedFetch,
|
|
||||||
startSyncProgress,
|
|
||||||
updateSyncProgress,
|
|
||||||
finishSyncProgress,
|
|
||||||
delay,
|
|
||||||
fetchStoresList,
|
|
||||||
fetchConfig,
|
|
||||||
setError,
|
|
||||||
setStatus
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
const refreshStoresAndConfig = useCallback(
|
|
||||||
({ block = false } = {}) => syncStoresWithProgress({ block, reason: 'manual', startJob: true }),
|
|
||||||
[syncStoresWithProgress]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let ticker;
|
|
||||||
let cancelled = false;
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
const storedToken = localStorage.getItem(TOKEN_STORAGE_KEY);
|
|
||||||
if (!storedToken) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
startSyncProgress('Session wird wiederhergestellt...', 5, true);
|
|
||||||
ticker = setInterval(() => nudgeSyncProgress('Session wird wiederhergestellt...', 1, 40), 1000);
|
|
||||||
const result = await bootstrapSession(storedToken, { progress: { update: updateSyncProgress } });
|
|
||||||
if (ticker) {
|
|
||||||
clearInterval(ticker);
|
|
||||||
ticker = null;
|
|
||||||
}
|
|
||||||
if (!cancelled) {
|
|
||||||
const needsStoreSync = !result?.storesFresh || !!result?.storeRefreshJob;
|
|
||||||
if (needsStoreSync) {
|
|
||||||
await syncStoresWithProgress({
|
|
||||||
reason: 'session-auto',
|
|
||||||
startJob: !result?.storeRefreshJob,
|
|
||||||
reuseOverlay: true,
|
|
||||||
block: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('Konnte gespeicherten Token nicht lesen oder wiederherstellen:', err);
|
|
||||||
} finally {
|
|
||||||
if (ticker) {
|
|
||||||
clearInterval(ticker);
|
|
||||||
}
|
|
||||||
finishSyncProgress();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
if (ticker) {
|
|
||||||
clearInterval(ticker);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
bootstrapSession,
|
|
||||||
startSyncProgress,
|
|
||||||
updateSyncProgress,
|
|
||||||
finishSyncProgress,
|
|
||||||
nudgeSyncProgress,
|
|
||||||
syncStoresWithProgress
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!session?.token || !session.isAdmin) {
|
if (!session?.token || !session.isAdmin) {
|
||||||
setAdminSettings(null);
|
setAdminSettings(null);
|
||||||
@@ -631,6 +432,57 @@ function App() {
|
|||||||
[syncStoresWithProgress]
|
[syncStoresWithProgress]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let ticker;
|
||||||
|
let cancelled = false;
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const storedToken = localStorage.getItem(TOKEN_STORAGE_KEY);
|
||||||
|
if (!storedToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startSyncProgress('Session wird wiederhergestellt...', 5, true);
|
||||||
|
ticker = setInterval(() => nudgeSyncProgress('Session wird wiederhergestellt...', 1, 40), 1000);
|
||||||
|
const result = await bootstrapSession(storedToken, { progress: { update: updateSyncProgress } });
|
||||||
|
if (ticker) {
|
||||||
|
clearInterval(ticker);
|
||||||
|
ticker = null;
|
||||||
|
}
|
||||||
|
if (!cancelled) {
|
||||||
|
const needsStoreSync = !result?.storesFresh || !!result?.storeRefreshJob;
|
||||||
|
if (needsStoreSync) {
|
||||||
|
await syncStoresWithProgress({
|
||||||
|
reason: 'session-auto',
|
||||||
|
startJob: !result?.storeRefreshJob,
|
||||||
|
reuseOverlay: true,
|
||||||
|
block: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Konnte gespeicherten Token nicht lesen oder wiederherstellen:', err);
|
||||||
|
} finally {
|
||||||
|
if (ticker) {
|
||||||
|
clearInterval(ticker);
|
||||||
|
}
|
||||||
|
finishSyncProgress();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
if (ticker) {
|
||||||
|
clearInterval(ticker);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
bootstrapSession,
|
||||||
|
startSyncProgress,
|
||||||
|
updateSyncProgress,
|
||||||
|
finishSyncProgress,
|
||||||
|
nudgeSyncProgress,
|
||||||
|
syncStoresWithProgress
|
||||||
|
]);
|
||||||
|
|
||||||
const saveConfig = async () => {
|
const saveConfig = async () => {
|
||||||
if (!session?.token) {
|
if (!session?.token) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user