refactoring
This commit is contained in:
235
src/App.js
235
src/App.js
@@ -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 (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user