Code
    RPS Digital P3 Intake ArchiveUpdated May 10, 2026TSX

    RPS Digital P3 Intake Archive Apps.Downloads.$Token source

    Imported React file from ../../app/app/routes/apps.downloads.$token.tsx.

    Source file

    ../../app/app/routes/apps.downloads.$token.tsx

    React61 lines
    1. import { json, type LoaderFunctionArgs } from '@remix-run/node';
    2. import { useLoaderData } from '@remix-run/react';
    3. import { getEntitlementByToken, getAssetsByRelease } from '../db.server';
    4. import { getSignedUrl } from '../storage.server';
    5. export async function loader({ params }: LoaderFunctionArgs) {
    6. const token = params.token || '';
    7. const entitlement = getEntitlementByToken(token);
    8. if (!entitlement) {
    9. return json({ error: 'Invalid token' }, { status: 404 });
    10. }
    11. const expiresAtMs = Date.parse(String(entitlement.expires_at || ''));
    12. if (!Number.isFinite(expiresAtMs)) {
    13. return json({ error: 'Invalid token' }, { status: 404 });
    14. }
    15. if (expiresAtMs <= Date.now()) {
    16. return json({ error: 'Expired token' }, { status: 410 });
    17. }
    18. if (!entitlement.release_id || entitlement.release_id === 'unknown-release') {
    19. return json({ error: 'Invalid entitlement release mapping' }, { status: 404 });
    20. }
    21. const assets = getAssetsByRelease(entitlement.release_id);
    22. if (!assets.length) {
    23. return json({ error: 'No downloadable assets available for this entitlement' }, { status: 404 });
    24. }
    25. const urls = await Promise.all(
    26. assets.map(async (asset: any) => ({
    27. key: asset.key,
    28. label: asset.variant_label,
    29. url: await getSignedUrl(asset.key, 24 * 60 * 60),
    30. }))
    31. );
    32. return json({ entitlement, urls });
    33. }
    34. export default function DownloadPage() {
    35. const data = useLoaderData<typeof loader>();
    36. if ('error' in data) {
    37. return <div>Invalid or expired link.</div>;
    38. }
    39. return (
    40. <div style={{ fontFamily: 'system-ui', padding: '2rem' }}>
    41. <h1>Your Digital Downloads</h1>
    42. <p>Links will expire in 24 hours.</p>
    43. <ul>
    44. {data.urls.map((item: { key: string; url: string; label: string }) => (
    45. <li key={item.key}>
    46. <a href={item.url} rel="noreferrer">
    47. {item.label}
    48. </a>
    49. </li>
    50. ))}
    51. </ul>
    52. </div>
    53. );
    54. }