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 useStoreSync from './hooks/useStoreSync';
|
||||||
import useDirtyNavigationGuard from './hooks/useDirtyNavigationGuard';
|
import useDirtyNavigationGuard from './hooks/useDirtyNavigationGuard';
|
||||||
import useSessionManager from './hooks/useSessionManager';
|
import useSessionManager from './hooks/useSessionManager';
|
||||||
|
import useAdminSettings from './hooks/useAdminSettings';
|
||||||
import NavigationTabs from './components/NavigationTabs';
|
import NavigationTabs from './components/NavigationTabs';
|
||||||
import LoginView from './components/LoginView';
|
import LoginView from './components/LoginView';
|
||||||
import DashboardView from './components/DashboardView';
|
import DashboardView from './components/DashboardView';
|
||||||
@@ -28,8 +29,6 @@ function App() {
|
|||||||
const [status, setStatus] = useState('');
|
const [status, setStatus] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [availableCollapsed, setAvailableCollapsed] = useState(true);
|
const [availableCollapsed, setAvailableCollapsed] = useState(true);
|
||||||
const [adminSettings, setAdminSettings] = useState(null);
|
|
||||||
const [adminSettingsLoading, setAdminSettingsLoading] = useState(false);
|
|
||||||
const [initializing, setInitializing] = useState(false);
|
const [initializing, setInitializing] = useState(false);
|
||||||
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
const [activeRangePicker, setActiveRangePicker] = useState(null);
|
||||||
const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
|
const [confirmDialog, setConfirmDialog] = useState({ open: false, resolve: null });
|
||||||
@@ -86,39 +85,6 @@ function App() {
|
|||||||
nudgeSyncProgress
|
nudgeSyncProgress
|
||||||
} = useSyncProgress();
|
} = 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 {
|
const {
|
||||||
session,
|
session,
|
||||||
authorizedFetch,
|
authorizedFetch,
|
||||||
@@ -129,7 +95,6 @@ function App() {
|
|||||||
getStoredToken
|
getStoredToken
|
||||||
} = useSessionManager({
|
} = useSessionManager({
|
||||||
normalizeConfigEntries,
|
normalizeConfigEntries,
|
||||||
normalizeAdminSettings,
|
|
||||||
onUnauthorized: notifyUnauthorized,
|
onUnauthorized: notifyUnauthorized,
|
||||||
setError,
|
setError,
|
||||||
setLoading
|
setLoading
|
||||||
@@ -169,6 +134,24 @@ function App() {
|
|||||||
finishSyncProgress
|
finishSyncProgress
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
adminSettings,
|
||||||
|
adminSettingsLoading,
|
||||||
|
setAdminSettingsSnapshot,
|
||||||
|
clearAdminSettings,
|
||||||
|
handleAdminSettingChange,
|
||||||
|
handleAdminNotificationChange,
|
||||||
|
handleIgnoredSlotChange,
|
||||||
|
addIgnoredSlot,
|
||||||
|
removeIgnoredSlot,
|
||||||
|
saveAdminSettings
|
||||||
|
} = useAdminSettings({
|
||||||
|
session,
|
||||||
|
authorizedFetch,
|
||||||
|
setStatus,
|
||||||
|
setError
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
requestNavigation,
|
requestNavigation,
|
||||||
dialogState: dirtyDialogState,
|
dialogState: dirtyDialogState,
|
||||||
@@ -187,11 +170,11 @@ function App() {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
setStores(Array.isArray(result.stores) ? result.stores : []);
|
setStores(Array.isArray(result.stores) ? result.stores : []);
|
||||||
setAdminSettings(result.adminSettings ?? null);
|
setAdminSettingsSnapshot(result.adminSettings ?? null);
|
||||||
setConfig(Array.isArray(result.config) ? result.config : []);
|
setConfig(Array.isArray(result.config) ? result.config : []);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
[setStores, setAdminSettings, setConfig]
|
[setStores, setAdminSettingsSnapshot, setConfig]
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetSessionState = useCallback(() => {
|
const resetSessionState = useCallback(() => {
|
||||||
@@ -199,8 +182,7 @@ function App() {
|
|||||||
setStores([]);
|
setStores([]);
|
||||||
setStatus('');
|
setStatus('');
|
||||||
setError('');
|
setError('');
|
||||||
setAdminSettings(null);
|
clearAdminSettings();
|
||||||
setAdminSettingsLoading(false);
|
|
||||||
setAvailableCollapsed(true);
|
setAvailableCollapsed(true);
|
||||||
setInitializing(false);
|
setInitializing(false);
|
||||||
}, [
|
}, [
|
||||||
@@ -208,8 +190,7 @@ function App() {
|
|||||||
setStores,
|
setStores,
|
||||||
setStatus,
|
setStatus,
|
||||||
setError,
|
setError,
|
||||||
setAdminSettings,
|
clearAdminSettings,
|
||||||
setAdminSettingsLoading,
|
|
||||||
setAvailableCollapsed,
|
setAvailableCollapsed,
|
||||||
setInitializing
|
setInitializing
|
||||||
]);
|
]);
|
||||||
@@ -237,42 +218,6 @@ function App() {
|
|||||||
sessionToken: session?.token
|
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) => {
|
const handleLogin = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -637,140 +582,6 @@ function App() {
|
|||||||
setFocusedStoreId(storeId);
|
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) {
|
if (!session?.token) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
189
src/hooks/useAdminSettings.js
Normal file
189
src/hooks/useAdminSettings.js
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { normalizeAdminSettings, serializeAdminSettings } from '../utils/adminSettings';
|
||||||
|
|
||||||
|
const useAdminSettings = ({ session, authorizedFetch, setStatus, setError }) => {
|
||||||
|
const [adminSettings, setAdminSettings] = useState(null);
|
||||||
|
const [adminSettingsLoading, setAdminSettingsLoading] = useState(false);
|
||||||
|
|
||||||
|
const clearAdminSettings = useCallback(() => {
|
||||||
|
setAdminSettings(null);
|
||||||
|
setAdminSettingsLoading(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setAdminSettingsSnapshot = useCallback((snapshot) => {
|
||||||
|
setAdminSettings(snapshot ? normalizeAdminSettings(snapshot) : null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadAdminSettings = useCallback(async () => {
|
||||||
|
if (!session?.token || !session.isAdmin) {
|
||||||
|
clearAdminSettings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAdminSettingsLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await authorizedFetch('/api/admin/settings');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
setAdminSettings(normalizeAdminSettings(data));
|
||||||
|
} catch (err) {
|
||||||
|
setError(`Admin-Einstellungen konnten nicht geladen werden: ${err.message}`);
|
||||||
|
} finally {
|
||||||
|
setAdminSettingsLoading(false);
|
||||||
|
}
|
||||||
|
}, [session?.token, session?.isAdmin, authorizedFetch, setError, clearAdminSettings]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!session?.token || !session.isAdmin) {
|
||||||
|
clearAdminSettings();
|
||||||
|
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, setError, clearAdminSettings]);
|
||||||
|
|
||||||
|
const handleAdminSettingChange = useCallback((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 = useCallback((channel, field, value) => {
|
||||||
|
setAdminSettings((prev) => {
|
||||||
|
if (!prev) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
notifications: {
|
||||||
|
...(prev.notifications || {}),
|
||||||
|
[channel]: {
|
||||||
|
...(prev.notifications?.[channel] || {}),
|
||||||
|
[field]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleIgnoredSlotChange = useCallback((index, field, value) => {
|
||||||
|
setAdminSettings((prev) => {
|
||||||
|
if (!prev) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const slots = [...(prev.ignoredSlots || [])];
|
||||||
|
slots[index] = {
|
||||||
|
...slots[index],
|
||||||
|
[field]: value
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
ignoredSlots: slots
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addIgnoredSlot = useCallback(() => {
|
||||||
|
setAdminSettings((prev) => {
|
||||||
|
if (!prev) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
ignoredSlots: [...(prev.ignoredSlots || []), { storeId: '', description: '' }]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const removeIgnoredSlot = useCallback((index) => {
|
||||||
|
setAdminSettings((prev) => {
|
||||||
|
if (!prev) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const slots = [...(prev.ignoredSlots || [])];
|
||||||
|
slots.splice(index, 1);
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
ignoredSlots: slots
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const saveAdminSettings = useCallback(async () => {
|
||||||
|
if (!session?.token || !session.isAdmin || !adminSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setStatus('Admin-Einstellungen werden gespeichert...');
|
||||||
|
setError('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const payload = serializeAdminSettings(adminSettings);
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
}, [session?.token, session?.isAdmin, adminSettings, authorizedFetch, setStatus, setError]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
adminSettings,
|
||||||
|
adminSettingsLoading,
|
||||||
|
setAdminSettingsSnapshot,
|
||||||
|
clearAdminSettings,
|
||||||
|
handleAdminSettingChange,
|
||||||
|
handleAdminNotificationChange,
|
||||||
|
handleIgnoredSlotChange,
|
||||||
|
addIgnoredSlot,
|
||||||
|
removeIgnoredSlot,
|
||||||
|
saveAdminSettings,
|
||||||
|
loadAdminSettings
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useAdminSettings;
|
||||||
@@ -1,14 +1,9 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { normalizeAdminSettings } from '../utils/adminSettings';
|
||||||
|
|
||||||
const TOKEN_STORAGE_KEY = 'pickupConfigToken';
|
const TOKEN_STORAGE_KEY = 'pickupConfigToken';
|
||||||
|
|
||||||
const useSessionManager = ({
|
const useSessionManager = ({ normalizeConfigEntries, onUnauthorized, setError, setLoading }) => {
|
||||||
normalizeConfigEntries,
|
|
||||||
normalizeAdminSettings,
|
|
||||||
onUnauthorized,
|
|
||||||
setError,
|
|
||||||
setLoading
|
|
||||||
}) => {
|
|
||||||
const [session, setSession] = useState(null);
|
const [session, setSession] = useState(null);
|
||||||
const unauthorizedRef = useRef(onUnauthorized || (() => {}));
|
const unauthorizedRef = useRef(onUnauthorized || (() => {}));
|
||||||
|
|
||||||
@@ -127,7 +122,7 @@ const useSessionManager = ({
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[normalizeAdminSettings, normalizeConfigEntries, handleUnauthorized, setError, setLoading]
|
[normalizeConfigEntries, handleUnauthorized, setError, setLoading]
|
||||||
);
|
);
|
||||||
|
|
||||||
const performLogout = useCallback(async () => {
|
const performLogout = useCallback(async () => {
|
||||||
|
|||||||
71
src/utils/adminSettings.js
Normal file
71
src/utils/adminSettings.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
export const normalizeAdminSettings = (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 toNumberOrUndefined = (value) => {
|
||||||
|
if (value === '' || value === null || value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
return Number.isFinite(parsed) ? parsed : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const serializeAdminSettings = (adminSettings) => {
|
||||||
|
if (!adminSettings) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
scheduleCron: adminSettings.scheduleCron,
|
||||||
|
randomDelayMinSeconds: toNumberOrUndefined(adminSettings.randomDelayMinSeconds),
|
||||||
|
randomDelayMaxSeconds: toNumberOrUndefined(adminSettings.randomDelayMaxSeconds),
|
||||||
|
initialDelayMinSeconds: toNumberOrUndefined(adminSettings.initialDelayMinSeconds),
|
||||||
|
initialDelayMaxSeconds: toNumberOrUndefined(adminSettings.initialDelayMaxSeconds),
|
||||||
|
storePickupCheckDelayMs: toNumberOrUndefined(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 || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user