diff --git a/.gitignore b/.gitignore index d9c7a05..a0ab227 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules dist build .env +.env.bck docs/* !docs/superpowers/ .superpowers diff --git a/adminsite/app/(customer)/instances/link/LinkForm.tsx b/adminsite/app/(customer)/instances/link/LinkForm.tsx index 361c9b7..4a4be8d 100644 --- a/adminsite/app/(customer)/instances/link/LinkForm.tsx +++ b/adminsite/app/(customer)/instances/link/LinkForm.tsx @@ -7,7 +7,16 @@ import { Field } from "@/components/Field"; const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; -export function LinkForm({ onLinked }: { onLinked: (instanceId: string) => void }) { +export function LinkForm({ + onLinked, + claimId, +}: { + onLinked: (instanceId: string) => void; + // When set, this is a PAID placeholder awaiting its real install UUID: claim + // it in place rather than creating a fresh (Free) instance. The name was + // chosen at checkout, so it is not asked for again. + claimId?: string; +}) { const [id, setId] = useState(""); const [name, setName] = useState(""); const [error, setError] = useState(); @@ -28,7 +37,9 @@ export function LinkForm({ onLinked }: { onLinked: (instanceId: string) => void setBusy(true); setError(undefined); try { - const inst = await api.link(value, name.trim()); + const inst = claimId + ? await api.claimLink(claimId, value) + : await api.link(value, name.trim()); onLinked(inst.instance_id); } catch (err) { setError( @@ -58,12 +69,14 @@ export function LinkForm({ onLinked }: { onLinked: (instanceId: string) => void } /> - setName(e.target.value)} - hint="So you can tell it apart from your other installs." - /> + {!claimId && ( + setName(e.target.value)} + hint="So you can tell it apart from your other installs." + /> + )} diff --git a/adminsite/app/(customer)/instances/link/page.tsx b/adminsite/app/(customer)/instances/link/page.tsx index 561fed3..538328e 100644 --- a/adminsite/app/(customer)/instances/link/page.tsx +++ b/adminsite/app/(customer)/instances/link/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useRouter } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; import { useQueryClient } from "@tanstack/react-query"; import { LinkForm } from "./LinkForm"; import { PageHeader } from "@/components/PageHeader"; @@ -8,6 +8,9 @@ import { PageHeader } from "@/components/PageHeader"; export default function LinkPage() { const router = useRouter(); const qc = useQueryClient(); + // A paid placeholder passes its id here so its install is claimed in place + // rather than a second, Free instance being created alongside it. + const claimId = useSearchParams().get("claim") ?? undefined; return (
@@ -17,6 +20,7 @@ export default function LinkPage() { subtitle="Every licence is tied to one install, so we need its ID before we can issue yours. Paste it below and your licence is ready on the next screen." /> { qc.invalidateQueries({ queryKey: ["account"] }); // Straight to the download, not back to a list: the licence is diff --git a/adminsite/components/InstanceRecord.tsx b/adminsite/components/InstanceRecord.tsx index 5115c9f..37720f2 100644 --- a/adminsite/components/InstanceRecord.tsx +++ b/adminsite/components/InstanceRecord.tsx @@ -221,7 +221,17 @@ export function InstanceRecord({
{state === "none" ? ( - Link an install + // A paid placeholder (awaiting_link) must CLAIM its install, not + // create a second Free instance beside it — so pass its id. + + Link an install + ) : cloud && instance.slug ? ( <>