diff --git a/client/src/App.tsx b/client/src/App.tsx index 75d944e..b1b1125 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,10 +1,38 @@ -import { BrowserRouter, Outlet, Route, Routes } from "react-router"; +import { BrowserRouter, Navigate, Outlet, Route, Routes, useParams } from "react-router"; import SubmissionPage from "./pages/eventId/Submission.tsx"; import HomePage from "./pages/Home.tsx"; import LandingPage from "./pages/Landing.tsx"; import NotFoundPage from "./pages/NotFound.tsx"; import ProjectPage from "./pages/Project.tsx"; +/** + * Nano ID 形式の正規表現。 + * 現在はハイフン・アンダースコアを含まないが、初期は含んでいたため URL の検証時は両方許容する。 + */ +const NANOID_REGEX = /^[A-Za-z0-9_-]{21}$/; + +/** + * 旧パス /:eventId から新パス /e/:eventId へのリダイレクト。eventId は Nano ID 形式。 + */ +function LegacyEventRedirect() { + const { eventId } = useParams(); + if (!eventId || !NANOID_REGEX.test(eventId)) { + return ; + } + return ; +} + +/** + * 旧パス /:eventId/edit から新パス /e/:eventId/edit へのリダイレクト。eventId は Nano ID 形式。 + */ +function LegacyEventEditRedirect() { + const { eventId } = useParams(); + if (!eventId || !NANOID_REGEX.test(eventId)) { + return ; + } + return ; +} + export default function App() { return ( @@ -12,11 +40,19 @@ export default function App() { } /> } /> } /> - }> - } /> - } /> - } /> + + + }> + } /> + } /> + } /> + + + {/* /:eventId (旧形式) を /e/:eventId (新形式) にリダイレクト */} + } /> + } /> + } /> diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 79700df..9c3c7b7 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -107,7 +107,7 @@ function ProjectDashboard({ involvedProjects }: { involvedProjects: BriefProject function ProjectCard({ project }: { project: BriefProject }) { return ( diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx index 86331ce..722ccf2 100644 --- a/client/src/pages/Project.tsx +++ b/client/src/pages/Project.tsx @@ -242,7 +242,7 @@ export default function ProjectPage() { useEffect(() => { if (!loading && project && !isHost) { if (eventId) { - navigate(`/${eventId}`); + navigate(`/e/${eventId}`); } else { navigate("/"); } @@ -613,7 +613,7 @@ export default function ProjectPage() { )}
{eventId ? ( - + 日程調整に戻る ) : ( @@ -639,12 +639,12 @@ export default function ProjectPage() { type="text" disabled className="input input-info w-full" - value={`${FRONTEND_ORIGIN}/${dialogStatus.projectId}`} + value={`${FRONTEND_ORIGIN}/e/${dialogStatus.projectId}`} />
- + イベントへ
diff --git a/client/src/pages/eventId/Submission.tsx b/client/src/pages/eventId/Submission.tsx index a422e60..e199edf 100644 --- a/client/src/pages/eventId/Submission.tsx +++ b/client/src/pages/eventId/Submission.tsx @@ -210,7 +210,7 @@ export default function SubmissionPage() { <>
- {loading || !selectedParticipationOptionId ? ( + {loading ? (
@@ -221,12 +221,16 @@ export default function SubmissionPage() { ホームに戻る
+ ) : !selectedParticipationOptionId ? ( +
+ +
) : (

{project.name} の日程調整

{isHost && ( - + イベント設定 diff --git a/server/src/routes/projects.ts b/server/src/routes/projects.ts index 89de447..948ce5d 100644 --- a/server/src/routes/projects.ts +++ b/server/src/routes/projects.ts @@ -1,13 +1,18 @@ import { zValidator } from "@hono/zod-validator"; import dotenv from "dotenv"; import { Hono } from "hono"; -import { nanoid } from "nanoid"; +import { customAlphabet } from "nanoid"; import { z } from "zod"; import { editReqSchema, projectReqSchema, submitReqSchema } from "../../../common/validators.js"; import { prisma } from "../main.js"; dotenv.config(); +/** + * ハイフン・アンダースコアを含まない Nano ID 形式。 + */ +const nanoid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 21); + const projectIdParamsSchema = z.object({ projectId: z.string().length(21) }); type AppVariables = {