Verbesserte
This commit is contained in:
172
src/App.js
172
src/App.js
@@ -28,6 +28,7 @@ function App() {
|
||||
const [syncProgress, setSyncProgress] = useState({ active: false, percent: 0, message: '', block: false });
|
||||
|
||||
const weekdays = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
|
||||
const delay = useCallback((ms) => new Promise((resolve) => setTimeout(resolve, ms)), []);
|
||||
|
||||
const startSyncProgress = useCallback((message, percent, block = false) => {
|
||||
setSyncProgress({ active: true, percent, message, block });
|
||||
@@ -117,7 +118,7 @@ function App() {
|
||||
const bootstrapSession = useCallback(
|
||||
async (token, { progress } = {}) => {
|
||||
if (!token) {
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
setLoading(true);
|
||||
setError('');
|
||||
@@ -153,45 +154,70 @@ function App() {
|
||||
progress?.update?.('Konfiguration wird geladen...', 75);
|
||||
setConfig(Array.isArray(configData) ? configData : []);
|
||||
progress?.update?.('Synchronisierung abgeschlossen', 95);
|
||||
return {
|
||||
storeRefreshJob: data.storeRefreshJob,
|
||||
storesFresh: data.storesFresh
|
||||
};
|
||||
} catch (err) {
|
||||
setError(`Session konnte nicht wiederhergestellt werden: ${err.message}`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
return {};
|
||||
},
|
||||
[handleUnauthorized, normalizeAdminSettings]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let ticker;
|
||||
try {
|
||||
const storedToken = localStorage.getItem(TOKEN_STORAGE_KEY);
|
||||
if (storedToken) {
|
||||
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);
|
||||
(async () => {
|
||||
try {
|
||||
await bootstrapSession(storedToken, { progress: { update: updateSyncProgress } });
|
||||
} finally {
|
||||
if (ticker) {
|
||||
clearInterval(ticker);
|
||||
}
|
||||
finishSyncProgress();
|
||||
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();
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Konnte gespeicherten Token nicht lesen:', err);
|
||||
if (ticker) {
|
||||
clearInterval(ticker);
|
||||
}
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
if (ticker) {
|
||||
clearInterval(ticker);
|
||||
}
|
||||
};
|
||||
}, [bootstrapSession, startSyncProgress, updateSyncProgress, finishSyncProgress, nudgeSyncProgress]);
|
||||
}, [
|
||||
bootstrapSession,
|
||||
startSyncProgress,
|
||||
updateSyncProgress,
|
||||
finishSyncProgress,
|
||||
nudgeSyncProgress,
|
||||
syncStoresWithProgress
|
||||
]);
|
||||
|
||||
const authorizedFetch = useCallback(
|
||||
async (url, options = {}, tokenOverride) => {
|
||||
@@ -276,8 +302,17 @@ function App() {
|
||||
}
|
||||
clearInterval(ticker);
|
||||
updateSyncProgress('Zugang bestätigt. Session wird aufgebaut...', 45);
|
||||
await bootstrapSession(data.token, { progress: { update: updateSyncProgress } });
|
||||
updateSyncProgress('Login abgeschlossen', 95);
|
||||
const bootstrapResult = await bootstrapSession(data.token, { progress: { update: updateSyncProgress } });
|
||||
const needsStoreSync = !bootstrapResult?.storesFresh || !!bootstrapResult?.storeRefreshJob;
|
||||
if (needsStoreSync) {
|
||||
await syncStoresWithProgress({
|
||||
reason: 'login-auto',
|
||||
startJob: !bootstrapResult?.storeRefreshJob,
|
||||
reuseOverlay: true,
|
||||
block: true
|
||||
});
|
||||
}
|
||||
updateSyncProgress('Login abgeschlossen', 98);
|
||||
setStatus('Anmeldung erfolgreich. Konfiguration geladen.');
|
||||
setTimeout(() => setStatus(''), 3000);
|
||||
} catch (err) {
|
||||
@@ -351,22 +386,101 @@ function App() {
|
||||
}
|
||||
}, [session?.token, authorizedFetch]);
|
||||
|
||||
const refreshStoresAndConfig = useCallback(
|
||||
async ({ block = false } = {}) => {
|
||||
const syncStoresWithProgress = useCallback(
|
||||
async ({ block = false, reason = 'manual', startJob = true, reuseOverlay = false } = {}) => {
|
||||
if (!session?.token) {
|
||||
return;
|
||||
}
|
||||
startSyncProgress('Betriebe werden geprüft...', 15, block);
|
||||
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();
|
||||
updateSyncProgress('Konfiguration wird aktualisiert...', 70);
|
||||
await fetchConfig(undefined, { silent: true });
|
||||
updateSyncProgress('Synchronisierung abgeschlossen', 95);
|
||||
setStatus('Betriebe aktualisiert.');
|
||||
setTimeout(() => setStatus(''), 3000);
|
||||
} catch (err) {
|
||||
setError(`Aktualisieren der Betriebe fehlgeschlagen: ${err.message}`);
|
||||
} finally {
|
||||
finishSyncProgress();
|
||||
if (!reuseOverlay) {
|
||||
finishSyncProgress();
|
||||
}
|
||||
}
|
||||
},
|
||||
[session?.token, fetchStoresList, fetchConfig, startSyncProgress, updateSyncProgress, finishSyncProgress]
|
||||
[
|
||||
session?.token,
|
||||
authorizedFetch,
|
||||
startSyncProgress,
|
||||
updateSyncProgress,
|
||||
finishSyncProgress,
|
||||
delay,
|
||||
fetchStoresList,
|
||||
fetchConfig,
|
||||
setError,
|
||||
setStatus
|
||||
]
|
||||
);
|
||||
|
||||
const refreshStoresAndConfig = useCallback(
|
||||
({ block = false } = {}) => syncStoresWithProgress({ block, reason: 'manual', startJob: true }),
|
||||
[syncStoresWithProgress]
|
||||
);
|
||||
|
||||
const saveConfig = async () => {
|
||||
|
||||
Reference in New Issue
Block a user