From 961fcdf441254be44ff6a46ced1076d0e081890b Mon Sep 17 00:00:00 2001 From: ap-justin <89639563+ap-justin@users.noreply.github.com> Date: Sat, 12 Oct 2024 21:53:00 +0800 Subject: [PATCH] profile loading --- src/App/App.tsx | 6 +--- src/pages/Profile/index.tsx | 38 +++------------------- src/pages/Profile/profile-loader.ts | 49 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 src/pages/Profile/profile-loader.ts diff --git a/src/App/App.tsx b/src/App/App.tsx index 475516ddf8..dc865a0850 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -40,11 +40,7 @@ const _appRoutes: RO[] = [ ...blogRoutes, ...legalRoutes, ...infoRoutes, - { - element: , //outlet-value: legacy - children: [{ path: appRoutes.profile + "/:id", ...profileRoute }], - }, - + { path: appRoutes.profile + "/:id", ...profileRoute }, { path: appRoutes.banking_applications, children: [ diff --git a/src/pages/Profile/index.tsx b/src/pages/Profile/index.tsx index 5691cacf4e..f8d40cfb83 100644 --- a/src/pages/Profile/index.tsx +++ b/src/pages/Profile/index.tsx @@ -3,43 +3,14 @@ import flying_character from "assets/images/flying-character.png"; import Image from "components/Image"; import Seo from "components/Seo"; import { APP_NAME, BASE_URL } from "constants/env"; -import { appRoutes } from "constants/routes"; -import { - Navigate, - Outlet, - type RouteObject, - useOutletContext, - useParams, -} from "react-router-dom"; -import { segment } from "schemas/string"; -import { useEndowment } from "services/aws/useEndowment"; +import { Outlet, type RouteObject, useLoaderData } from "react-router-dom"; +import type { EndowmentProfile } from "types/aws"; import { bodyRoute } from "./Body"; -import PageError from "./PageError"; import ProfileContext, { useProfileContext } from "./ProfileContext"; -import Skeleton from "./Skeleton"; +import { profileLoader } from "./profile-loader"; function Profile() { - const legacy = useOutletContext(); - const { id = "" } = useParams<{ id: string }>(); - - const { isLoading, isError, data } = useEndowment( - segment.isValidSync(id) ? { slug: id } : { id: Number(id) } - ); - - if (isLoading) return ; - if (isError || !data) return ; - - if (legacy) { - if (data.id === null) { - return ; - } - - if (data.id !== Number(id)) { - return ; - } - } - - // if (!data.published) return ; + const data = useLoaderData() as EndowmentProfile; return ( @@ -85,5 +56,6 @@ function Logo() { export const profileRoute: RouteObject = { element: , + loader: profileLoader, children: [bodyRoute], }; diff --git a/src/pages/Profile/profile-loader.ts b/src/pages/Profile/profile-loader.ts new file mode 100644 index 0000000000..8c8de82d31 --- /dev/null +++ b/src/pages/Profile/profile-loader.ts @@ -0,0 +1,49 @@ +import { APIs } from "constants/urls"; +import { type LoaderFunctionArgs, redirect } from "react-router-dom"; +import { apiEnv } from "services/constants"; +import * as v from "valibot"; + +const schema = v.union([ + v.pipe( + v.string(), + v.transform((x) => +x), + v.number(), + v.integer(), + v.minValue(1) + ), + v.pipe( + v.string(), + v.trim(), + v.nonEmpty(), + //must not be id-like + v.regex(/^(?!^\d+$)/, "should not be an id"), + //valid characters + v.regex(/^[a-zA-Z0-9-._~]+$/, "invalid segment"), + v.excludes("..", "invalid segment"), + v.custom((x) => !(x as string).startsWith("."), "invalid segment"), + v.custom((x) => !(x as string).endsWith("."), "invalid segment") + ), +]); + +export const profileLoader = async ({ + params, +}: LoaderFunctionArgs): Promise => { + const cache = await caches.open("bg"); + const { output: id, issues } = v.safeParse(schema, params.id); + if (issues) return redirect("/marketplace"); + + const url = new URL(APIs.aws); + url.searchParams.set("env", apiEnv); + if (typeof id === "number") { + url.pathname = `v9/endowments/${id}`; + } + if (typeof id === "string") { + url.pathname = `v9/endowments`; + url.searchParams.set("slug", id); + } + const c = await cache.match(url); + if (c) return c.clone(); + + await cache.add(url); + return cache.match(url); +};