From cd93800ffbe0b3fa6e3c7b57233fb7065901259a Mon Sep 17 00:00:00 2001 From: root Date: Sun, 9 Nov 2025 14:31:52 +0100 Subject: [PATCH] aktueller Stand --- config/credentials.json | 2 +- package-lock.json | 54 +++++++ package.json | 3 +- src/App.js | 325 +++++++++++++++++++++++++--------------- src/App.test.js | 6 +- 5 files changed, 266 insertions(+), 124 deletions(-) diff --git a/config/credentials.json b/config/credentials.json index c7589de..1cd9355 100644 --- a/config/credentials.json +++ b/config/credentials.json @@ -2,6 +2,6 @@ "839246": { "email": "meikdre@gmx.de", "password": "R67aJUj2-wWVfP8", - "token": "1fdccfbe-2182-4749-9f42-ac79345c143d" + "token": "5e5b273c-fd9c-4a1f-a4cd-55b26a3b6419" } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d754262..957db8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "node-cron": "^3.0.3", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-router-dom": "^7.9.5", "uuid": "^11.0.3", "web-vitals": "^2.1.4" }, @@ -15232,6 +15233,53 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz", + "integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.5.tgz", + "integrity": "sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.5" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -16159,6 +16207,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", diff --git a/package.json b/package.json index 896ef77..a1a85a6 100644 --- a/package.json +++ b/package.json @@ -3,17 +3,18 @@ "version": "0.1.0", "private": true, "dependencies": { - "axios": "^1.7.7", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.7.7", "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.18.2", "node-cron": "^3.0.3", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-router-dom": "^7.9.5", "uuid": "^11.0.3", "web-vitals": "^2.1.4" }, diff --git a/src/App.js b/src/App.js index 9ea6cb8..09e3fce 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import { BrowserRouter as Router, Routes, Route, Navigate, Link, useLocation } from 'react-router-dom'; import './App.css'; const emptyEntry = { @@ -659,7 +660,7 @@ function App() { ); } - return ( + const dashboardContent = (

Foodsharing Pickup Manager

@@ -877,124 +878,6 @@ function App() {
- {session?.isAdmin && ( -
-

Admin-Einstellungen

- {adminSettingsLoading &&

Lade Admin-Einstellungen...

} - {!adminSettingsLoading && !adminSettings && ( -

Keine Admin-Einstellungen verfügbar.

- )} - {adminSettings && ( - <> -
-
- - handleAdminSettingChange('scheduleCron', e.target.value)} - className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - /> -
-
- -
- handleAdminSettingChange('initialDelayMinSeconds', e.target.value, true)} - className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - placeholder="Min" - /> - handleAdminSettingChange('initialDelayMaxSeconds', e.target.value, true)} - className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - placeholder="Max" - /> -
-
-
- -
- handleAdminSettingChange('randomDelayMinSeconds', e.target.value, true)} - className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - placeholder="Min" - /> - handleAdminSettingChange('randomDelayMaxSeconds', e.target.value, true)} - className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - placeholder="Max" - /> -
-
-
- -
-
-

Ignorierte Slots

- -
- {(!adminSettings.ignoredSlots || adminSettings.ignoredSlots.length === 0) && ( -

Keine Regeln definiert.

- )} - {adminSettings.ignoredSlots?.map((slot, index) => ( -
- handleIgnoredSlotChange(index, 'storeId', e.target.value)} - placeholder="Store-ID" - className="md:col-span-2 border rounded p-2 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - /> - handleIgnoredSlotChange(index, 'description', e.target.value)} - placeholder="Beschreibung (optional)" - className="md:col-span-2 border rounded p-2 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" - /> - -
- ))} -
- -
- -
- - )} -
- )} - {showNewEntryForm ? (

Neuen Eintrag hinzufügen

@@ -1126,6 +1009,210 @@ function App() {
); + + const adminPageContent = session?.isAdmin ? ( +
+
+
+

Admin-Einstellungen

+

Globale Abläufe und Verzögerungen für die Abhol-Automation verwalten.

+
+ + Zur Konfiguration + +
+ {error && ( +
+ {error} + +
+ )} + {status && ( +
+ {status} +
+ )} +
+ {adminSettingsLoading &&

Lade Admin-Einstellungen...

} + {!adminSettingsLoading && !adminSettings && ( +

Keine Admin-Einstellungen verfügbar.

+ )} + {adminSettings && ( + <> +
+
+ + handleAdminSettingChange('scheduleCron', e.target.value)} + className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + placeholder="z. B. 0 * * * *" + /> +
+
+ +
+ handleAdminSettingChange('initialDelayMinSeconds', e.target.value, true)} + className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + placeholder="Min" + /> + handleAdminSettingChange('initialDelayMaxSeconds', e.target.value, true)} + className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + placeholder="Max" + /> +
+
+
+ +
+ handleAdminSettingChange('randomDelayMinSeconds', e.target.value, true)} + className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + placeholder="Min" + /> + handleAdminSettingChange('randomDelayMaxSeconds', e.target.value, true)} + className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + placeholder="Max" + /> +
+
+
+ +
+
+

Ignorierte Slots

+ +
+ {(!adminSettings.ignoredSlots || adminSettings.ignoredSlots.length === 0) && ( +

Keine Regeln definiert.

+ )} + {adminSettings.ignoredSlots?.map((slot, index) => ( +
+ handleIgnoredSlotChange(index, 'storeId', e.target.value)} + placeholder="Store-ID" + className="md:col-span-2 border rounded p-2 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + /> + handleIgnoredSlotChange(index, 'description', e.target.value)} + placeholder="Beschreibung (optional)" + className="md:col-span-2 border rounded p-2 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500" + /> + +
+ ))} +
+ +
+ +
+ + )} +
+
+ ) : ( + + ); + + return ( + +
+
+ + + + + } /> + +
+
+
+ ); +} + +function NavigationTabs({ isAdmin }) { + const location = useLocation(); + const tabs = [{ to: '/', label: 'Konfiguration' }]; + if (isAdmin) { + tabs.push({ to: '/admin', label: 'Admin' }); + } + + return ( +
+ {tabs.map((tab) => { + const isActive = location.pathname === tab.to; + return ( + + {tab.label} + + ); + })} +
+ ); +} + +function AdminAccessMessage() { + return ( +
+

Kein Zugriff

+

Dieser Bereich ist nur für Administratoren verfügbar.

+ + Zurück zur Konfiguration + +
+ ); } export default App; diff --git a/src/App.test.js b/src/App.test.js index 1f03afe..42bdfd1 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,8 +1,8 @@ import { render, screen } from '@testing-library/react'; import App from './App'; -test('renders learn react link', () => { +test('zeigt das Login-Formular an, wenn keine Session aktiv ist', () => { render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); + expect(screen.getByText(/Pickup Config Login/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/E-Mail/i)).toBeInTheDocument(); });