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:
parent
155d36e94c
commit
2e2dbe05c1
3 changed files with 24 additions and 20 deletions
|
|
@ -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;
|
||||
|
|
|
|||
16
apps/journal/app/routes/api.routes.$id.gpx.ts
Normal file
16
apps/journal/app/routes/api.routes.$id.gpx.ts
Normal 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"`,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue