trails/apps/planner/app/routes/new.tsx
Ullrich Schäfer 40e541fcce Implement Planner-Journal handoff (Group 9)
JWT-based handoff between Journal and Planner:

Journal side:
- JWT token generation scoped to route_id with 7-day expiry (jose)
- "Edit in Planner" button on route detail page — generates JWT,
  redirects to Planner /new with callback URL, token, and GPX
- Callback endpoint (POST /api/routes/:id/callback) validates JWT
  and creates new route version from received GPX

Planner side:
- /new route accepts callback, token, returnUrl, gpx params
- Creates session with callback metadata, initializes with GPX
- "Save to Journal" button POSTs GPX with Bearer token to callback
- "Return to Journal" link shown after successful save

All 6 Group 9 tasks complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:22:58 +00:00

36 lines
1.2 KiB
TypeScript

import { redirect } from "react-router";
import type { Route } from "./+types/new";
import { createSession, initializeSessionWithWaypoints } from "~/lib/sessions";
import { parseGpx } from "@trails-cool/gpx";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const callbackUrl = url.searchParams.get("callback");
const token = url.searchParams.get("token");
const returnUrl = url.searchParams.get("returnUrl");
const gpxEncoded = url.searchParams.get("gpx");
// Create a session with callback info
const session = await createSession({
callbackUrl: callbackUrl ?? undefined,
callbackToken: token ?? undefined,
});
// Initialize with GPX waypoints if provided
if (gpxEncoded) {
try {
const gpx = decodeURIComponent(gpxEncoded);
const gpxData = parseGpx(gpx);
initializeSessionWithWaypoints(session.id, gpxData.waypoints);
} catch {
// Continue with empty session if GPX is invalid
}
}
// Store returnUrl in the session URL for later
const sessionUrl = returnUrl
? `/session/${session.id}?returnUrl=${encodeURIComponent(returnUrl)}`
: `/session/${session.id}`;
return redirect(sessionUrl);
}