import React, { useState } from 'react'; import { InputControl } from '../../components/ui/input-control'; import { DismissibleAlert } from '../../components/ui/dismissible-alert'; import { Text } from '../../components/ui/text'; import { Spinner } from '../../components/ui/spinner'; import { adoptInstallationCode } from '../../utils/wpAdminApi'; /** * The other way onto this screen: a practice somebody has ALREADY set up on akashic.health. * * Enrolment mints a code, stamps it on the Organization and tells the contractor to hand it to the * practice - and until now it had nowhere to go, because the plugin only ever generated its own id. The * lookup was always BY CODE, so accepting one here is the whole of it. * * IT SITS BELOW THE SELF-SERVE FORM, NOT ABOVE IT, and that placement is the card's first control. * Creating a new organization is the normal path and the one most installs take. A code box in front of * it would ask every new practice to answer a question that does not apply to them, and the likeliest * reading of an unfamiliar field is that something is required. */ /** * The refusals, in the practice's own words, and they deliberately point in different directions. * * `already-adopted` is the one that has to say the most. It is not a typo and re-reading the code will * not help: this site is pointed at a practice and the code names a different one, so the honest next * step is to check which SITE you are on rather than which characters you copied. */ const REFUSALS = { // CORRECTED 2026-08-30, and this was the worst-placed instance of the wrong prefix. It told the // person their code should begin with "contractor:" while the server has only ever minted // "contractor-enrolled:" - so somebody holding a VALID code was refused and then coached into // editing it until it was genuinely broken. An error message that instructs is worse than one that // only reports, when the instruction is wrong. malformed: 'That does not look like an installation code. It should begin with "contractor-enrolled:" - check for a character lost when it was copied.', 'already-adopted': 'This site is already connected to a practice, so it will not be pointed at a different one. If that is wrong, disconnect it first - otherwise check whether you meant a different WordPress site.', unavailable: 'That could not be sent to WordPress. Nothing on this site was changed - check your connection and try again.', } as const; const AdoptInstallationCode: React.FC = () => { const [code, setCode] = useState(''); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const submit = async (event: React.FormEvent) => { event.preventDefault(); if (!code.trim() || busy) return; setBusy(true); setError(null); const outcome = await adoptInstallationCode(code.trim()); if (outcome.ok) { // A full reload rather than a state flip: the organization is resolved ONCE at boot from this // option, so the app has to start again to see the practice it now points at. Anything short // of that leaves a connected site still rendering the setup form. window.location.reload(); return; } setError(REFUSALS[outcome.reason]); setBusy(false); }; return (
Only for an IT contractor or web designer installing Akashic for a practice they already enrolled. Setting up your own practice? Ignore this and use the form above. Paste the installation code from enrolment. It connects this site to that practice instead of creating a second one. {error ? {error} : null} { setCode(next ?? ''); // Cleared as soon as they edit: a stale refusal sitting beside a field they have just // corrected reads as though the correction was rejected too. if (error) setError(null); }} /> ); }; export default AdoptInstallationCode;