From 1f0ba8f564bd04f473e7921a09fb1a1554c2ef5a Mon Sep 17 00:00:00 2001
From: Meik
Date: Mon, 10 Nov 2025 17:00:59 +0100
Subject: [PATCH] =?UTF-8?q?Neue=20Seite=20um=20Betriebe=20zu=20=C3=BCberwa?=
=?UTF-8?q?chen?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.js | 2 +-
src/components/StoreWatchPage.js | 123 ++++++++++++++++++++++++++++---
2 files changed, 114 insertions(+), 11 deletions(-)
diff --git a/src/App.js b/src/App.js
index a66f424..6e44ab1 100644
--- a/src/App.js
+++ b/src/App.js
@@ -696,7 +696,7 @@ function App() {
- } />
+ } />
} />
diff --git a/src/components/StoreWatchPage.js b/src/components/StoreWatchPage.js
index 690ca08..e6eaf73 100644
--- a/src/components/StoreWatchPage.js
+++ b/src/components/StoreWatchPage.js
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
-const StoreWatchPage = ({ authorizedFetch }) => {
+const StoreWatchPage = ({ authorizedFetch, knownStores = [] }) => {
const [regions, setRegions] = useState([]);
const [selectedRegionId, setSelectedRegionId] = useState('');
const [storesByRegion, setStoresByRegion] = useState({});
@@ -12,6 +12,8 @@ const StoreWatchPage = ({ authorizedFetch }) => {
const [error, setError] = useState('');
const [dirty, setDirty] = useState(false);
const [saving, setSaving] = useState(false);
+ const [filterText, setFilterText] = useState('');
+ const [sortBy, setSortBy] = useState('name');
const watchedIds = useMemo(
() => new Set(watchList.map((entry) => String(entry.storeId))),
@@ -36,6 +38,58 @@ const StoreWatchPage = ({ authorizedFetch }) => {
[currentStores]
);
+ const membershipMap = useMemo(() => {
+ const map = new Map();
+ (knownStores || []).forEach((store) => {
+ if (store?.id) {
+ map.set(String(store.id), store);
+ }
+ });
+ return map;
+ }, [knownStores]);
+
+ const filteredStores = useMemo(() => {
+ const search = filterText.trim().toLowerCase();
+ const data = !search
+ ? [...eligibleStores]
+ : eligibleStores.filter((store) => {
+ const haystack = [
+ store.name,
+ store.city,
+ store.street,
+ store.zipCode,
+ store.id
+ ]
+ .filter(Boolean)
+ .map((value) => String(value).toLowerCase());
+ return haystack.some((value) => value.includes(search));
+ });
+ const compareString = (a = '', b = '') => a.localeCompare(b, 'de', { sensitivity: 'base' });
+ data.sort((a, b) => {
+ switch (sortBy) {
+ case 'city':
+ return compareString(a.city || '', b.city || '') || compareString(a.name || '', b.name || '');
+ case 'created-desc': {
+ const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
+ const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
+ if (timeA === timeB) {
+ return compareString(a.name || '', b.name || '');
+ }
+ return timeB - timeA;
+ }
+ case 'membership':
+ return (
+ Number(membershipMap.has(String(b.id))) - Number(membershipMap.has(String(a.id))) ||
+ compareString(a.name || '', b.name || '')
+ );
+ case 'name':
+ default:
+ return compareString(a.name || '', b.name || '');
+ }
+ });
+ return data;
+ }, [eligibleStores, filterText, sortBy, membershipMap]);
+
const loadRegions = useCallback(async () => {
if (!authorizedFetch) {
return;
@@ -279,6 +333,42 @@ const StoreWatchPage = ({ authorizedFetch }) => {
+
+
+
+
+ Betriebe filtern
+
+ setFilterText(event.target.value)}
+ className="border rounded-md p-2 w-full"
+ placeholder="Name, Ort oder PLZ"
+ disabled={!selectedRegionId}
+ />
+
+
+
+ Sortieren nach
+
+ setSortBy(event.target.value)}
+ className="border rounded-md p-2 w-full"
+ disabled={!selectedRegionId}
+ >
+ Name (A-Z)
+ Ort (A-Z)
+ Kooperation (neueste zuerst)
+ Eigene Betriebe zuerst
+
+
+
+
+
Betriebe in der Region
@@ -290,27 +380,33 @@ const StoreWatchPage = ({ authorizedFetch }) => {
)}
{storesLoading &&
Lade Betriebe...
}
- {!storesLoading && (!selectedRegionId || eligibleStores.length === 0) && (
+ {!storesLoading && !selectedRegionId && (
+
Bitte zuerst eine Region auswählen.
+ )}
+ {!storesLoading && selectedRegionId && filteredStores.length === 0 && (
- {selectedRegionId
- ? 'Keine geeigneten Betriebe (Status "aktiv") in dieser Region.'
- : 'Bitte zuerst eine Region auswählen.'}
+ Keine Betriebe gefunden. Prüfe Filter oder sortiere anders.
)}
- {!storesLoading && eligibleStores.length > 0 && (
+ {!storesLoading && filteredStores.length > 0 && (