diff --git a/src/App.js b/src/App.js
index d7998d5..0bc452b 100644
--- a/src/App.js
+++ b/src/App.js
@@ -92,7 +92,6 @@ function App() {
authorizedFetch,
bootstrapSession,
performLogout,
- handleUnauthorized,
storeToken,
getStoredToken
} = useSessionManager({
@@ -456,31 +455,34 @@ function App() {
}
};
- const handleDateRangeSelection = useCallback((entryId, startDate, endDate) => {
- setIsDirty(true);
- setConfig((prev) =>
- prev.map((item) => {
- if (item.id !== entryId) {
- return item;
- }
- const updated = { ...item };
- const startValue = formatDateValue(startDate);
- const endValue = formatDateValue(endDate);
- if (startValue || endValue) {
- updated.desiredDateRange = {
- start: startValue || endValue,
- end: endValue || startValue
- };
- } else if (updated.desiredDateRange) {
- delete updated.desiredDateRange;
- }
- if (updated.desiredDate) {
- delete updated.desiredDate;
- }
- return updated;
- })
- );
- }, [setConfig]);
+ const handleDateRangeSelection = useCallback(
+ (entryId, startDate, endDate) => {
+ setIsDirty(true);
+ setConfig((prev) =>
+ prev.map((item) => {
+ if (item.id !== entryId) {
+ return item;
+ }
+ const updated = { ...item };
+ const startValue = formatDateValue(startDate);
+ const endValue = formatDateValue(endDate);
+ if (startValue || endValue) {
+ updated.desiredDateRange = {
+ start: startValue || endValue,
+ end: endValue || startValue
+ };
+ } else if (updated.desiredDateRange) {
+ delete updated.desiredDateRange;
+ }
+ if (updated.desiredDate) {
+ delete updated.desiredDate;
+ }
+ return updated;
+ })
+ );
+ },
+ [setConfig, setIsDirty]
+ );
const configMap = useMemo(() => {
const map = new Map();
diff --git a/src/components/DashboardView.js b/src/components/DashboardView.js
index 0dbfb42..7a2963f 100644
--- a/src/components/DashboardView.js
+++ b/src/components/DashboardView.js
@@ -16,14 +16,144 @@ const ColumnTextFilter = ({ column, placeholder }) => {
if (!column.getCanFilter()) {
return null;
}
- const configTableData = useMemo(() => {
- return Array.isArray(visibleConfig)
- ? visibleConfig.map((item) => ({
- ...item,
- normalizedLabel: (item.label || '').toLowerCase()
- }))
- : [];
- }, [visibleConfig]);
+ return (
+ column.setFilterValue(event.target.value || undefined)}
+ placeholder={placeholder}
+ className="mt-1 w-full rounded border px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-blue-500"
+ />
+ );
+};
+
+const ColumnSelectFilter = ({ column, options, placeholder = 'Alle' }) => {
+ if (!column.getCanFilter()) {
+ return null;
+ }
+ return (
+
+ );
+};
+
+function readConfigTableState() {
+ if (typeof window === 'undefined') {
+ return { sorting: [], columnFilters: [] };
+ }
+ try {
+ const raw = window.localStorage.getItem(CONFIG_TABLE_STATE_KEY);
+ if (!raw) {
+ return { sorting: [], columnFilters: [] };
+ }
+ const parsed = JSON.parse(raw);
+ return {
+ sorting: Array.isArray(parsed.sorting) ? parsed.sorting : [],
+ columnFilters: Array.isArray(parsed.columnFilters) ? parsed.columnFilters : []
+ };
+ } catch {
+ return { sorting: [], columnFilters: [] };
+ }
+}
+
+function persistConfigTableState(state) {
+ if (typeof window === 'undefined') {
+ return;
+ }
+ try {
+ window.localStorage.setItem(CONFIG_TABLE_STATE_KEY, JSON.stringify(state));
+ } catch {
+ /* ignore */
+ }
+}
+
+const DashboardView = ({
+ session,
+ onRefresh,
+ onLogout,
+ notificationPanelOpen,
+ onToggleNotificationPanel,
+ notificationProps,
+ stores,
+ availableCollapsed,
+ onToggleStores,
+ onStoreSelect,
+ configMap,
+ error,
+ onDismissError,
+ status,
+ visibleConfig,
+ config,
+ onToggleActive,
+ onToggleProfileCheck,
+ onToggleOnlyNotify,
+ onWeekdayChange,
+ weekdays,
+ onRangePickerRequest,
+ formatRangeLabel,
+ onSaveConfig,
+ onResetConfig,
+ onHideEntry,
+ onDeleteEntry,
+ canDelete,
+ focusedStoreId,
+ onClearFocus,
+ userLocation,
+ locationLoading,
+ locationSaving,
+ locationError,
+ onUpdateLocation
+}) => {
+ useEffect(() => {
+ if (!focusedStoreId) {
+ return;
+ }
+ const row = document.querySelector(`[data-store-row="${focusedStoreId}"]`);
+ if (!row) {
+ onClearFocus();
+ return;
+ }
+ row.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ row.classList.add('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
+ const timeout = setTimeout(() => {
+ row.classList.remove('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
+ onClearFocus();
+ }, 2500);
+ return () => {
+ clearTimeout(timeout);
+ row.classList.remove('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
+ };
+ }, [focusedStoreId, onClearFocus]);
+ const [geoBusy, setGeoBusy] = useState(false);
+ const [geoError, setGeoError] = useState('');
+ const initialTableState = useMemo(() => readConfigTableState(), []);
+ const [tableSorting, setTableSorting] = useState(initialTableState.sorting);
+ const [tableFilters, setTableFilters] = useState(initialTableState.columnFilters);
+
+ useEffect(() => {
+ persistConfigTableState({ sorting: tableSorting, columnFilters: tableFilters });
+ }, [tableSorting, tableFilters]);
+
+ const configTableData = useMemo(
+ () =>
+ Array.isArray(visibleConfig)
+ ? visibleConfig.map((item) => ({
+ ...item,
+ normalizedLabel: (item.label || '').toLowerCase()
+ }))
+ : [],
+ [visibleConfig]
+ );
const weekdaysOptions = useMemo(
() =>
@@ -251,134 +381,6 @@ const ColumnTextFilter = ({ column, placeholder }) => {
getFilteredRowModel: getFilteredRowModel()
});
- return (
- column.setFilterValue(event.target.value || undefined)}
- placeholder={placeholder}
- className="mt-1 w-full rounded border px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-blue-500"
- />
- );
-};
-
-const ColumnSelectFilter = ({ column, options, placeholder = 'Alle' }) => {
- if (!column.getCanFilter()) {
- return null;
- }
- return (
-
- );
-};
-
-const DashboardView = ({
- session,
- onRefresh,
- onLogout,
- notificationPanelOpen,
- onToggleNotificationPanel,
- notificationProps,
- stores,
- availableCollapsed,
- onToggleStores,
- onStoreSelect,
- configMap,
- error,
- onDismissError,
- status,
- visibleConfig,
- config,
- onToggleActive,
- onToggleProfileCheck,
- onToggleOnlyNotify,
- onWeekdayChange,
- weekdays,
- onRangePickerRequest,
- formatRangeLabel,
- onSaveConfig,
- onResetConfig,
- onHideEntry,
- onDeleteEntry,
- canDelete,
- focusedStoreId,
- onClearFocus,
- userLocation,
- locationLoading,
- locationSaving,
- locationError,
- onUpdateLocation
-}) => {
- const loadTableState = useCallback(() => {
- if (typeof window === 'undefined') {
- return { sorting: [], columnFilters: [] };
- }
- try {
- const raw = window.localStorage.getItem(CONFIG_TABLE_STATE_KEY);
- if (!raw) {
- return { sorting: [], columnFilters: [] };
- }
- const parsed = JSON.parse(raw);
- return {
- sorting: Array.isArray(parsed.sorting) ? parsed.sorting : [],
- columnFilters: Array.isArray(parsed.columnFilters) ? parsed.columnFilters : []
- };
- } catch {
- return { sorting: [], columnFilters: [] };
- }
- }, []);
-
- const initialTableState = loadTableState();
-
- useEffect(() => {
- if (!focusedStoreId) {
- return;
- }
- const row = document.querySelector(`[data-store-row="${focusedStoreId}"]`);
- if (!row) {
- onClearFocus();
- return;
- }
- row.scrollIntoView({ behavior: 'smooth', block: 'center' });
- row.classList.add('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
- const timeout = setTimeout(() => {
- row.classList.remove('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
- onClearFocus();
- }, 2500);
- return () => {
- clearTimeout(timeout);
- row.classList.remove('dashboard-row-highlight', 'ring-4', 'ring-blue-400');
- };
- }, [focusedStoreId, onClearFocus]);
- const [geoBusy, setGeoBusy] = useState(false);
- const [geoError, setGeoError] = useState('');
- const [tableSorting, setTableSorting] = useState(initialTableState.sorting);
- const [tableFilters, setTableFilters] = useState(initialTableState.columnFilters);
-
- useEffect(() => {
- if (typeof window === 'undefined') {
- return;
- }
- try {
- window.localStorage.setItem(
- CONFIG_TABLE_STATE_KEY,
- JSON.stringify({ sorting: tableSorting, columnFilters: tableFilters })
- );
- } catch {
- /* ignore */
- }
- }, [tableSorting, tableFilters]);
-
const handleDetectLocation = useCallback(() => {
if (!navigator.geolocation) {
setGeoError('Standortbestimmung wird von diesem Browser nicht unterstützt.');
diff --git a/src/components/StoreWatchPage.js b/src/components/StoreWatchPage.js
index 16571ef..66a464f 100644
--- a/src/components/StoreWatchPage.js
+++ b/src/components/StoreWatchPage.js
@@ -500,7 +500,7 @@ const StoreWatchPage = ({ authorizedFetch, knownStores = [], userLocation }) =>
} finally {
setRegionLoading(false);
}
- }, [authorizedFetch, selectedRegionId]);
+ }, [authorizedFetch]);
const loadSubscriptions = useCallback(async () => {
if (!authorizedFetch) {