@the-portland-company/shell 0.75.1 → 0.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/active-org.cjs +119 -0
- package/dist/active-org.cjs.map +1 -1
- package/dist/active-org.d.cts +62 -2
- package/dist/active-org.d.ts +62 -2
- package/dist/active-org.js +1 -1
- package/dist/app-chrome.cjs +222 -20
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +34 -2
- package/dist/app-chrome.d.ts +34 -2
- package/dist/app-chrome.js +133 -18
- package/dist/app-chrome.js.map +1 -1
- package/dist/chrome.css +17 -5
- package/dist/chunk-BWV52AT6.js +171 -0
- package/dist/chunk-BWV52AT6.js.map +1 -0
- package/dist/{chunk-AQMSMAK2.js → chunk-WHF6YW27.js} +16 -8
- package/dist/chunk-WHF6YW27.js.map +1 -0
- package/dist/native.cjs +14 -6
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +8 -2
- package/dist/native.d.ts +8 -2
- package/dist/native.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AQMSMAK2.js.map +0 -1
- package/dist/chunk-W2HITMV5.js +0 -64
- package/dist/chunk-W2HITMV5.js.map +0 -1
package/dist/app-chrome.d.cts
CHANGED
|
@@ -188,6 +188,8 @@ type PolitogyFrameData = {
|
|
|
188
188
|
devNotes?: ChromeDevNotesConfig;
|
|
189
189
|
/** Controlled org state for apps that own active-org + switching. */
|
|
190
190
|
org?: ControlledOrgState;
|
|
191
|
+
/** Auth-owned active org from verified token claims (v2). Wins over `org`. */
|
|
192
|
+
tokenOrg?: TokenOrgState;
|
|
191
193
|
/**
|
|
192
194
|
* App-owned children for a standard nav entry this app owns (Contacts).
|
|
193
195
|
* `count` is the live contact total, pre-formatted ("31.9K"), drawn
|
|
@@ -393,6 +395,34 @@ type ControlledOrgState = {
|
|
|
393
395
|
*/
|
|
394
396
|
onExternalSwitch?: (id: string) => void;
|
|
395
397
|
};
|
|
398
|
+
/**
|
|
399
|
+
* Auth-owned active org (Global-Rules v38, UI-Platform v46). The app server
|
|
400
|
+
* passes the VERIFIED token claims; the shell never resolves the org itself.
|
|
401
|
+
*/
|
|
402
|
+
type TokenOrgState = {
|
|
403
|
+
/** `org_id` claim from the app's verified token (full uuid). */
|
|
404
|
+
orgId: string | null;
|
|
405
|
+
/** `org_role` claim (raw VRM Core role). */
|
|
406
|
+
orgRole?: string | null;
|
|
407
|
+
/**
|
|
408
|
+
* The switcher list from the app server (names for the pill). When given,
|
|
409
|
+
* the chrome `/api/orgs` call is skipped. When absent it is the fallback.
|
|
410
|
+
*/
|
|
411
|
+
orgs?: (NavOrgOption & {
|
|
412
|
+
rawRole?: string | null;
|
|
413
|
+
})[];
|
|
414
|
+
/**
|
|
415
|
+
* Server action that re-exchanges for tokens on `orgId`. Called after the
|
|
416
|
+
* IdP accepted the switch (shared) or for a per-tab override (`perTab`).
|
|
417
|
+
*/
|
|
418
|
+
onReexchange: (orgId: string, opts: {
|
|
419
|
+
perTab: boolean;
|
|
420
|
+
}) => void | Promise<void>;
|
|
421
|
+
/** IdP base override (default: auth / auth-staging by host). */
|
|
422
|
+
authBaseUrl?: string;
|
|
423
|
+
/** Called when the IdP refuses a switch (403 not a member, 401 no session). */
|
|
424
|
+
onSwitchError?: (err: unknown) => void;
|
|
425
|
+
};
|
|
396
426
|
type ChromeDevNotesConfig = {
|
|
397
427
|
/** Override the DevNotes API base (default: `${proxyBasePath}/devnotes`). */
|
|
398
428
|
basePath?: string;
|
|
@@ -417,7 +447,7 @@ type ChromeDevNotesConfig = {
|
|
|
417
447
|
* <ShellFrame …/>
|
|
418
448
|
* </PolitogyAppChrome>
|
|
419
449
|
*/
|
|
420
|
-
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, devNotes, org, identity, children, }: {
|
|
450
|
+
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, devNotes, org, tokenOrg, identity, children, }: {
|
|
421
451
|
storagePrefix: string;
|
|
422
452
|
proxyBasePath?: string;
|
|
423
453
|
/**
|
|
@@ -430,6 +460,8 @@ declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fe
|
|
|
430
460
|
devNotes?: ChromeDevNotesConfig;
|
|
431
461
|
/** Controlled org state — the app owns active-org + switching (Contacts). */
|
|
432
462
|
org?: ControlledOrgState;
|
|
463
|
+
/** Auth-owned active org from verified token claims (v2). Wins over `org`. */
|
|
464
|
+
tokenOrg?: TokenOrgState;
|
|
433
465
|
identity: ChromeIdentity;
|
|
434
466
|
children: ReactNode;
|
|
435
467
|
}): react_jsx_runtime.JSX.Element;
|
|
@@ -502,4 +534,4 @@ type UseChromeModeArg = ModeId | {
|
|
|
502
534
|
*/
|
|
503
535
|
declare function useChromeMode(arg?: UseChromeModeArg): NavMode;
|
|
504
536
|
|
|
505
|
-
export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, deriveBreadcrumbs, looksLikeEmail, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
|
|
537
|
+
export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, looksLikeEmail, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
|
package/dist/app-chrome.d.ts
CHANGED
|
@@ -188,6 +188,8 @@ type PolitogyFrameData = {
|
|
|
188
188
|
devNotes?: ChromeDevNotesConfig;
|
|
189
189
|
/** Controlled org state for apps that own active-org + switching. */
|
|
190
190
|
org?: ControlledOrgState;
|
|
191
|
+
/** Auth-owned active org from verified token claims (v2). Wins over `org`. */
|
|
192
|
+
tokenOrg?: TokenOrgState;
|
|
191
193
|
/**
|
|
192
194
|
* App-owned children for a standard nav entry this app owns (Contacts).
|
|
193
195
|
* `count` is the live contact total, pre-formatted ("31.9K"), drawn
|
|
@@ -393,6 +395,34 @@ type ControlledOrgState = {
|
|
|
393
395
|
*/
|
|
394
396
|
onExternalSwitch?: (id: string) => void;
|
|
395
397
|
};
|
|
398
|
+
/**
|
|
399
|
+
* Auth-owned active org (Global-Rules v38, UI-Platform v46). The app server
|
|
400
|
+
* passes the VERIFIED token claims; the shell never resolves the org itself.
|
|
401
|
+
*/
|
|
402
|
+
type TokenOrgState = {
|
|
403
|
+
/** `org_id` claim from the app's verified token (full uuid). */
|
|
404
|
+
orgId: string | null;
|
|
405
|
+
/** `org_role` claim (raw VRM Core role). */
|
|
406
|
+
orgRole?: string | null;
|
|
407
|
+
/**
|
|
408
|
+
* The switcher list from the app server (names for the pill). When given,
|
|
409
|
+
* the chrome `/api/orgs` call is skipped. When absent it is the fallback.
|
|
410
|
+
*/
|
|
411
|
+
orgs?: (NavOrgOption & {
|
|
412
|
+
rawRole?: string | null;
|
|
413
|
+
})[];
|
|
414
|
+
/**
|
|
415
|
+
* Server action that re-exchanges for tokens on `orgId`. Called after the
|
|
416
|
+
* IdP accepted the switch (shared) or for a per-tab override (`perTab`).
|
|
417
|
+
*/
|
|
418
|
+
onReexchange: (orgId: string, opts: {
|
|
419
|
+
perTab: boolean;
|
|
420
|
+
}) => void | Promise<void>;
|
|
421
|
+
/** IdP base override (default: auth / auth-staging by host). */
|
|
422
|
+
authBaseUrl?: string;
|
|
423
|
+
/** Called when the IdP refuses a switch (403 not a member, 401 no session). */
|
|
424
|
+
onSwitchError?: (err: unknown) => void;
|
|
425
|
+
};
|
|
396
426
|
type ChromeDevNotesConfig = {
|
|
397
427
|
/** Override the DevNotes API base (default: `${proxyBasePath}/devnotes`). */
|
|
398
428
|
basePath?: string;
|
|
@@ -417,7 +447,7 @@ type ChromeDevNotesConfig = {
|
|
|
417
447
|
* <ShellFrame …/>
|
|
418
448
|
* </PolitogyAppChrome>
|
|
419
449
|
*/
|
|
420
|
-
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, devNotes, org, identity, children, }: {
|
|
450
|
+
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, devNotes, org, tokenOrg, identity, children, }: {
|
|
421
451
|
storagePrefix: string;
|
|
422
452
|
proxyBasePath?: string;
|
|
423
453
|
/**
|
|
@@ -430,6 +460,8 @@ declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fe
|
|
|
430
460
|
devNotes?: ChromeDevNotesConfig;
|
|
431
461
|
/** Controlled org state — the app owns active-org + switching (Contacts). */
|
|
432
462
|
org?: ControlledOrgState;
|
|
463
|
+
/** Auth-owned active org from verified token claims (v2). Wins over `org`. */
|
|
464
|
+
tokenOrg?: TokenOrgState;
|
|
433
465
|
identity: ChromeIdentity;
|
|
434
466
|
children: ReactNode;
|
|
435
467
|
}): react_jsx_runtime.JSX.Element;
|
|
@@ -502,4 +534,4 @@ type UseChromeModeArg = ModeId | {
|
|
|
502
534
|
*/
|
|
503
535
|
declare function useChromeMode(arg?: UseChromeModeArg): NavMode;
|
|
504
536
|
|
|
505
|
-
export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, deriveBreadcrumbs, looksLikeEmail, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
|
|
537
|
+
export { type BootPhase, type BootProgress, type BootStageId, type ChromeDevNotesConfig, type ChromeIdentity, ChromeTopBarActions, type ControlledOrgState, LoadingScreen, POLITOGY_APPS, PolitogyAppChrome, PolitogyAppFrame, type PolitogyAppKey, type PolitogyAppMode, type PolitogyAppSession, type PolitogyBuildMeta, type PolitogyFrameData, type PolitogyFrameGrant, type PolitogyGrantedFrame, type ResolvedIdentity, type TokenOrgState, deriveBreadcrumbs, looksLikeEmail, resolveIdentity, standardNavIcons, useChromeFooter, useChromeIdentity, useChromeMode, useChromeState, useChromeUserMenu, useIsSuperAdmin };
|
package/dist/app-chrome.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { broadcastLogout, watchLogout } from './chunk-LL6LSJAH.js';
|
|
3
|
-
import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-
|
|
4
|
-
export { standardNavIcons } from './chunk-
|
|
3
|
+
import { clearBetaBannerDismissal, standardPolitogyNav, standardNavIcons, isNavItemActive, NavAppShell, NavChromeProvider, TopBarWidgetSlot, FuelAction, SpecOverlayAction, NotificationsAction, SupportAction, useChromeMe, useThemePreference, useNavChromeFetcher, useChromeOrgs } from './chunk-WHF6YW27.js';
|
|
4
|
+
export { standardNavIcons } from './chunk-WHF6YW27.js';
|
|
5
5
|
import { warnDeprecated } from './chunk-MY6G3LMN.js';
|
|
6
6
|
import './chunk-BHRVZPZ7.js';
|
|
7
|
-
import { NAV_DISPLAY_DEFAULT, resolveNavDisplay,
|
|
8
|
-
import {
|
|
7
|
+
import { NAV_DISPLAY_DEFAULT, resolveNavDisplay, writeNavDisplayLocal, writeNavDisplayCookie, isNavDisplayPreference, NAV_DISPLAY_STORAGE_KEY, readNavDisplayCookie } from './chunk-7YVJ7HQG.js';
|
|
8
|
+
import { readOrgSelectorFromUrl, matchOrgSelector, isOrgId, switchActiveOrg, ACTIVE_ORG_QUERY_PARAM, ORG_ID_QUERY_PARAM, orgIdTail, writeActiveOrgCookie, resolveActiveOrg, readActiveOrgCookie } from './chunk-BWV52AT6.js';
|
|
9
9
|
import { createContext, useMemo, useRef, useEffect, useState, useCallback, useContext } from 'react';
|
|
10
10
|
import { DevNotesMenu, createDevNotesClient, DevNotesProvider, DevNotesTaskListModal, DevNotesOverlay } from '@the-portland-company/devnotes';
|
|
11
11
|
import { LuNotebookPen, LuContactRound, LuMegaphone, LuFilePenLine } from 'react-icons/lu';
|
|
@@ -427,7 +427,9 @@ function LoadingScreen({
|
|
|
427
427
|
padding: 0,
|
|
428
428
|
border: "none",
|
|
429
429
|
background: "transparent",
|
|
430
|
-
|
|
430
|
+
// 0.38 alpha was 3.51:1 on the ink-900 loading background —
|
|
431
|
+
// below WCAG 2.2 AA 4.5:1. 0.72 clears it.
|
|
432
|
+
color: "rgba(255,255,255,0.72)",
|
|
431
433
|
fontFamily: "var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif)",
|
|
432
434
|
fontSize: "12.5px",
|
|
433
435
|
textDecoration: "underline",
|
|
@@ -454,7 +456,9 @@ function LoadingScreen({
|
|
|
454
456
|
padding: "0 32px 30px",
|
|
455
457
|
fontFamily: "var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif)",
|
|
456
458
|
fontSize: "12.5px",
|
|
457
|
-
|
|
459
|
+
// 0.38 alpha was 3.51:1 on the ink-900 loading background — below
|
|
460
|
+
// WCAG 2.2 AA 4.5:1. 0.72 clears it.
|
|
461
|
+
color: "rgba(255,255,255,0.72)"
|
|
458
462
|
},
|
|
459
463
|
children: [
|
|
460
464
|
/* @__PURE__ */ jsx("span", { children: "Politogy VRM. Built for the long game." }),
|
|
@@ -522,11 +526,17 @@ var POLITOGY_APPS = {
|
|
|
522
526
|
storagePrefix: "contacts",
|
|
523
527
|
pageTitle: false
|
|
524
528
|
},
|
|
525
|
-
|
|
526
|
-
|
|
529
|
+
// 'title' for forms/surveys/polls/ctas for the same reason as petitions
|
|
530
|
+
// below: their pages have real names ("Volunteer Signup", "Q3 Satisfaction"),
|
|
531
|
+
// where the registry can only say the app's own name. Without the grant the
|
|
532
|
+
// page header falls back to the static registry title forever, so the
|
|
533
|
+
// designed "<mode> mode" eyebrow + H2 + subtitle block never gets the real
|
|
534
|
+
// per-page title an app passes it (UI-Platform → Page header).
|
|
535
|
+
forms: { title: "Forms", origin: "https://forms.politogyvrm.com", storagePrefix: "forms", grants: ["title"] },
|
|
536
|
+
surveys: { title: "Surveys", origin: "https://surveys.politogyvrm.com", storagePrefix: "surveys", grants: ["title"] },
|
|
527
537
|
// Specs/Left-Navigation §9.2: Polling is a Campaign row (Research).
|
|
528
|
-
polls: { title: "Polls", origin: "https://polls.politogyvrm.com", storagePrefix: "polls", mode: "campaign" },
|
|
529
|
-
ctas: { title: "CTAs", origin: "https://ctas.politogyvrm.com", storagePrefix: "ctas" },
|
|
538
|
+
polls: { title: "Polls", origin: "https://polls.politogyvrm.com", storagePrefix: "polls", mode: "campaign", grants: ["title"] },
|
|
539
|
+
ctas: { title: "CTAs", origin: "https://ctas.politogyvrm.com", storagePrefix: "ctas", grants: ["title"] },
|
|
530
540
|
// V2 apps that replace retired app.politogyvrm.com pages (Reference/
|
|
531
541
|
// UI-Platform v42 "Retirement of app.politogyvrm.com"). Dashboard hosts the
|
|
532
542
|
// Relationship Dashboard + Campaign Battleground/District data/Campaigns
|
|
@@ -550,7 +560,7 @@ var POLITOGY_APPS = {
|
|
|
550
560
|
},
|
|
551
561
|
// Relationship Mode Email Engine (Specs/Email-Engine) — the V2 standalone
|
|
552
562
|
// app, running in parallel to VRM core's V1 Email Broadcast.
|
|
553
|
-
email: { title: "Email", origin: "https://email.politogyvrm.com", storagePrefix: "email", mode: "relationship" },
|
|
563
|
+
email: { title: "Email", origin: "https://email.politogyvrm.com", storagePrefix: "email", mode: "relationship", grants: ["title"] },
|
|
554
564
|
// Campaign Mode apps — each scoped to Campaign, so they render the Campaign
|
|
555
565
|
// tree and a static Campaign pill. Not yet deployed; hidden from the Campaign
|
|
556
566
|
// nav by CAMPAIGN_FEATURE_AVAILABILITY until their launch flips the flag.
|
|
@@ -563,11 +573,12 @@ var POLITOGY_APPS = {
|
|
|
563
573
|
origin: "https://a2p.politogyvrm.com",
|
|
564
574
|
storagePrefix: "a2p",
|
|
565
575
|
mode: "campaign",
|
|
566
|
-
dual: { modes: ["relationship", "campaign"], defaultMode: "campaign" }
|
|
576
|
+
dual: { modes: ["relationship", "campaign"], defaultMode: "campaign" },
|
|
577
|
+
grants: ["title"]
|
|
567
578
|
},
|
|
568
|
-
phonebank: { title: "Phone Banking", origin: "https://phonebank.politogyvrm.com", storagePrefix: "phonebank", mode: "campaign" },
|
|
569
|
-
canvass: { title: "Field Canvassing", origin: "https://canvass.politogyvrm.com", storagePrefix: "canvass", mode: "campaign" },
|
|
570
|
-
signs: { title: "Sign Mapping", origin: "https://signs.politogyvrm.com", storagePrefix: "signs", mode: "campaign" }
|
|
579
|
+
phonebank: { title: "Phone Banking", origin: "https://phonebank.politogyvrm.com", storagePrefix: "phonebank", mode: "campaign", grants: ["title"] },
|
|
580
|
+
canvass: { title: "Field Canvassing", origin: "https://canvass.politogyvrm.com", storagePrefix: "canvass", mode: "campaign", grants: ["title"] },
|
|
581
|
+
signs: { title: "Sign Mapping", origin: "https://signs.politogyvrm.com", storagePrefix: "signs", mode: "campaign", grants: ["title"] }
|
|
571
582
|
};
|
|
572
583
|
var DEFAULT_SEARCH_PLACEHOLDER = {
|
|
573
584
|
contacts: "Search contacts, segments, forms"
|
|
@@ -594,6 +605,7 @@ function PolitogyAppFrame({
|
|
|
594
605
|
fetchJson: data?.fetchJson,
|
|
595
606
|
devNotes: data?.devNotes,
|
|
596
607
|
org: data?.org,
|
|
608
|
+
tokenOrg: data?.tokenOrg,
|
|
597
609
|
identity: {
|
|
598
610
|
userId: session.userId,
|
|
599
611
|
userName: session.userName ?? null,
|
|
@@ -874,6 +886,107 @@ var ChromeStateContext = createContext(null);
|
|
|
874
886
|
function useChromeState() {
|
|
875
887
|
return useContext(ChromeStateContext);
|
|
876
888
|
}
|
|
889
|
+
function TokenChromeStateProvider({
|
|
890
|
+
tokenOrg,
|
|
891
|
+
children
|
|
892
|
+
}) {
|
|
893
|
+
const { orgs: fetchedOrgs, loading: orgsFetching, error: orgsError } = useChromeOrgs({
|
|
894
|
+
enabled: !tokenOrg.orgs
|
|
895
|
+
});
|
|
896
|
+
const [navDisplay, setNavDisplayState] = useState(NAV_DISPLAY_DEFAULT);
|
|
897
|
+
const [pendingOrg, setPendingOrg] = useState(null);
|
|
898
|
+
const tokenOrgRef = useRef(tokenOrg);
|
|
899
|
+
tokenOrgRef.current = tokenOrg;
|
|
900
|
+
useEffect(() => {
|
|
901
|
+
setNavDisplayState(resolveNavDisplay());
|
|
902
|
+
}, []);
|
|
903
|
+
const orgs = useMemo(
|
|
904
|
+
() => tokenOrg.orgs ?? (fetchedOrgs ?? []).map((o) => ({
|
|
905
|
+
id: o.id,
|
|
906
|
+
name: o.name,
|
|
907
|
+
logoUrl: o.logoUrl,
|
|
908
|
+
brandColor: o.brandColor,
|
|
909
|
+
role: o.role,
|
|
910
|
+
rawRole: o.rawRole ?? null
|
|
911
|
+
})),
|
|
912
|
+
[tokenOrg.orgs, fetchedOrgs]
|
|
913
|
+
);
|
|
914
|
+
const [urlSelector] = useState(
|
|
915
|
+
() => typeof window === "undefined" ? null : readOrgSelectorFromUrl(window.location.search)
|
|
916
|
+
);
|
|
917
|
+
const overrideOrg = useMemo(
|
|
918
|
+
() => urlSelector ? matchOrgSelector(urlSelector, orgs)?.id ?? null : null,
|
|
919
|
+
[urlSelector, orgs]
|
|
920
|
+
);
|
|
921
|
+
const orgId = pendingOrg ?? (tokenOrg.orgId && overrideOrg ? overrideOrg : tokenOrg.orgId);
|
|
922
|
+
const reexchangedFor = useRef(null);
|
|
923
|
+
useEffect(() => {
|
|
924
|
+
if (!overrideOrg || !tokenOrg.orgId || overrideOrg === tokenOrg.orgId) return;
|
|
925
|
+
if (reexchangedFor.current === overrideOrg) return;
|
|
926
|
+
reexchangedFor.current = overrideOrg;
|
|
927
|
+
void Promise.resolve(tokenOrgRef.current.onReexchange(overrideOrg, { perTab: true })).catch(
|
|
928
|
+
() => {
|
|
929
|
+
}
|
|
930
|
+
);
|
|
931
|
+
}, [overrideOrg, tokenOrg.orgId]);
|
|
932
|
+
useEffect(() => {
|
|
933
|
+
if (pendingOrg && tokenOrg.orgId === pendingOrg) setPendingOrg(null);
|
|
934
|
+
}, [pendingOrg, tokenOrg.orgId]);
|
|
935
|
+
const setOrgId = useCallback((id) => {
|
|
936
|
+
const current = tokenOrgRef.current;
|
|
937
|
+
if (!isOrgId(id) || id === (current.orgId ?? null)) return;
|
|
938
|
+
setPendingOrg(id);
|
|
939
|
+
void (async () => {
|
|
940
|
+
try {
|
|
941
|
+
const claims = await switchActiveOrg(id, { authBaseUrl: current.authBaseUrl });
|
|
942
|
+
try {
|
|
943
|
+
const url = new URL(window.location.href);
|
|
944
|
+
url.searchParams.delete(ACTIVE_ORG_QUERY_PARAM);
|
|
945
|
+
url.searchParams.set(ORG_ID_QUERY_PARAM, orgIdTail(claims.orgId));
|
|
946
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
947
|
+
} catch {
|
|
948
|
+
}
|
|
949
|
+
await tokenOrgRef.current.onReexchange(claims.orgId, { perTab: false });
|
|
950
|
+
} catch (err) {
|
|
951
|
+
setPendingOrg(null);
|
|
952
|
+
tokenOrgRef.current.onSwitchError?.(err);
|
|
953
|
+
}
|
|
954
|
+
})();
|
|
955
|
+
}, []);
|
|
956
|
+
const setNavDisplay = useCallback((m) => {
|
|
957
|
+
setNavDisplayState(m);
|
|
958
|
+
writeNavDisplayLocal(m);
|
|
959
|
+
writeNavDisplayCookie(m);
|
|
960
|
+
}, []);
|
|
961
|
+
useEffect(() => {
|
|
962
|
+
if (!isOrgId(orgId)) return;
|
|
963
|
+
try {
|
|
964
|
+
const url = new URL(window.location.href);
|
|
965
|
+
const tail = orgIdTail(orgId);
|
|
966
|
+
if (url.searchParams.has(ACTIVE_ORG_QUERY_PARAM) || url.searchParams.get(ORG_ID_QUERY_PARAM) !== tail) {
|
|
967
|
+
url.searchParams.delete(ACTIVE_ORG_QUERY_PARAM);
|
|
968
|
+
url.searchParams.set(ORG_ID_QUERY_PARAM, tail);
|
|
969
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
970
|
+
}
|
|
971
|
+
} catch {
|
|
972
|
+
}
|
|
973
|
+
}, [orgId]);
|
|
974
|
+
useEffect(() => {
|
|
975
|
+
if (isOrgId(tokenOrg.orgId) && !pendingOrg) writeActiveOrgCookie(tokenOrg.orgId);
|
|
976
|
+
}, [tokenOrg.orgId, pendingOrg]);
|
|
977
|
+
const value = useMemo(
|
|
978
|
+
() => ({
|
|
979
|
+
orgId,
|
|
980
|
+
setOrgId,
|
|
981
|
+
orgs,
|
|
982
|
+
orgsLoading: !tokenOrg.orgs && orgsFetching && !orgsError && !fetchedOrgs,
|
|
983
|
+
navDisplay,
|
|
984
|
+
setNavDisplay
|
|
985
|
+
}),
|
|
986
|
+
[orgId, setOrgId, orgs, tokenOrg.orgs, orgsFetching, orgsError, fetchedOrgs, navDisplay, setNavDisplay]
|
|
987
|
+
);
|
|
988
|
+
return /* @__PURE__ */ jsx(ChromeStateContext.Provider, { value, children });
|
|
989
|
+
}
|
|
877
990
|
function ChromeStateProvider({
|
|
878
991
|
controlledOrg,
|
|
879
992
|
children
|
|
@@ -1177,6 +1290,7 @@ function PolitogyAppChrome({
|
|
|
1177
1290
|
fetchJson: fetchJsonOverride,
|
|
1178
1291
|
devNotes,
|
|
1179
1292
|
org,
|
|
1293
|
+
tokenOrg,
|
|
1180
1294
|
identity,
|
|
1181
1295
|
children
|
|
1182
1296
|
}) {
|
|
@@ -1195,7 +1309,7 @@ function PolitogyAppChrome({
|
|
|
1195
1309
|
[proxyBasePath]
|
|
1196
1310
|
);
|
|
1197
1311
|
const fetchJson = fetchJsonOverride ?? proxyFetchJson;
|
|
1198
|
-
|
|
1312
|
+
const devNotesTree = /* @__PURE__ */ jsx(
|
|
1199
1313
|
AppDevNotes,
|
|
1200
1314
|
{
|
|
1201
1315
|
storagePrefix,
|
|
@@ -1204,7 +1318,8 @@ function PolitogyAppChrome({
|
|
|
1204
1318
|
identity,
|
|
1205
1319
|
children
|
|
1206
1320
|
}
|
|
1207
|
-
)
|
|
1321
|
+
);
|
|
1322
|
+
return /* @__PURE__ */ jsx(NavChromeProvider, { fetchJson, children: tokenOrg ? /* @__PURE__ */ jsx(TokenChromeStateProvider, { tokenOrg, children: devNotesTree }) : /* @__PURE__ */ jsx(ChromeStateProvider, { controlledOrg: org, children: devNotesTree }) });
|
|
1208
1323
|
}
|
|
1209
1324
|
function ChromeTopBarActions() {
|
|
1210
1325
|
const state = useChromeState();
|
|
@@ -1221,7 +1336,7 @@ function ChromeTopBarActions() {
|
|
|
1221
1336
|
/* @__PURE__ */ jsx(FuelAction, { orgId: state.orgId }),
|
|
1222
1337
|
/* @__PURE__ */ jsx(SpecOverlayAction, { orgId: state.orgId, orgName: state.orgs.find((o) => o.id === state.orgId)?.name ?? null }),
|
|
1223
1338
|
/* @__PURE__ */ jsx(NotificationsAction, { orgId: state.orgId }),
|
|
1224
|
-
/* @__PURE__ */ jsx(SupportAction, { orgId: state.orgId })
|
|
1339
|
+
/* @__PURE__ */ jsx(SupportAction, { orgId: state.orgId, orgs: state.orgs.length ? state.orgs : void 0 })
|
|
1225
1340
|
] });
|
|
1226
1341
|
}
|
|
1227
1342
|
function ChromeDevNotesMenu() {
|