Fix GPX export: use API route with direct download link

React Router page actions wrap responses, preventing raw file
downloads. Moved GPX export to GET /api/routes/:id/gpx and
changed the button to a plain <a download> link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-03-24 20:57:59 +01:00 committed by GitHub
parent 155d36e94c
commit 2e2dbe05c1
3 changed files with 24 additions and 20 deletions

View file

@ -14,5 +14,6 @@ export default [
route("routes/:id/edit", "routes/routes.$id.edit.tsx"),
route("api/routes/:id/callback", "routes/api.routes.$id.callback.ts"),
route("api/routes/:id/edit-in-planner", "routes/api.routes.$id.edit-in-planner.ts"),
route("api/routes/:id/gpx", "routes/api.routes.$id.gpx.ts"),
route("users/:username", "routes/users.$username.tsx"),
] satisfies RouteConfig;

View file

@ -0,0 +1,16 @@
import type { Route } from "./+types/api.routes.$id.gpx";
import { getRouteWithVersions } from "~/lib/routes.server";
export async function loader({ params }: Route.LoaderArgs) {
const route = await getRouteWithVersions(params.id);
if (!route?.gpx) {
return new Response("No GPX data", { status: 404 });
}
return new Response(route.gpx, {
headers: {
"Content-Type": "application/gpx+xml",
"Content-Disposition": `attachment; filename="${route.name.replace(/[^a-z0-9]/gi, "_")}.gpx"`,
},
});
}

View file

@ -62,18 +62,6 @@ export async function action({ params, request }: Route.ActionArgs) {
return redirect(`/routes/${params.id}`);
}
if (intent === "export-gpx") {
const route = await getRouteWithVersions(params.id);
if (!route?.gpx) return data({ error: "No GPX data" }, { status: 400 });
return new Response(route.gpx, {
headers: {
"Content-Type": "application/gpx+xml",
"Content-Disposition": `attachment; filename="${route.name.replace(/[^a-z0-9]/gi, "_")}.gpx"`,
},
});
}
return data({ error: "Unknown action" }, { status: 400 });
}
@ -123,16 +111,15 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {
>
Edit
</a>
<form method="post">
<input type="hidden" name="intent" value="export-gpx" />
<button
type="submit"
disabled={!route.hasGpx}
className="rounded-md border border-gray-300 px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-50 disabled:opacity-50"
{route.hasGpx && (
<a
href={`/api/routes/${route.id}/gpx`}
download
className="rounded-md border border-gray-300 px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-50"
>
Export GPX
</button>
</form>
</a>
)}
</div>
)}
</div>