diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6ec308a..e3d554a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,14 +20,13 @@ "@types/node": "^20.0.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", - "@types/react-router-dom": "^5.3.3", "axios": "^1.10.0", "bootstrap": "^5.3.7", "browser-image-compression": "^2.0.2", "react": "^19.1.0", "react-datepicker": "^9.1.0", "react-dom": "^19.1.0", - "react-router-dom": "^6.30.1", + "react-router": "^7.12.0", "socket.io-client": "^4.8.1", "stripe": "^18.4.0", "typescript": "^4.9.5" @@ -1271,15 +1270,6 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@remix-run/router": { - "version": "1.23.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", - "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1860,12 +1850,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "20.19.30", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", @@ -1893,27 +1877,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, "node_modules/@types/statuses": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", @@ -2384,7 +2347,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3692,35 +3654,25 @@ } }, "node_modules/react-router": { - "version": "6.30.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", - "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz", + "integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.23.2" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.30.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", - "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.2", - "react-router": "6.30.3" + "react": ">=18", + "react-dom": ">=18" }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/redent": { @@ -3837,6 +3789,12 @@ "semver": "bin/semver.js" } }, + "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/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 4cb7012..519e3c2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,14 +16,13 @@ "@types/node": "^20.0.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", - "@types/react-router-dom": "^5.3.3", "axios": "^1.10.0", "bootstrap": "^5.3.7", "browser-image-compression": "^2.0.2", "react": "^19.1.0", "react-datepicker": "^9.1.0", "react-dom": "^19.1.0", - "react-router-dom": "^6.30.1", + "react-router": "^7.12.0", "socket.io-client": "^4.8.1", "stripe": "^18.4.0", "typescript": "^4.9.5" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3e310d6..48ff69d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,13 +1,10 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import React, { useState, useEffect } from 'react'; +import { createBrowserRouter, RouterProvider } from 'react-router'; import { AuthProvider, useAuth } from './contexts/AuthContext'; import { SocketProvider } from './contexts/SocketContext'; -import Navbar from './components/Navbar'; -import Footer from './components/Footer'; -import AuthModal from './components/AuthModal'; +import RootLayout from './components/RootLayout'; +import ProtectedLayout from './components/ProtectedLayout'; import AlphaGate from './components/AlphaGate'; -import FeedbackButton from './components/FeedbackButton'; -import { TwoFactorVerifyModal } from './components/TwoFactor'; import Home from './pages/Home'; import GoogleCallback from './pages/GoogleCallback'; import VerifyEmail from './pages/VerifyEmail'; @@ -30,50 +27,56 @@ import EarningsDashboard from './pages/EarningsDashboard'; import CompletePayment from './pages/CompletePayment'; import FAQ from './pages/FAQ'; import NotFound from './pages/NotFound'; -import PrivateRoute from './components/PrivateRoute'; import axios from 'axios'; import './App.css'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:5001'; +const router = createBrowserRouter([ + { + element: , + children: [ + // Public routes + { path: '/', element: }, + { path: '/auth/google/callback', element: }, + { path: '/verify-email', element: }, + { path: '/reset-password', element: }, + { path: '/items', element: }, + { path: '/items/:id', element: }, + { path: '/users/:id', element: }, + { path: '/forum', element: }, + { path: '/forum/:id', element: }, + { path: '/faq', element: }, + + // Protected routes group + { + element: , + children: [ + { path: '/items/:id/edit', element: }, + { path: '/items/:id/rent', element: }, + { path: '/create-item', element: }, + { path: '/renting', element: }, + { path: '/complete-payment/:rentalId', element: }, + { path: '/owning', element: }, + { path: '/profile', element: }, + { path: '/messages', element: }, + { path: '/forum/create', element: }, + { path: '/forum/:id/edit', element: }, + { path: '/my-posts', element: }, + { path: '/earnings', element: }, + ], + }, + + // Catch-all route + { path: '*', element: }, + ], + }, +]); + const AppContent: React.FC = () => { - const { showAuthModal, authModalMode, closeAuthModal, user } = useAuth(); const [hasAlphaAccess, setHasAlphaAccess] = useState(null); const [checkingAccess, setCheckingAccess] = useState(true); - // Step-up authentication state - const [showStepUpModal, setShowStepUpModal] = useState(false); - const [stepUpAction, setStepUpAction] = useState(); - const [stepUpMethods, setStepUpMethods] = useState<("totp" | "email" | "recovery")[]>([]); - - // Listen for step-up authentication required events - useEffect(() => { - const handleStepUpRequired = (event: CustomEvent) => { - const { action, methods } = event.detail; - setStepUpAction(action); - setStepUpMethods(methods || ["totp", "email", "recovery"]); - setShowStepUpModal(true); - }; - - window.addEventListener("stepUpRequired", handleStepUpRequired as EventListener); - - return () => { - window.removeEventListener("stepUpRequired", handleStepUpRequired as EventListener); - }; - }, []); - - const handleStepUpSuccess = useCallback(() => { - setShowStepUpModal(false); - setStepUpAction(undefined); - // Dispatch event so pending actions can auto-retry - window.dispatchEvent(new CustomEvent("stepUpSuccess")); - }, []); - - const handleStepUpClose = useCallback(() => { - setShowStepUpModal(false); - setStepUpAction(undefined); - }, []); - useEffect(() => { const checkAlphaAccess = async () => { // Bypass alpha access check if feature is disabled @@ -115,145 +118,7 @@ const AppContent: React.FC = () => { return ; } - return ( - <> - -
- -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - } /> - } /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - } /> - } /> - -
-
-
-
- - - - {/* Show feedback button for authenticated users */} - {user && } - - {/* Global Step-Up Authentication Modal */} - - - ); + return ; }; const AppWithSocket: React.FC = () => { @@ -274,4 +139,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/frontend/src/__tests__/components/ItemCard.test.tsx b/frontend/src/__tests__/components/ItemCard.test.tsx index d02a42c..e91f4c8 100644 --- a/frontend/src/__tests__/components/ItemCard.test.tsx +++ b/frontend/src/__tests__/components/ItemCard.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; +import { BrowserRouter } from 'react-router'; import { vi, type MockedFunction } from 'vitest'; import ItemCard from '../../components/ItemCard'; import { Item } from '../../types'; diff --git a/frontend/src/__tests__/components/Navbar.test.tsx b/frontend/src/__tests__/components/Navbar.test.tsx index 76b813b..22a1641 100644 --- a/frontend/src/__tests__/components/Navbar.test.tsx +++ b/frontend/src/__tests__/components/Navbar.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; +import { BrowserRouter } from 'react-router'; import { vi, type Mock } from 'vitest'; import Navbar from '../../components/Navbar'; import { rentalAPI, messageAPI } from '../../services/api'; @@ -45,8 +45,8 @@ vi.mock('../../contexts/AuthContext', () => ({ // Mock useNavigate const mockNavigate = vi.fn(); -vi.mock('react-router-dom', async () => { - const actual = await vi.importActual('react-router-dom'); +vi.mock('react-router', async () => { + const actual = await vi.importActual('react-router'); return { ...actual, useNavigate: () => mockNavigate, diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx index 80d6cae..8f78120 100644 --- a/frontend/src/components/Footer.tsx +++ b/frontend/src/components/Footer.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; const Footer: React.FC = () => { return ( diff --git a/frontend/src/components/ForumPostListItem.tsx b/frontend/src/components/ForumPostListItem.tsx index 9bb2380..7fb78ed 100644 --- a/frontend/src/components/ForumPostListItem.tsx +++ b/frontend/src/components/ForumPostListItem.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; import { ForumPost } from "../types"; import CategoryBadge from "./CategoryBadge"; import PostStatusBadge from "./PostStatusBadge"; diff --git a/frontend/src/components/ItemCard.tsx b/frontend/src/components/ItemCard.tsx index 283ba20..8753c0d 100644 --- a/frontend/src/components/ItemCard.tsx +++ b/frontend/src/components/ItemCard.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { Item } from '../types'; import { getImageUrl } from '../services/uploadService'; diff --git a/frontend/src/components/ItemReviews.tsx b/frontend/src/components/ItemReviews.tsx index 162e92c..61a6956 100644 --- a/frontend/src/components/ItemReviews.tsx +++ b/frontend/src/components/ItemReviews.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import { Rental } from "../types"; import { itemAPI } from "../services/api"; import Avatar from "./Avatar"; diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index 1d080dc..c1aca8f 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef, useCallback } from "react"; -import { Link, useNavigate, useLocation } from "react-router-dom"; +import { Link, useNavigate, useLocation } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { useSocket } from "../contexts/SocketContext"; import { rentalAPI, messageAPI } from "../services/api"; diff --git a/frontend/src/components/PricingForm.tsx b/frontend/src/components/PricingForm.tsx index 30c639f..45b1409 100644 --- a/frontend/src/components/PricingForm.tsx +++ b/frontend/src/components/PricingForm.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; interface PricingFormProps { pricePerHour: number | string; diff --git a/frontend/src/components/PrivateRoute.tsx b/frontend/src/components/ProtectedLayout.tsx similarity index 83% rename from frontend/src/components/PrivateRoute.tsx rename to frontend/src/components/ProtectedLayout.tsx index 8e7170a..b6921a0 100644 --- a/frontend/src/components/PrivateRoute.tsx +++ b/frontend/src/components/ProtectedLayout.tsx @@ -1,11 +1,8 @@ import React, { useEffect } from "react"; +import { Outlet } from "react-router"; import { useAuth } from "../contexts/AuthContext"; -interface PrivateRouteProps { - children: React.ReactNode; -} - -const PrivateRoute: React.FC = ({ children }) => { +const ProtectedLayout: React.FC = () => { const { user, loading, openAuthModal } = useAuth(); useEffect(() => { @@ -41,7 +38,7 @@ const PrivateRoute: React.FC = ({ children }) => { ); } - return <>{children}; + return ; }; -export default PrivateRoute; +export default ProtectedLayout; diff --git a/frontend/src/components/RootLayout.tsx b/frontend/src/components/RootLayout.tsx new file mode 100644 index 0000000..67e5fcd --- /dev/null +++ b/frontend/src/components/RootLayout.tsx @@ -0,0 +1,77 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Outlet } from "react-router"; +import { useAuth } from "../contexts/AuthContext"; +import Navbar from "./Navbar"; +import Footer from "./Footer"; +import AuthModal from "./AuthModal"; +import FeedbackButton from "./FeedbackButton"; +import { TwoFactorVerifyModal } from "./TwoFactor"; + +const RootLayout: React.FC = () => { + const { showAuthModal, authModalMode, closeAuthModal, user } = useAuth(); + + // Step-up authentication state + const [showStepUpModal, setShowStepUpModal] = useState(false); + const [stepUpAction, setStepUpAction] = useState(); + const [stepUpMethods, setStepUpMethods] = useState<("totp" | "email" | "recovery")[]>([]); + + // Listen for step-up authentication required events + useEffect(() => { + const handleStepUpRequired = (event: CustomEvent) => { + const { action, methods } = event.detail; + setStepUpAction(action); + setStepUpMethods(methods || ["totp", "email", "recovery"]); + setShowStepUpModal(true); + }; + + window.addEventListener("stepUpRequired", handleStepUpRequired as EventListener); + + return () => { + window.removeEventListener("stepUpRequired", handleStepUpRequired as EventListener); + }; + }, []); + + const handleStepUpSuccess = useCallback(() => { + setShowStepUpModal(false); + setStepUpAction(undefined); + // Dispatch event so pending actions can auto-retry + window.dispatchEvent(new CustomEvent("stepUpSuccess")); + }, []); + + const handleStepUpClose = useCallback(() => { + setShowStepUpModal(false); + setStepUpAction(undefined); + }, []); + + return ( + <> +
+ +
+ +
+
+
+ + + + {/* Show feedback button for authenticated users */} + {user && } + + {/* Global Step-Up Authentication Modal */} + + + ); +}; + +export default RootLayout; diff --git a/frontend/src/pages/CompletePayment.tsx b/frontend/src/pages/CompletePayment.tsx index 4328c85..c725548 100644 --- a/frontend/src/pages/CompletePayment.tsx +++ b/frontend/src/pages/CompletePayment.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useCallback, useRef } from "react"; -import { useParams, useNavigate, Link } from "react-router-dom"; +import { useParams, useNavigate, Link } from "react-router"; import { loadStripe } from "@stripe/stripe-js"; import { rentalAPI } from "../services/api"; import { useAuth } from "../contexts/AuthContext"; diff --git a/frontend/src/pages/CreateForumPost.tsx b/frontend/src/pages/CreateForumPost.tsx index 2a740ce..8b1ba83 100644 --- a/frontend/src/pages/CreateForumPost.tsx +++ b/frontend/src/pages/CreateForumPost.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { useNavigate, Link, useParams } from "react-router-dom"; +import { useNavigate, Link, useParams } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { forumAPI, addressAPI } from "../services/api"; import { uploadImagesWithVariants, getImageUrl } from "../services/uploadService"; diff --git a/frontend/src/pages/CreateItem.tsx b/frontend/src/pages/CreateItem.tsx index 4b0193d..9b37fba 100644 --- a/frontend/src/pages/CreateItem.tsx +++ b/frontend/src/pages/CreateItem.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import api, { addressAPI, userAPI, itemAPI } from "../services/api"; import { uploadImagesWithVariants } from "../services/uploadService"; diff --git a/frontend/src/pages/EarningsDashboard.tsx b/frontend/src/pages/EarningsDashboard.tsx index e25e78f..986942c 100644 --- a/frontend/src/pages/EarningsDashboard.tsx +++ b/frontend/src/pages/EarningsDashboard.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; import { rentalAPI, userAPI, stripeAPI } from "../services/api"; import { Rental, User } from "../types"; import StripeConnectOnboarding from "../components/StripeConnectOnboarding"; diff --git a/frontend/src/pages/EditItem.tsx b/frontend/src/pages/EditItem.tsx index fee9257..1e7b04e 100644 --- a/frontend/src/pages/EditItem.tsx +++ b/frontend/src/pages/EditItem.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate } from "react-router"; import { Item, Rental, Address } from "../types"; import { useAuth } from "../contexts/AuthContext"; import { itemAPI, rentalAPI, addressAPI, userAPI } from "../services/api"; diff --git a/frontend/src/pages/FAQ.tsx b/frontend/src/pages/FAQ.tsx index e3634d2..8fd9b10 100644 --- a/frontend/src/pages/FAQ.tsx +++ b/frontend/src/pages/FAQ.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; interface FAQItem { question: string; diff --git a/frontend/src/pages/ForumPostDetail.tsx b/frontend/src/pages/ForumPostDetail.tsx index 4113604..e209a7f 100644 --- a/frontend/src/pages/ForumPostDetail.tsx +++ b/frontend/src/pages/ForumPostDetail.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useParams, useNavigate, Link, useSearchParams } from 'react-router-dom'; +import { useParams, useNavigate, Link, useSearchParams } from 'react-router'; import { useAuth } from '../contexts/AuthContext'; import { forumAPI } from '../services/api'; import { uploadImagesWithVariants, getImageUrl } from '../services/uploadService'; diff --git a/frontend/src/pages/ForumPosts.tsx b/frontend/src/pages/ForumPosts.tsx index a6beff8..3dc1ec2 100644 --- a/frontend/src/pages/ForumPosts.tsx +++ b/frontend/src/pages/ForumPosts.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { Link, useSearchParams } from 'react-router-dom'; +import { Link, useSearchParams } from 'react-router'; import { useAuth } from '../contexts/AuthContext'; import { forumAPI } from '../services/api'; import { ForumPost } from '../types'; diff --git a/frontend/src/pages/GoogleCallback.tsx b/frontend/src/pages/GoogleCallback.tsx index 9150abf..44bc730 100644 --- a/frontend/src/pages/GoogleCallback.tsx +++ b/frontend/src/pages/GoogleCallback.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router'; import { useAuth } from '../contexts/AuthContext'; import { fetchCSRFToken } from '../services/api'; diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 8c74f8d..5d4cf5a 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { itemAPI } from "../services/api"; import { Item } from "../types"; diff --git a/frontend/src/pages/ItemDetail.tsx b/frontend/src/pages/ItemDetail.tsx index 6a96124..40beeb8 100644 --- a/frontend/src/pages/ItemDetail.tsx +++ b/frontend/src/pages/ItemDetail.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate } from "react-router"; import DatePicker from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; import { Item, Rental } from "../types"; diff --git a/frontend/src/pages/ItemList.tsx b/frontend/src/pages/ItemList.tsx index 6dd1b47..b5e31b9 100644 --- a/frontend/src/pages/ItemList.tsx +++ b/frontend/src/pages/ItemList.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; -import { useSearchParams, useNavigate } from "react-router-dom"; +import { useSearchParams, useNavigate } from "react-router"; import { Item } from "../types"; import { itemAPI } from "../services/api"; import ItemCard from "../components/ItemCard"; diff --git a/frontend/src/pages/MyPosts.tsx b/frontend/src/pages/MyPosts.tsx index 4a3ca44..53ee7f8 100644 --- a/frontend/src/pages/MyPosts.tsx +++ b/frontend/src/pages/MyPosts.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; +import { Link } from 'react-router'; import { useAuth } from '../contexts/AuthContext'; import { forumAPI } from '../services/api'; import { ForumPost } from '../types'; diff --git a/frontend/src/pages/NotFound.tsx b/frontend/src/pages/NotFound.tsx index 05c6cf4..fb93f0d 100644 --- a/frontend/src/pages/NotFound.tsx +++ b/frontend/src/pages/NotFound.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Link } from "react-router-dom"; +import { Link } from "react-router"; const NotFound: React.FC = () => { return ( diff --git a/frontend/src/pages/Owning.tsx b/frontend/src/pages/Owning.tsx index b2a8a39..c902889 100644 --- a/frontend/src/pages/Owning.tsx +++ b/frontend/src/pages/Owning.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import api from "../services/api"; import { Item, Rental, ConditionCheck } from "../types"; diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx index 71fd061..e73891a 100644 --- a/frontend/src/pages/Profile.tsx +++ b/frontend/src/pages/Profile.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useCallback, useMemo } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { userAPI, itemAPI, rentalAPI, addressAPI, conditionCheckAPI } from "../services/api"; import { User, Item, Rental, Address, ConditionCheck } from "../types"; diff --git a/frontend/src/pages/PublicProfile.tsx b/frontend/src/pages/PublicProfile.tsx index 0d2b336..2156899 100644 --- a/frontend/src/pages/PublicProfile.tsx +++ b/frontend/src/pages/PublicProfile.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; +import { useParams, useNavigate } from 'react-router'; import { User, Item } from '../types'; import { userAPI, itemAPI } from '../services/api'; import { getImageUrl } from '../services/uploadService'; diff --git a/frontend/src/pages/RentItem.tsx b/frontend/src/pages/RentItem.tsx index 49517f2..8119682 100644 --- a/frontend/src/pages/RentItem.tsx +++ b/frontend/src/pages/RentItem.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { useParams, useNavigate, useSearchParams } from "react-router-dom"; +import { useParams, useNavigate, useSearchParams } from "react-router"; import { Item } from "../types"; import { useAuth } from "../contexts/AuthContext"; import { itemAPI, rentalAPI } from "../services/api"; diff --git a/frontend/src/pages/Renting.tsx b/frontend/src/pages/Renting.tsx index c1d5370..12925a3 100644 --- a/frontend/src/pages/Renting.tsx +++ b/frontend/src/pages/Renting.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { rentalAPI, conditionCheckAPI } from "../services/api"; import { getImageUrl } from "../services/uploadService"; diff --git a/frontend/src/pages/ResetPassword.tsx b/frontend/src/pages/ResetPassword.tsx index ab04a1f..38ae02d 100644 --- a/frontend/src/pages/ResetPassword.tsx +++ b/frontend/src/pages/ResetPassword.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { useNavigate, useSearchParams, Link } from 'react-router-dom'; +import { useNavigate, useSearchParams, Link } from 'react-router'; import { useAuth } from '../contexts/AuthContext'; import { authAPI } from '../services/api'; import PasswordInput from '../components/PasswordInput'; diff --git a/frontend/src/pages/VerifyEmail.tsx b/frontend/src/pages/VerifyEmail.tsx index 9858c33..70002a7 100644 --- a/frontend/src/pages/VerifyEmail.tsx +++ b/frontend/src/pages/VerifyEmail.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from "react"; -import { useNavigate, useSearchParams, Link } from "react-router-dom"; +import { useNavigate, useSearchParams, Link } from "react-router"; import { useAuth } from "../contexts/AuthContext"; import { authAPI } from "../services/api"; diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index c672f51..cc5450d 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -160,7 +160,7 @@ api.interceptors.response.use( isRefreshing = false; processQueue(refreshError as AxiosError); - // Refresh failed - let React Router handle redirects via PrivateRoute + // Refresh failed - let React Router handle redirects via ProtectedLayout return Promise.reject(refreshError); } }