This commit is contained in:
root
2025-11-09 15:57:30 +01:00
parent 39bb145219
commit 238ae31cb3

View File

@@ -168,6 +168,174 @@ function App() {
[handleUnauthorized, normalizeAdminSettings] [handleUnauthorized, normalizeAdminSettings]
); );
const authorizedFetch = useCallback(
async (url, options = {}, tokenOverride) => {
const activeToken = tokenOverride || session?.token;
if (!activeToken) {
throw new Error('Keine aktive Session');
}
const headers = {
Authorization: `Bearer ${activeToken}`,
...(options.headers || {})
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401) {
handleUnauthorized();
throw new Error('Nicht autorisiert');
}
return response;
},
[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(() => { useEffect(() => {
let ticker; let ticker;
let cancelled = false; let cancelled = false;
@@ -219,26 +387,6 @@ function App() {
syncStoresWithProgress syncStoresWithProgress
]); ]);
const authorizedFetch = useCallback(
async (url, options = {}, tokenOverride) => {
const activeToken = tokenOverride || session?.token;
if (!activeToken) {
throw new Error('Keine aktive Session');
}
const headers = {
Authorization: `Bearer ${activeToken}`,
...(options.headers || {})
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401) {
handleUnauthorized();
throw new Error('Nicht autorisiert');
}
return response;
},
[handleUnauthorized, session?.token]
);
useEffect(() => { useEffect(() => {
if (!session?.token || !session.isAdmin) { if (!session?.token || !session.isAdmin) {
setAdminSettings(null); setAdminSettings(null);