From 5ba463427b4605042a2a21f43aabd0301e3df769 Mon Sep 17 00:00:00 2001 From: "matthias.lotz" Date: Tue, 28 Oct 2025 22:59:59 +0100 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20upgrade=20react-router-dom=20?= =?UTF-8?q?5=E2=86=926=20(Phase=203)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update package.json: react-router-dom ^5.2.0→^6.28.0 - Migrate App.js: Switch→Routes, component→element props, path="*" for 404 - Migrate 5 pages: useHistory→useNavigate, history.push()→navigate() - GroupsOverviewPage.js (4x navigate) - ModerationGroupsPage.js (1x navigate) - ModerationGroupImagesPage.js (2x navigate) - PublicGroupImagesPage.js (import updated) - SlideshowPage.js (4x navigate + keyboard handler) - Regenerate package-lock.json with react-router v6 ✅ Tested: Production build 254.46 KB gzip (+1.17 KB) ✅ Manual test: Navigation, moderation routing, slideshow ESC - all working Phase 3 complete: Modern react-router v6 with improved routing API. --- frontend/package-lock.json | 130 ++++-------------- frontend/package.json | 2 +- frontend/src/App.js | 20 +-- .../Components/Pages/GroupsOverviewPage.js | 12 +- .../Pages/ModerationGroupImagesPage.js | 8 +- .../Components/Pages/ModerationGroupsPage.js | 6 +- .../Components/Pages/PublicGroupImagesPage.js | 4 +- .../src/Components/Pages/SlideshowPage.js | 16 +-- 8 files changed, 61 insertions(+), 137 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 21a0ea1..6f67502 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,7 +20,7 @@ "react-dropzone": "^11.3.1", "react-helmet": "^6.1.0", "react-lottie": "^1.2.3", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.28.0", "react-scripts": "5.0.1", "sass": "^1.32.8", "sweetalert2": "^10.15.6", @@ -3840,6 +3840,14 @@ "node": ">=8.9.0" } }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -9657,18 +9665,6 @@ "node": "*" } }, - "node_modules/history": { - "version": "4.10.1", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "license": "BSD-3-Clause", @@ -17020,69 +17016,35 @@ } }, "node_modules/react-router": { - "version": "5.2.0", - "license": "MIT", + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", + "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "5.2.0", - "license": "MIT", + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", + "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/react-router/node_modules/isarray": { - "version": "0.0.1", - "license": "MIT" - }, - "node_modules/react-router/node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - }, - "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/react-router/node_modules/path-to-regexp": { - "version": "1.8.0", - "license": "MIT", - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/react-router/node_modules/react-is": { - "version": "16.13.1", - "license": "MIT" - }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -17518,10 +17480,6 @@ "node": ">=8" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "license": "MIT" - }, "node_modules/resolve-url-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", @@ -18966,19 +18924,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -19149,10 +19094,6 @@ "license": "MIT", "optional": true }, - "node_modules/tiny-invariant": { - "version": "1.1.0", - "license": "MIT" - }, "node_modules/tiny-warning": { "version": "1.0.3", "license": "MIT" @@ -19396,19 +19337,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/typescript-plugin-styled-components": { "version": "1.4.4", "license": "MIT", @@ -19607,10 +19535,6 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, - "node_modules/value-equal": { - "version": "1.0.1", - "license": "MIT" - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 29dad6a..42a3f71 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,7 @@ "react-dropzone": "^11.3.1", "react-helmet": "^6.1.0", "react-lottie": "^1.2.3", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.28.0", "react-scripts": "5.0.1", "sass": "^1.32.8", "sweetalert2": "^10.15.6", diff --git a/frontend/src/App.js b/frontend/src/App.js index 19f9237..9f60ec2 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,5 +1,5 @@ import './App.css'; -import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; // Pages import MultiUploadPage from './Components/Pages/MultiUploadPage'; @@ -13,15 +13,15 @@ import FZF from './Components/Pages/404Page.js' function App() { return ( - - - - - - - - - + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + ); } diff --git a/frontend/src/Components/Pages/GroupsOverviewPage.js b/frontend/src/Components/Pages/GroupsOverviewPage.js index 0c4091d..98e61cf 100644 --- a/frontend/src/Components/Pages/GroupsOverviewPage.js +++ b/frontend/src/Components/Pages/GroupsOverviewPage.js @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import { Container, @@ -25,7 +25,7 @@ import '../../App.css'; function GroupsOverviewPage() { // use CSS classes from GroupsOverviewPage.css - const history = useHistory(); + const navigate = useNavigate(); const [groups, setGroups] = useState([]); const [loading, setLoading] = useState(true); @@ -50,19 +50,19 @@ function GroupsOverviewPage() { }; const handleViewSlideshow = (groupId) => { - history.push(`/slideshow/${groupId}`); + navigate(`/slideshow/${groupId}`); }; const handleViewGroup = (groupId) => { - history.push(`/groups/${groupId}`); + navigate(`/groups/${groupId}`); }; const handleCreateNew = () => { - history.push('/multi-upload'); + navigate('/multi-upload'); }; const handleGoHome = () => { - history.push('/'); + navigate('/'); }; const formatDate = (dateString) => { diff --git a/frontend/src/Components/Pages/ModerationGroupImagesPage.js b/frontend/src/Components/Pages/ModerationGroupImagesPage.js index f5165b8..619e74a 100644 --- a/frontend/src/Components/Pages/ModerationGroupImagesPage.js +++ b/frontend/src/Components/Pages/ModerationGroupImagesPage.js @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useParams, useHistory } from 'react-router-dom'; +import { useParams, useNavigate } from 'react-router-dom'; import { Button, Container } from '@material-ui/core'; import Swal from 'sweetalert2/dist/sweetalert2.js'; import 'sweetalert2/src/sweetalert2.scss'; @@ -15,7 +15,7 @@ import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput'; const ModerationGroupImagesPage = () => { const { groupId } = useParams(); - const history = useHistory(); + const navigate = useNavigate(); const [group, setGroup] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); @@ -86,7 +86,7 @@ const ModerationGroupImagesPage = () => { } Swal.fire({ icon: 'success', title: 'Gruppe erfolgreich aktualisiert', timer: 1500, showConfirmButton: false }); - history.push('/moderation'); + navigate('/moderation'); } catch (e) { console.error(e); Swal.fire({ icon: 'error', title: 'Fehler beim Speichern', text: e.message }); @@ -144,7 +144,7 @@ const ModerationGroupImagesPage = () => {
- +
diff --git a/frontend/src/Components/Pages/ModerationGroupsPage.js b/frontend/src/Components/Pages/ModerationGroupsPage.js index f0ef83e..452d06b 100644 --- a/frontend/src/Components/Pages/ModerationGroupsPage.js +++ b/frontend/src/Components/Pages/ModerationGroupsPage.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { Helmet } from 'react-helmet'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { Container } from '@material-ui/core'; import Navbar from '../ComponentUtils/Headers/Navbar'; import Footer from '../ComponentUtils/Footer'; @@ -12,7 +12,7 @@ const ModerationGroupsPage = () => { const [error, setError] = useState(null); const [selectedGroup, setSelectedGroup] = useState(null); const [showImages, setShowImages] = useState(false); - const history = useHistory(); + const navigate = useNavigate(); useEffect(() => { loadModerationGroups(); @@ -134,7 +134,7 @@ const ModerationGroupsPage = () => { // Navigate to the dedicated group images page const viewGroupImages = (group) => { - history.push(`/moderation/groups/${group.groupId}`); + navigate(`/moderation/groups/${group.groupId}`); }; if (loading) { diff --git a/frontend/src/Components/Pages/PublicGroupImagesPage.js b/frontend/src/Components/Pages/PublicGroupImagesPage.js index 121da90..ce8d184 100644 --- a/frontend/src/Components/Pages/PublicGroupImagesPage.js +++ b/frontend/src/Components/Pages/PublicGroupImagesPage.js @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useParams, useHistory } from 'react-router-dom'; +import { useParams, useNavigate } from 'react-router-dom'; import { Button, Container } from '@material-ui/core'; import Navbar from '../ComponentUtils/Headers/Navbar'; import Footer from '../ComponentUtils/Footer'; @@ -9,7 +9,7 @@ import ImageGallery from '../ComponentUtils/ImageGallery'; const PublicGroupImagesPage = () => { const { groupId } = useParams(); - const history = useHistory(); + const navigate = useNavigate(); const [group, setGroup] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); diff --git a/frontend/src/Components/Pages/SlideshowPage.js b/frontend/src/Components/Pages/SlideshowPage.js index cdfb9ee..81cd8a3 100644 --- a/frontend/src/Components/Pages/SlideshowPage.js +++ b/frontend/src/Components/Pages/SlideshowPage.js @@ -1,5 +1,5 @@ import React, { useState, useEffect, useCallback } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import { Typography, @@ -108,7 +108,7 @@ const useStyles = makeStyles({ function SlideshowPage() { const classes = useStyles(); - const history = useHistory(); + const navigate = useNavigate(); const [allGroups, setAllGroups] = useState([]); const [currentGroupIndex, setCurrentGroupIndex] = useState(0); @@ -184,7 +184,7 @@ function SlideshowPage() { const handleKeyPress = (event) => { switch (event.key) { case 'Escape': - history.push('/'); + navigate('/'); break; case ' ': case 'ArrowRight': @@ -197,7 +197,7 @@ function SlideshowPage() { document.addEventListener('keydown', handleKeyPress); return () => document.removeEventListener('keydown', handleKeyPress); - }, [nextImage, history]); + }, [nextImage, navigate]); // Aktuelle Gruppe und Bild const currentGroup = allGroups[currentGroupIndex]; @@ -221,7 +221,7 @@ function SlideshowPage() { {error} history.push('/')} + onClick={() => navigate('/')} title="Zur Startseite" > @@ -240,7 +240,7 @@ function SlideshowPage() { history.push('/')} + onClick={() => navigate('/')} title="Zur Startseite" > @@ -255,7 +255,7 @@ function SlideshowPage() { {/* Navigation Buttons */} history.push('/')} + onClick={() => navigate('/')} title="Zur Startseite" > @@ -263,7 +263,7 @@ function SlideshowPage() { history.push('/')} + onClick={() => navigate('/')} title="Slideshow beenden" >