import { Suspense, lazy } from "react"; import { data, redirect } from "react-router"; import { useTranslation } from "react-i18next"; import type { Route } from "./+types/activities.$id"; import { getSessionUser } from "~/lib/auth.server"; import { getActivity, deleteActivity, linkActivityToRoute, createRouteFromActivity } from "~/lib/activities.server"; import { deleteImportByActivity } from "~/lib/sync/imports.server"; import { listRoutes } from "~/lib/routes.server"; import { ClientDate } from "~/components/ClientDate"; const RouteMapThumbnail = lazy(() => import("~/components/RouteMapThumbnail").then((m) => ({ default: m.RouteMapThumbnail })), ); export async function loader({ params, request }: Route.LoaderArgs) { const activity = await getActivity(params.id); if (!activity) throw data({ error: "Activity not found" }, { status: 404 }); const user = await getSessionUser(request); const isOwner = user?.id === activity.ownerId; const userRoutes = isOwner && user ? await listRoutes(user.id) : []; return data({ activity: { id: activity.id, name: activity.name, description: activity.description, distance: activity.distance, elevationGain: activity.elevationGain, elevationLoss: activity.elevationLoss, duration: activity.duration, routeId: activity.routeId, hasGpx: !!activity.gpx, geojson: activity.geojson ?? null, startedAt: activity.startedAt?.toISOString() ?? null, createdAt: activity.createdAt.toISOString(), importSource: activity.importSource, }, isOwner, routes: userRoutes.map((r) => ({ id: r.id, name: r.name })), }); } export async function action({ params, request }: Route.ActionArgs) { const user = await getSessionUser(request); if (!user) return redirect("/auth/login"); const formData = await request.formData(); const intent = formData.get("intent"); if (intent === "link-route") { const routeId = formData.get("routeId") as string; if (routeId) { await linkActivityToRoute(params.id, routeId, user.id); } return redirect(`/activities/${params.id}`); } if (intent === "create-route") { const routeId = await createRouteFromActivity(params.id, user.id); if (routeId) return redirect(`/routes/${routeId}`); return data({ error: "No GPX data to create route from" }, { status: 400 }); } if (intent === "delete") { await deleteImportByActivity(params.id); const deleted = await deleteActivity(params.id, user.id); if (deleted) return redirect("/activities"); return data({ error: "Activity not found" }, { status: 404 }); } return data({ error: "Unknown action" }, { status: 400 }); } export function meta({ data: loaderData }: Route.MetaArgs) { const name = (loaderData as { activity: { name: string } })?.activity?.name ?? "Activity"; return [{ title: `${name} — trails.cool` }]; } export default function ActivityDetailPage({ loaderData }: Route.ComponentProps) { const { activity, isOwner, routes } = loaderData; const { t } = useTranslation("journal"); return (
{activity.description}
)}{(activity.distance / 1000).toFixed(1)} km
Distance
↑ {activity.elevationGain} m
Ascent
↓ {activity.elevationLoss} m
Descent