Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 2x 20x 20x 20x 20x 20x 3x 3x 2x 2x 2x 1x 1x 1x 2x 20x 40x 6x | /**
* Terms acceptance — the one gate between signing in and working.
*
* Reskinned to the Job Book (redesign plan 4.2). Two changes beyond the paint:
* the two documents are ROWS that tint on hover rather than a pair of bordered
* tiles, and the tick is the `Checkbox` primitive rather than a raw
* `<input type="checkbox">` with an `accent-*` colour.
*
* The box and its sentence are siblings, not nested: the sentence carries two
* links, and the HTML spec makes a label do nothing for clicks on interactive
* descendants, so `htmlFor` is the honest wiring (the links navigate, the rest
* of the sentence ticks the box).
*/
import { useNavigate } from "@tanstack/react-router";
import { type FormEvent, useState } from "react";
import { AuthShell } from "../components/auth/auth-shell";
import { Button } from "../components/ui/button";
import { Card, CardContent } from "../components/ui/card";
import { Checkbox } from "../components/ui/checkbox";
import { authApi, getErrorMessage } from "../lib/api";
import { useAuth } from "../lib/auth-context";
import { MARKETPLACE_URL } from "../lib/env";
import { notify } from "../lib/notify";
import { CURRENT_TERMS_VERSION } from "../lib/terms";
const DOCUMENTS = [
{ label: "Terms of Use", path: "/terms" },
{ label: "Privacy Policy", path: "/privacy" },
] as const;
export function AcceptTermsPage() {
const { refreshSession } = useAuth();
const navigate = useNavigate();
const [agreed, setAgreed] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
if (!agreed || !CURRENT_TERMS_VERSION) return;
setIsLoading(true);
try {
await authApi.acceptTerms(CURRENT_TERMS_VERSION);
await refreshSession();
navigate({ to: "/" });
} catch (err) {
notify.error(getErrorMessage(err));
} finally {
setIsLoading(false);
}
};
return (
<AuthShell
title="Before you continue"
lead="We've added Terms of Use and a Privacy Policy to Interioring. Please take a moment to review them."
footer="You must accept to continue using Interioring."
>
<Card>
<ul className="border-b border-border-default">
{DOCUMENTS.map((doc) => (
<li
key={doc.path}
className="border-b border-border-default last:border-b-0"
>
<a
href={`${MARKETPLACE_URL}${doc.path}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-between gap-3 px-5 py-2.5 text-sm font-semibold text-foreground-default transition-colors hover:bg-background-muted"
>
{doc.label}
<span aria-hidden="true" className="text-foreground-subtle">
▸
</span>
</a>
</li>
))}
</ul>
<CardContent className="p-5">
<form onSubmit={handleSubmit}>
<div className="flex items-start gap-2.5">
<span className="mt-0.5">
<Checkbox
id="accept-terms"
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
/>
</span>
<label
htmlFor="accept-terms"
className="cursor-pointer text-sm leading-relaxed text-foreground-default"
>
I agree to the{" "}
<a
href={`${MARKETPLACE_URL}/terms`}
target="_blank"
rel="noopener noreferrer"
className="font-semibold underline decoration-2 underline-offset-4 hover:text-primary-600"
>
Terms of Use
</a>{" "}
and{" "}
<a
href={`${MARKETPLACE_URL}/privacy`}
target="_blank"
rel="noopener noreferrer"
className="font-semibold underline decoration-2 underline-offset-4 hover:text-primary-600"
>
Privacy Policy
</a>
</label>
</div>
<Button
type="submit"
className="mt-5 w-full"
disabled={!agreed}
isLoading={isLoading}
>
Accept and continue
</Button>
</form>
</CardContent>
</Card>
</AuthShell>
);
}
|