diff --git a/frontend/src/components/EditAndReviewTable.jsx b/frontend/src/components/EditAndReviewTable.jsx index a62498e..a5a354d 100644 --- a/frontend/src/components/EditAndReviewTable.jsx +++ b/frontend/src/components/EditAndReviewTable.jsx @@ -1,3 +1,4 @@ +import { useMemo } from "react"; import PropTypes from "prop-types"; import { Link, useNavigate } from "react-router-dom"; import classNames from "classnames"; @@ -8,19 +9,17 @@ import { faChevronRight, } from "@fa-kit/icons/classic/solid"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import paths from "@/router/paths"; import StatusBadge from "@/components/StatusBadge"; import NotReadyFlag from "@/components/NotReadyFlag"; function TableRow(park) { const navigate = useNavigate(); - - function getParkLink() { - return `/park/${park.orcs}`; - } + const parkLink = useMemo(() => paths.park(park.orcs), [park.orcs]); // navigate to park details page function navigateToPark() { - navigate(getParkLink()); + navigate(parkLink); } return ( @@ -31,7 +30,7 @@ function TableRow(park) { - + , }, // edit/submit dates for a season { - path: "/park/:parkId/edit/:seasonId", + path: paths.seasonEdit(":parkId", ":seasonId"), element: , }, // review changes { - path: "/park/:parkId/edit/:seasonId/preview", + path: paths.seasonPreview(":parkId", ":seasonId"), element: , }, // edit/submit winter fees dates { - path: "/park/:parkId/winter-fees/:seasonId/edit", + path: paths.winterFeesEdit(":parkId", ":seasonId"), element: , }, // review winter fees dates { - path: "/park/:parkId/winter-fees/:seasonId/preview", + path: paths.winterFeesPreview(":parkId", ":seasonId"), element: , }, ], diff --git a/frontend/src/router/pages/ParkDetails.jsx b/frontend/src/router/pages/ParkDetails.jsx index 8226381..0e8d693 100644 --- a/frontend/src/router/pages/ParkDetails.jsx +++ b/frontend/src/router/pages/ParkDetails.jsx @@ -1,5 +1,6 @@ import { useEffect } from "react"; import { useParams, useSearchParams } from "react-router-dom"; +import paths from "@/router/paths"; import { useApiGet } from "@/hooks/useApi"; import { useFlashMessage } from "@/hooks/useFlashMessage"; import NavBack from "@/components/NavBack"; @@ -45,7 +46,7 @@ function ParkDetails() { // Remove the query string so the flash message won't show again searchParams.delete("approved"); searchParams.delete("saved"); - setSearchParams(searchParams); + setSearchParams(searchParams, { replace: true }); // Find the season in the park data by its ID const allSeasons = [ @@ -100,9 +101,8 @@ function ParkDetails() { seasons={seasons} seasonProps={{ getDataEndpoint: (seasonId) => `/seasons/${seasonId}`, - getEditRoutePath: (seasonId) => `/park/${parkId}/edit/${seasonId}`, - getPreviewRoutePath: (seasonId) => - `/park/${parkId}/edit/${seasonId}/preview`, + getEditRoutePath: paths.seasonEdit, + getPreviewRoutePath: paths.seasonPreview, getTitle: (season) => `${season.operatingYear} season`, DetailsComponent: SeasonDates, }} @@ -117,10 +117,8 @@ function ParkDetails() { seasons={park.winterFees} seasonProps={{ getDataEndpoint: (seasonId) => `/winter-fees/${seasonId}`, - getEditRoutePath: (seasonId) => - `/park/${parkId}/winter-fees/${seasonId}/edit`, - getPreviewRoutePath: (seasonId) => - `/park/${parkId}/winter-fees/${seasonId}/preview`, + getEditRoutePath: paths.winterFeesEdit, + getPreviewRoutePath: paths.winterFeesPreview, getTitle: (season) => `${season.operatingYear} – ${season.operatingYear + 1}`, DetailsComponent: WinterFeesDates, diff --git a/frontend/src/router/pages/PreviewChanges.jsx b/frontend/src/router/pages/PreviewChanges.jsx index cc63cd9..85f23fe 100644 --- a/frontend/src/router/pages/PreviewChanges.jsx +++ b/frontend/src/router/pages/PreviewChanges.jsx @@ -1,11 +1,12 @@ import PropTypes from "prop-types"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams, Link } from "react-router-dom"; import { useEffect, useState } from "react"; import { useApiGet, useApiPost } from "@/hooks/useApi"; import { useNavigationGuard } from "@/hooks/useNavigationGuard"; import { useConfirmation } from "@/hooks/useConfirmation"; import { useMissingDatesConfirmation } from "@/hooks/useMissingDatesConfirmation"; import { useFlashMessage } from "@/hooks/useFlashMessage"; +import paths from "@/router/paths"; import { faPen } from "@fa-kit/icons/classic/solid"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -21,8 +22,6 @@ import ConfirmationDialog from "@/components/ConfirmationDialog"; import MissingDatesConfirmationDialog from "@/components/MissingDatesConfirmationDialog"; import FlashMessage from "@/components/FlashMessage"; -import { Link } from "react-router-dom"; - import "./PreviewChanges.scss"; function PreviewChanges() { @@ -65,7 +64,7 @@ function PreviewChanges() { useNavigationGuard(hasChanges, openConfirmation); function navigateToEdit() { - navigate(`/park/${parkId}/edit/${seasonId}`); + navigate(paths.seasonEdit(parkId, seasonId)); } function getPrevSeasonDates(feature, dateType) { @@ -114,7 +113,7 @@ function PreviewChanges() { readyToPublish, }); - navigate(`/park/${parkId}?saved=${data.id}`); + navigate(`${paths.park(parkId)}?saved=${data.id}`); } catch (err) { console.error("Error saving preview", err); @@ -215,7 +214,7 @@ function PreviewChanges() { missingDatesConfirmation.setInputMessage(""); // Redirect back to the Park Details page on success. // Use the "approved" query param to show a flash message. - navigate(`/park/${parkId}?approved=${data.id}`); + navigate(`${paths.park(parkId)}?approved=${data.id}`); } } else { await approveData({ @@ -224,7 +223,7 @@ function PreviewChanges() { }); // Redirect back to the Park Details page on success. // Use the "approved" query param to show a flash message. - navigate(`/park/${parkId}?approved=${data.id}`); + navigate(`${paths.park(parkId)}?approved=${data.id}`); } } catch (err) { console.error("Error approving preview", err); @@ -368,7 +367,7 @@ function PreviewChanges() { onCancel={missingDatesConfirmation.handleCancel} onConfirm={missingDatesConfirmation.handleConfirm} /> - + Back to {data?.park.name} dates @@ -424,7 +423,7 @@ function PreviewChanges() {
diff --git a/frontend/src/router/pages/PreviewWinterFeesChanges.jsx b/frontend/src/router/pages/PreviewWinterFeesChanges.jsx index 60fc7e8..731be14 100644 --- a/frontend/src/router/pages/PreviewWinterFeesChanges.jsx +++ b/frontend/src/router/pages/PreviewWinterFeesChanges.jsx @@ -1,11 +1,12 @@ import PropTypes from "prop-types"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate, useParams, Link } from "react-router-dom"; import { useEffect, useState } from "react"; import { useApiGet, useApiPost } from "@/hooks/useApi"; import { useNavigationGuard } from "@/hooks/useNavigationGuard"; import { useConfirmation } from "@/hooks/useConfirmation"; import { useMissingDatesConfirmation } from "@/hooks/useMissingDatesConfirmation"; import { useFlashMessage } from "@/hooks/useFlashMessage"; +import paths from "@/router/paths"; import { faPen } from "@fa-kit/icons/classic/solid"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -21,8 +22,6 @@ import ConfirmationDialog from "@/components/ConfirmationDialog"; import MissingDatesConfirmationDialog from "@/components/MissingDatesConfirmationDialog"; import FlashMessage from "@/components/FlashMessage"; -import { Link } from "react-router-dom"; - import "./PreviewChanges.scss"; function PreviewChanges() { @@ -65,7 +64,7 @@ function PreviewChanges() { useNavigationGuard(hasChanges, openConfirmation); function navigateToEdit() { - navigate(`/park/${parkId}/winter-fees/${seasonId}/edit`); + navigate(paths.winterFeesEdit(parkId, seasonId)); } function getDates(dates) { @@ -97,7 +96,7 @@ function PreviewChanges() { readyToPublish, }); - navigate(`/park/${parkId}?saved=${data.id}`); + navigate(`${paths.park(parkId)}?saved=${data.id}`); } catch (err) { console.error("Error saving preview", err); @@ -134,7 +133,7 @@ function PreviewChanges() { missingDatesConfirmation.setInputMessage(""); // Redirect back to the Park Details page on success. // Use the "approved" query param to show a flash message. - navigate(`/park/${parkId}?approved=${data.id}`); + navigate(`${paths.park(parkId)}?approved=${data.id}`); } } else { await approveData({ @@ -143,7 +142,7 @@ function PreviewChanges() { }); // Redirect back to the Park Details page on success. // Use the "approved" query param to show a flash message. - navigate(`/park/${parkId}?approved=${data.id}`); + navigate(`${paths.park(parkId)}?approved=${data.id}`); } } catch (err) { console.error("Error approving preview", err); @@ -257,7 +256,7 @@ function PreviewChanges() { onConfirm={missingDatesConfirmation.handleConfirm} /> - + Back to {data?.park.name} dates @@ -313,7 +312,7 @@ function PreviewChanges() {
diff --git a/frontend/src/router/pages/SubmitDates.jsx b/frontend/src/router/pages/SubmitDates.jsx index ef5a8f8..0c0a5e4 100644 --- a/frontend/src/router/pages/SubmitDates.jsx +++ b/frontend/src/router/pages/SubmitDates.jsx @@ -32,6 +32,7 @@ import { normalizeToUTCDate, normalizeToLocalDate, } from "@/lib/utils"; +import paths from "@/router/paths"; import "./SubmitDates.scss"; @@ -125,7 +126,7 @@ function SubmitDates() { const response = await sendData(payload); if (savingDraft) { - navigate(`/park/${parkId}?saved=${data.id}`); + navigate(`${paths.park(parkId)}?saved=${data.id}`); } return response; @@ -165,7 +166,7 @@ function SubmitDates() { const submitOk = await submitChanges(); if (submitOk) { - navigate(`/park/${parkId}/edit/${seasonId}/preview`); + navigate(paths.seasonPreview(parkId, seasonId)); } } catch (err) { console.error(err); @@ -725,7 +726,7 @@ function SubmitDates() { variant="error" /> - + Back to {season?.park.name} season dates @@ -807,7 +808,7 @@ function SubmitDates() {
diff --git a/frontend/src/router/pages/SubmitWinterFeesDates.jsx b/frontend/src/router/pages/SubmitWinterFeesDates.jsx index caa16e1..f3badb3 100644 --- a/frontend/src/router/pages/SubmitWinterFeesDates.jsx +++ b/frontend/src/router/pages/SubmitWinterFeesDates.jsx @@ -32,6 +32,7 @@ import { normalizeToUTCDate, normalizeToLocalDate, } from "@/lib/utils"; +import paths from "@/router/paths"; import "./SubmitWinterFeesDates.scss"; @@ -455,7 +456,7 @@ export default function SubmitWinterFeesDates() { const response = await sendData(payload); if (savingDraft) { - navigate(`/park/${parkId}?saved=${data.id}`); + navigate(`${paths.park(parkId)}?saved=${data.id}`); } return response; @@ -511,7 +512,7 @@ export default function SubmitWinterFeesDates() { const submitOk = await submitChanges(); if (submitOk) { - navigate(`/park/${parkId}/winter-fees/${seasonId}/preview`); + navigate(paths.winterFeesPreview(parkId, seasonId)); } } catch (err) { console.error(err); @@ -575,7 +576,7 @@ export default function SubmitWinterFeesDates() { isOpen={isConfirmationOpen} /> - + Back to {season.park.name} season dates @@ -649,7 +650,7 @@ export default function SubmitWinterFeesDates() {
diff --git a/frontend/src/router/paths.js b/frontend/src/router/paths.js new file mode 100644 index 0000000..da25200 --- /dev/null +++ b/frontend/src/router/paths.js @@ -0,0 +1,25 @@ +// Router path resolvers for resource IDs + +function park(id) { + return `/parks/${id}`; +} + +export default { + park, + + seasonEdit(parkId, seasonId) { + return `${park(parkId)}/seasons/${seasonId}/edit`; + }, + + seasonPreview(parkId, seasonId) { + return `${park(parkId)}/seasons/${seasonId}/preview`; + }, + + winterFeesEdit(parkId, seasonId) { + return `${park(parkId)}/winter-fees/${seasonId}/edit`; + }, + + winterFeesPreview(parkId, seasonId) { + return `${park(parkId)}/winter-fees/${seasonId}/preview`; + }, +};