| 1 | /** |
| 2 | * `POST -/home/seen` with `{ "at": <epoch ms> }`: Home marks the viewer's |
| 3 | * visit once the page has been in view for a few seconds, with the time it |
| 4 | * loaded (routes/workspace/home.tsx). Notify keeps it per person and |
| 5 | * workspace and only moves it forward. |
| 6 | */ |
| 7 | import { data } from "react-router"; |
| 8 | |
| 9 | import type { Route } from "./+types/home-seen"; |
| 10 | import { markVisit } from "../../lib/home.server"; |
| 11 | import { assertSameOrigin, requireUser, roleIn } from "../../lib/session.server"; |
| 12 | |
| 13 | export async function action({ params, context, request }: Route.ActionArgs) { |
| 14 | if (request.method !== "POST") throw data(null, { status: 405 }); |
| 15 | assertSameOrigin(request); |
| 16 | const viewer = requireUser(context, request); |
| 17 | const slug = params.owner.toLowerCase(); |
| 18 | if (!roleIn(viewer, slug)) throw data(null, { status: 404 }); |
| 19 | const sent = (await request.json().catch(() => ({}))) as { at?: unknown }; |
| 20 | const at = typeof sent.at === "number" && Number.isFinite(sent.at) ? Math.min(sent.at, Date.now()) : Date.now(); |
| 21 | const ok = await markVisit(viewer, slug, at); |
| 22 | return new Response(null, { status: ok ? 204 : 503, headers: { "cache-control": "no-store" } }); |
| 23 | } |