refactoring

This commit is contained in:
2025-11-10 13:43:13 +01:00
parent ea95188dd7
commit 7b3625ae3b
4 changed files with 286 additions and 220 deletions

View File

@@ -11,6 +11,7 @@ import useConfigManager from './hooks/useConfigManager';
import useStoreSync from './hooks/useStoreSync';
import useDirtyNavigationGuard from './hooks/useDirtyNavigationGuard';
import useSessionManager from './hooks/useSessionManager';
import useAdminSettings from './hooks/useAdminSettings';
import NavigationTabs from './components/NavigationTabs';
import LoginView from './components/LoginView';
import DashboardView from './components/DashboardView';
@@ -28,8 +29,6 @@ function App() {
const [status, setStatus] = useState('');
const [error, setError] = useState('');
const [availableCollapsed, setAvailableCollapsed] = useState(true);
const [adminSettings, setAdminSettings] = useState(null);
const [adminSettingsLoading, setAdminSettingsLoading] = useState(false);
const [initializing, setInitializing] = useState(false);
const [activeRangePicker, setActiveRangePicker] = useState(null);
const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
@@ -86,39 +85,6 @@ function App() {
nudgeSyncProgress
} = useSyncProgress();
const normalizeAdminSettings = useCallback((raw) => {
if (!raw) {
return null;
}
return {
scheduleCron: raw.scheduleCron || '',
randomDelayMinSeconds: raw.randomDelayMinSeconds ?? '',
randomDelayMaxSeconds: raw.randomDelayMaxSeconds ?? '',
initialDelayMinSeconds: raw.initialDelayMinSeconds ?? '',
initialDelayMaxSeconds: raw.initialDelayMaxSeconds ?? '',
storePickupCheckDelayMs: raw.storePickupCheckDelayMs ?? '',
ignoredSlots: Array.isArray(raw.ignoredSlots)
? raw.ignoredSlots.map((slot) => ({
storeId: slot?.storeId ? String(slot.storeId) : '',
description: slot?.description || ''
}))
: [],
notifications: {
ntfy: {
enabled: !!raw.notifications?.ntfy?.enabled,
serverUrl: raw.notifications?.ntfy?.serverUrl || 'https://ntfy.sh',
topicPrefix: raw.notifications?.ntfy?.topicPrefix || '',
username: raw.notifications?.ntfy?.username || '',
password: raw.notifications?.ntfy?.password || ''
},
telegram: {
enabled: !!raw.notifications?.telegram?.enabled,
botToken: raw.notifications?.telegram?.botToken || ''
}
}
};
}, []);
const {
session,
authorizedFetch,
@@ -129,7 +95,6 @@ function App() {
getStoredToken
} = useSessionManager({
normalizeConfigEntries,
normalizeAdminSettings,
onUnauthorized: notifyUnauthorized,
setError,
setLoading
@@ -169,6 +134,24 @@ function App() {
finishSyncProgress
});
const {
adminSettings,
adminSettingsLoading,
setAdminSettingsSnapshot,
clearAdminSettings,
handleAdminSettingChange,
handleAdminNotificationChange,
handleIgnoredSlotChange,
addIgnoredSlot,
removeIgnoredSlot,
saveAdminSettings
} = useAdminSettings({
session,
authorizedFetch,
setStatus,
setError
});
const {
requestNavigation,
dialogState: dirtyDialogState,
@@ -187,11 +170,11 @@ function App() {
return {};
}
setStores(Array.isArray(result.stores) ? result.stores : []);
setAdminSettings(result.adminSettings ?? null);
setAdminSettingsSnapshot(result.adminSettings ?? null);
setConfig(Array.isArray(result.config) ? result.config : []);
return result;
},
[setStores, setAdminSettings, setConfig]
[setStores, setAdminSettingsSnapshot, setConfig]
);
const resetSessionState = useCallback(() => {
@@ -199,8 +182,7 @@ function App() {
setStores([]);
setStatus('');
setError('');
setAdminSettings(null);
setAdminSettingsLoading(false);
clearAdminSettings();
setAvailableCollapsed(true);
setInitializing(false);
}, [
@@ -208,8 +190,7 @@ function App() {
setStores,
setStatus,
setError,
setAdminSettings,
setAdminSettingsLoading,
clearAdminSettings,
setAvailableCollapsed,
setInitializing
]);
@@ -237,42 +218,6 @@ function App() {
sessionToken: session?.token
});
useEffect(() => {
if (!session?.token || !session.isAdmin) {
setAdminSettings(null);
setAdminSettingsLoading(false);
return;
}
let cancelled = false;
setAdminSettingsLoading(true);
(async () => {
try {
const response = await authorizedFetch('/api/admin/settings');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
if (!cancelled) {
setAdminSettings(normalizeAdminSettings(data));
}
} catch (err) {
if (!cancelled) {
setError(`Admin-Einstellungen konnten nicht geladen werden: ${err.message}`);
}
} finally {
if (!cancelled) {
setAdminSettingsLoading(false);
}
}
})();
return () => {
cancelled = true;
};
}, [session?.token, session?.isAdmin, authorizedFetch, normalizeAdminSettings]);
const handleLogin = async (event) => {
event.preventDefault();
setLoading(true);
@@ -637,140 +582,6 @@ function App() {
setFocusedStoreId(storeId);
};
const handleAdminSettingChange = (field, value, isNumber = false) => {
setAdminSettings((prev) => {
if (!prev) {
return prev;
}
let nextValue = value;
if (isNumber) {
nextValue = value === '' ? '' : Number(value);
}
return {
...prev,
[field]: nextValue
};
});
};
const handleAdminNotificationChange = (channel, field, value) => {
setAdminSettings((prev) => {
if (!prev) {
return prev;
}
return {
...prev,
notifications: {
...(prev.notifications || {}),
[channel]: {
...(prev.notifications?.[channel] || {}),
[field]: value
}
}
};
});
};
const handleIgnoredSlotChange = (index, field, value) => {
setAdminSettings((prev) => {
if (!prev) {
return prev;
}
const slots = [...(prev.ignoredSlots || [])];
slots[index] = {
...slots[index],
[field]: field === 'storeId' ? value : value
};
return {
...prev,
ignoredSlots: slots
};
});
};
const addIgnoredSlot = () => {
setAdminSettings((prev) => {
if (!prev) {
return prev;
}
return {
...prev,
ignoredSlots: [...(prev.ignoredSlots || []), { storeId: '', description: '' }]
};
});
};
const removeIgnoredSlot = (index) => {
setAdminSettings((prev) => {
if (!prev) {
return prev;
}
const slots = [...(prev.ignoredSlots || [])];
slots.splice(index, 1);
return {
...prev,
ignoredSlots: slots
};
});
};
const saveAdminSettings = async () => {
if (!session?.token || !session.isAdmin || !adminSettings) {
return;
}
setStatus('Admin-Einstellungen werden gespeichert...');
setError('');
const toNumber = (value) => {
if (value === '' || value === null || value === undefined) {
return undefined;
}
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : undefined;
};
try {
const payload = {
scheduleCron: adminSettings.scheduleCron,
randomDelayMinSeconds: toNumber(adminSettings.randomDelayMinSeconds),
randomDelayMaxSeconds: toNumber(adminSettings.randomDelayMaxSeconds),
initialDelayMinSeconds: toNumber(adminSettings.initialDelayMinSeconds),
initialDelayMaxSeconds: toNumber(adminSettings.initialDelayMaxSeconds),
storePickupCheckDelayMs: toNumber(adminSettings.storePickupCheckDelayMs),
ignoredSlots: (adminSettings.ignoredSlots || []).map((slot) => ({
storeId: slot.storeId || '',
description: slot.description || ''
})),
notifications: {
ntfy: {
enabled: !!adminSettings.notifications?.ntfy?.enabled,
serverUrl: adminSettings.notifications?.ntfy?.serverUrl || '',
topicPrefix: adminSettings.notifications?.ntfy?.topicPrefix || '',
username: adminSettings.notifications?.ntfy?.username || '',
password: adminSettings.notifications?.ntfy?.password || ''
},
telegram: {
enabled: !!adminSettings.notifications?.telegram?.enabled,
botToken: adminSettings.notifications?.telegram?.botToken || ''
}
}
};
const response = await authorizedFetch('/api/admin/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
setAdminSettings(normalizeAdminSettings(data));
setStatus('Admin-Einstellungen gespeichert.');
setTimeout(() => setStatus(''), 3000);
} catch (err) {
setError(`Speichern der Admin-Einstellungen fehlgeschlagen: ${err.message}`);
}
};
if (!session?.token) {
return (
<>