domain change
This commit is contained in:
@@ -1,90 +1,63 @@
|
||||
import type { ConsoleRole } from './roles';
|
||||
|
||||
/**
|
||||
* Which console this build is.
|
||||
* Who may sign in to the merchant console.
|
||||
*
|
||||
* ── Why one codebase produces two sites ─────────────────────────────────────
|
||||
* ── Why this is a constant ──────────────────────────────────────────────────
|
||||
*
|
||||
* Nearle's own staff work at `platform.nearledaily.com`; merchants and their
|
||||
* branch users work at `app.nearledaily.com`. They are the same application
|
||||
* built twice with this flag set differently, rather than two repositories,
|
||||
* because every screen below the workspace split — drawers, tables, the
|
||||
* assistant, the design system — is shared and would otherwise be maintained
|
||||
* in two places and drift.
|
||||
* There was a `VITE_WORKSPACE` build flag here while one codebase served both
|
||||
* consoles and had to be told which it was. That is over: Nearle's own staff
|
||||
* have their own application, `nearle-platform`, and this repository is the
|
||||
* merchant console and nothing else. A flag would only be a way to deploy this
|
||||
* application as something it is not.
|
||||
*
|
||||
* What the flag changes is which routes are mounted and which roles may sign
|
||||
* in. It does not change what is compiled: the branch in `App.tsx` is evaluated
|
||||
* at runtime, so both workspaces' chunks are built and served, and the
|
||||
* unmounted one is simply never fetched because nothing routes to it. Removing
|
||||
* it from the bundle would need the flag to be a literal at each import site,
|
||||
* which is a separate piece of work and buys nothing for access control.
|
||||
* ── The separation is a refusal, not a redirect ─────────────────────────────
|
||||
*
|
||||
* ── The default is `merchant`, deliberately ─────────────────────────────────
|
||||
* A Nearle staff account is turned away here with a sentence naming where it
|
||||
* belongs. It is not bounced to the other site carrying a half-made session.
|
||||
*
|
||||
* An unset variable is the ordinary state of a developer's machine and of any
|
||||
* deployment that has not been told about this yet. Defaulting to `merchant`
|
||||
* means the existing site keeps behaving exactly as it did, and the platform
|
||||
* build is the one that has to be asked for. The opposite default would turn
|
||||
* every un-migrated environment into a platform console the day this shipped.
|
||||
* The role is not known until the password has been checked — `applogin`
|
||||
* returns it — so the refusal can only happen after credentials are verified.
|
||||
* `login` applies it BEFORE the session is written and `restore` applies it to
|
||||
* what is already stored. That order is the point: a session persisted first
|
||||
* and refused afterwards leaves somebody signed in by every measure the shell
|
||||
* uses, with a nav built from a role this application serves no routes for.
|
||||
*/
|
||||
export type Workspace = 'platform' | 'merchant';
|
||||
export const WORKSPACE = 'merchant' as const;
|
||||
|
||||
const CONFIGURED = (import.meta.env?.['VITE_WORKSPACE'] ?? '').trim().toLowerCase();
|
||||
|
||||
export const WORKSPACE: Workspace = CONFIGURED === 'platform' ? 'platform' : 'merchant';
|
||||
|
||||
export const IS_PLATFORM = WORKSPACE === 'platform';
|
||||
|
||||
/**
|
||||
* Who may sign in here.
|
||||
*
|
||||
* The separation is a REFUSAL, not a redirect. A merchant reaching the platform
|
||||
* console is told which console their account belongs to and stays where they
|
||||
* are; they are not bounced across a domain boundary carrying a half-made
|
||||
* session. Each site serves exactly one audience and says so.
|
||||
*/
|
||||
const ALLOWED: Record<Workspace, ReadonlySet<ConsoleRole>> = {
|
||||
platform: new Set<ConsoleRole>(['nearle-admin']),
|
||||
merchant: new Set<ConsoleRole>(['store-admin', 'store-manager']),
|
||||
};
|
||||
const ALLOWED: ReadonlySet<ConsoleRole> = new Set<ConsoleRole>(['store-admin', 'store-manager']);
|
||||
|
||||
export function isAllowedHere(role: ConsoleRole): boolean {
|
||||
return ALLOWED[WORKSPACE].has(role);
|
||||
return ALLOWED.has(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* The other console's address, for the sentence shown to somebody in the wrong
|
||||
* place.
|
||||
* The platform console's address, for the sentence shown to a staff member who
|
||||
* signs in at the wrong site.
|
||||
*
|
||||
* Named rather than derived from `location.hostname`, because the two sites are
|
||||
* not a naming convention apart — they are separate deployments and either can
|
||||
* move. A build that was not told falls back to the production hostnames, which
|
||||
* is right far more often than saying nothing.
|
||||
* A build variable rather than a constant, because the two are separate
|
||||
* deployments and either can move. The fallback is the production hostname,
|
||||
* which is right far more often than saying nothing would be.
|
||||
*/
|
||||
const OTHER_SITE: Record<Workspace, string> = {
|
||||
platform: (import.meta.env?.['VITE_MERCHANT_HOST'] ?? '').trim() || 'app.nearledaily.com',
|
||||
merchant: (import.meta.env?.['VITE_PLATFORM_HOST'] ?? '').trim() || 'platform.nearledaily.com',
|
||||
};
|
||||
const PLATFORM_HOST =
|
||||
(import.meta.env?.['VITE_PLATFORM_HOST'] ?? '').trim() || 'platform.nearledaily.com';
|
||||
|
||||
/**
|
||||
* What to tell somebody whose account belongs to the other console.
|
||||
*
|
||||
* Names the host rather than linking to it. A live link from a sign-in screen
|
||||
* to another sign-in screen reads as a redirect that failed, and this is not a
|
||||
* failure — it is the right answer to the wrong door.
|
||||
* Names the host rather than linking to it. A live link from one sign-in screen
|
||||
* to another reads as a redirect that failed, and this is not a failure — it is
|
||||
* the right answer to the wrong door.
|
||||
*/
|
||||
export function wrongConsoleMessage(role: ConsoleRole): string {
|
||||
const site = OTHER_SITE[WORKSPACE];
|
||||
|
||||
return IS_PLATFORM
|
||||
? `This is the Nearle platform console. ${roleWord(role)} accounts sign in at ${site}.`
|
||||
: `${roleWord(role)} accounts sign in at ${site}, not here.`;
|
||||
return `${roleWord(role)} accounts sign in at ${PLATFORM_HOST}, not here.`;
|
||||
}
|
||||
|
||||
function roleWord(role: ConsoleRole): string {
|
||||
switch (role) {
|
||||
case 'nearle-admin':
|
||||
return 'Nearle staff';
|
||||
// Unreachable: both merchant roles are allowed here, so neither reaches the
|
||||
// refusal. Present because the switch is exhaustive over the union and a
|
||||
// missing arm would be a type error the day a role is added.
|
||||
case 'store-admin':
|
||||
return 'Store admin';
|
||||
case 'store-manager':
|
||||
|
||||
Reference in New Issue
Block a user