@the-portland-company/shell 0.36.3 → 0.37.1
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 +41 -0
- package/dist/app-chrome.cjs +149 -37
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.js +50 -15
- package/dist/app-chrome.js.map +1 -1
- package/dist/chunk-6UHJV2FH.js +63 -0
- package/dist/chunk-6UHJV2FH.js.map +1 -0
- package/dist/{chunk-LIGKGXFT.js → chunk-WKKJHCEK.js} +45 -27
- package/dist/chunk-WKKJHCEK.js.map +1 -0
- package/dist/native.cjs +43 -24
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +22 -5
- package/dist/native.d.ts +22 -5
- package/dist/native.js +1 -1
- package/dist/nav-preference.cjs +75 -0
- package/dist/nav-preference.cjs.map +1 -0
- package/dist/nav-preference.d.cts +18 -0
- package/dist/nav-preference.d.ts +18 -0
- package/dist/nav-preference.js +3 -0
- package/dist/nav-preference.js.map +1 -0
- package/package.json +6 -1
- package/dist/chunk-LIGKGXFT.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
## 0.37.1 — 2026-07-27
|
|
2
|
+
|
|
3
|
+
### Fixed — cross-app navigation kept the user's active organization
|
|
4
|
+
|
|
5
|
+
Every link the Relationship tree emitted was bare: `Forms` / `Surveys` / `Polls`
|
|
6
|
+
went to their standalone apps, and every core route went to `app.politogyvrm.com`,
|
|
7
|
+
with no `?org=` selector. A multi-org user working in one organization clicked a
|
|
8
|
+
feature and landed in whichever organization the destination resolved by default
|
|
9
|
+
(reported: working in "We Need Steve", clicked Contacts, arrived in another org's
|
|
10
|
+
contacts). Intra-app links already carried the selector, so the jump only
|
|
11
|
+
happened when crossing apps.
|
|
12
|
+
|
|
13
|
+
`standardPolitogyNav` now stamps `?org=<full-uuid>` on EVERY link it builds, in
|
|
14
|
+
every tree — the Campaign and Petition trees already did. The full UUID is the
|
|
15
|
+
only collision-free selector (contacts-api matches exact id first, then a short
|
|
16
|
+
suffix that can collide across a user's orgs), and `isNavItemActive` already
|
|
17
|
+
excludes `org` from active-detection, so nothing changes about which row is
|
|
18
|
+
selected. The app-owned `contactsItem` override is still used verbatim; the
|
|
19
|
+
`politogy_active_org` cookie remains the fallback for a bare URL.
|
|
20
|
+
|
|
21
|
+
The same treatment applies to the chrome's own cross-app links — "Buy More Fuel"
|
|
22
|
+
/ "Add fuel" and "View all" quarantined contacts, which all point into VRM core.
|
|
23
|
+
|
|
24
|
+
## 0.37.0 — 2026-07-27
|
|
25
|
+
|
|
26
|
+
### Fixed — organization logo renders in every app, not just VRM core
|
|
27
|
+
|
|
28
|
+
`organizations.logo_url` is authored by VRM core and stored as a ROOT-RELATIVE
|
|
29
|
+
core route (`/api/storage/public?bucket=organization-logos&path=<org>/logo.png`
|
|
30
|
+
— core's signed-storage proxy). VRM core rendered it fine because the path
|
|
31
|
+
resolved against its own origin; every feature app resolved the same path
|
|
32
|
+
against ITS origin (`forms.politogyvrm.com/api/storage/public`), 404'd, and
|
|
33
|
+
showed a broken image in the sidebar org pill and the org dropdown.
|
|
34
|
+
|
|
35
|
+
`resolveOrgLogoUrl` (exported from `./native`) now absolutizes a relative logo
|
|
36
|
+
path against `CORE_APP_ORIGIN` at the point of render, for all three org-badge
|
|
37
|
+
sites (active pill, dropdown rows, non-switcher pill). Absolute, protocol-
|
|
38
|
+
relative and `data:` URLs pass through untouched; empty values still fall back
|
|
39
|
+
to initials. This is the same treatment `absolutizeAvatarUrl` already applied to
|
|
40
|
+
`profiles.avatar_url` in the chrome API — the org logo was simply missed.
|
|
41
|
+
|
|
1
42
|
## 0.36.0 — 2026-07-24
|
|
2
43
|
|
|
3
44
|
### Added — cross-subdomain active-org + favicon cache-busting
|
package/dist/app-chrome.cjs
CHANGED
|
@@ -150,6 +150,16 @@ var CORE_APP_ORIGIN = "https://app.politogyvrm.com";
|
|
|
150
150
|
var CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
|
|
151
151
|
var CORE_BILLING_URL = `${CORE_APP_ORIGIN}${CORE_BILLING_PATH}`;
|
|
152
152
|
var QUARANTINED_CONTACTS_URL = `${CORE_APP_ORIGIN}/relationship/contacts/quarantined`;
|
|
153
|
+
function withOrgParam(url, orgId) {
|
|
154
|
+
if (!orgId) return url;
|
|
155
|
+
return `${url}${url.includes("?") ? "&" : "?"}org=${orgId}`;
|
|
156
|
+
}
|
|
157
|
+
function resolveOrgLogoUrl(url) {
|
|
158
|
+
const raw = url?.trim();
|
|
159
|
+
if (!raw) return void 0;
|
|
160
|
+
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(raw)) return raw;
|
|
161
|
+
return `${CORE_APP_ORIGIN}${raw.startsWith("/") ? "" : "/"}${raw}`;
|
|
162
|
+
}
|
|
153
163
|
function topBarIconButtonClass(tone = "default") {
|
|
154
164
|
const toneClass = tone === "danger" || tone === "warning" ? "text-[color:var(--color-race-red)] hover:text-[color:var(--color-race-red)]" : "text-[color:var(--topbar-icon-color,var(--muted))] hover:text-[color:var(--topbar-icon-hover-color,var(--foreground))] hover:bg-[color:var(--topbar-icon-hover-bg,transparent)]";
|
|
155
165
|
return [
|
|
@@ -498,7 +508,7 @@ function FuelRow({
|
|
|
498
508
|
) })
|
|
499
509
|
] });
|
|
500
510
|
}
|
|
501
|
-
function LowFuelHint({ lowFuel }) {
|
|
511
|
+
function LowFuelHint({ lowFuel, orgId }) {
|
|
502
512
|
const [dismissed, setDismissed] = react.useState(() => {
|
|
503
513
|
if (typeof window === "undefined") return false;
|
|
504
514
|
try {
|
|
@@ -542,7 +552,7 @@ function LowFuelHint({ lowFuel }) {
|
|
|
542
552
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
543
553
|
"a",
|
|
544
554
|
{
|
|
545
|
-
href: CORE_BILLING_URL,
|
|
555
|
+
href: withOrgParam(CORE_BILLING_URL, orgId),
|
|
546
556
|
className: "mt-1 inline-block text-sm font-bold underline hover:opacity-90",
|
|
547
557
|
children: "Buy More Fuel"
|
|
548
558
|
}
|
|
@@ -609,7 +619,7 @@ function FuelAction({ orgId }) {
|
|
|
609
619
|
label: "SMS Signal",
|
|
610
620
|
channel: fuel?.signal ?? null,
|
|
611
621
|
loading,
|
|
612
|
-
addHref: CORE_BILLING_URL,
|
|
622
|
+
addHref: withOrgParam(CORE_BILLING_URL, orgId),
|
|
613
623
|
addLabel: "Add SMS Signal fuel"
|
|
614
624
|
}
|
|
615
625
|
),
|
|
@@ -619,7 +629,7 @@ function FuelAction({ orgId }) {
|
|
|
619
629
|
label: "Email Broadcast",
|
|
620
630
|
channel: fuel?.broadcast ?? null,
|
|
621
631
|
loading,
|
|
622
|
-
addHref: CORE_BILLING_URL,
|
|
632
|
+
addHref: withOrgParam(CORE_BILLING_URL, orgId),
|
|
623
633
|
addLabel: "Add Email Broadcast fuel"
|
|
624
634
|
}
|
|
625
635
|
)
|
|
@@ -627,7 +637,7 @@ function FuelAction({ orgId }) {
|
|
|
627
637
|
] })
|
|
628
638
|
}
|
|
629
639
|
),
|
|
630
|
-
/* @__PURE__ */ jsxRuntime.jsx(LowFuelHint, { lowFuel: low })
|
|
640
|
+
/* @__PURE__ */ jsxRuntime.jsx(LowFuelHint, { lowFuel: low, orgId })
|
|
631
641
|
] })
|
|
632
642
|
);
|
|
633
643
|
}
|
|
@@ -922,7 +932,7 @@ function NotificationsAction({ orgId }) {
|
|
|
922
932
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
923
933
|
"a",
|
|
924
934
|
{
|
|
925
|
-
href: QUARANTINED_CONTACTS_URL,
|
|
935
|
+
href: withOrgParam(QUARANTINED_CONTACTS_URL, orgId),
|
|
926
936
|
className: "text-[11px] font-semibold text-[color:var(--color-race-red)] hover:underline",
|
|
927
937
|
children: "View all"
|
|
928
938
|
}
|
|
@@ -1390,15 +1400,15 @@ function standardPolitogyNav(opts) {
|
|
|
1390
1400
|
const base = opts.coreBaseUrl.replace(/\/+$/, "");
|
|
1391
1401
|
const abs = (path) => `${base}${path.startsWith("/") ? path : `/${path}`}`;
|
|
1392
1402
|
const icon = (key) => opts.icons?.[key];
|
|
1393
|
-
const
|
|
1403
|
+
const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
|
|
1404
|
+
const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
|
|
1405
|
+
const leaves = (children) => children.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(abs(c.path)) }));
|
|
1394
1406
|
const branches = (children) => children.map((c) => ({
|
|
1395
1407
|
label: c.label,
|
|
1396
1408
|
icon: icon(c.icon),
|
|
1397
|
-
href: abs(c.path),
|
|
1409
|
+
href: withOrg(abs(c.path)),
|
|
1398
1410
|
children: c.children ? leaves(c.children) : void 0
|
|
1399
1411
|
}));
|
|
1400
|
-
const orgParam = opts.activeOrgId ? `org=${opts.activeOrgId}` : "";
|
|
1401
|
-
const withOrg = (url) => orgParam ? `${url}${url.includes("?") ? "&" : "?"}${orgParam}` : url;
|
|
1402
1412
|
const buildRelationship = () => {
|
|
1403
1413
|
const contacts = opts.contactsItem ? {
|
|
1404
1414
|
label: "Contacts",
|
|
@@ -1408,22 +1418,22 @@ function standardPolitogyNav(opts) {
|
|
|
1408
1418
|
} : {
|
|
1409
1419
|
label: "Contacts",
|
|
1410
1420
|
icon: icon("users"),
|
|
1411
|
-
href: abs("/relationship/contacts/dashboard"),
|
|
1421
|
+
href: withOrg(abs("/relationship/contacts/dashboard")),
|
|
1412
1422
|
children: leaves(CONTACTS_DEFAULT_CHILDREN)
|
|
1413
1423
|
};
|
|
1414
1424
|
return [
|
|
1415
|
-
{ label: "Dashboard", icon: icon("home"), href: abs("/relationship/dashboard") },
|
|
1425
|
+
{ label: "Dashboard", icon: icon("home"), href: withOrg(abs("/relationship/dashboard")) },
|
|
1416
1426
|
contacts,
|
|
1417
1427
|
{
|
|
1418
1428
|
label: "Email Broadcast",
|
|
1419
1429
|
icon: icon("mail"),
|
|
1420
|
-
href: abs("/relationship/email/dashboard"),
|
|
1430
|
+
href: withOrg(abs("/relationship/email/dashboard")),
|
|
1421
1431
|
children: leaves(EMAIL_CHILDREN)
|
|
1422
1432
|
},
|
|
1423
1433
|
{
|
|
1424
1434
|
label: "SMS/MMS Blast",
|
|
1425
1435
|
icon: icon("messageSquare"),
|
|
1426
|
-
href: abs("/relationship/sms-mms-blast/dashboard"),
|
|
1436
|
+
href: withOrg(abs("/relationship/sms-mms-blast/dashboard")),
|
|
1427
1437
|
children: leaves(SMS_CHILDREN)
|
|
1428
1438
|
},
|
|
1429
1439
|
// These two carry no top-level href in VRM core (parent row only toggles).
|
|
@@ -1431,25 +1441,25 @@ function standardPolitogyNav(opts) {
|
|
|
1431
1441
|
{
|
|
1432
1442
|
label: "Forms",
|
|
1433
1443
|
icon: icon("activity"),
|
|
1434
|
-
href: "https://forms.politogyvrm.com/",
|
|
1435
|
-
children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: c.href }))
|
|
1444
|
+
href: withOrg("https://forms.politogyvrm.com/"),
|
|
1445
|
+
children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
1436
1446
|
},
|
|
1437
1447
|
{
|
|
1438
1448
|
label: "Surveys",
|
|
1439
1449
|
icon: icon("fileText"),
|
|
1440
|
-
href: "https://surveys.politogyvrm.com/surveys",
|
|
1441
|
-
children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: c.href }))
|
|
1450
|
+
href: withOrg("https://surveys.politogyvrm.com/surveys"),
|
|
1451
|
+
children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
1442
1452
|
},
|
|
1443
1453
|
{
|
|
1444
1454
|
label: "Polls",
|
|
1445
1455
|
icon: icon("barChart"),
|
|
1446
|
-
href: "https://polls.politogyvrm.com/",
|
|
1447
|
-
children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: c.href }))
|
|
1456
|
+
href: withOrg("https://polls.politogyvrm.com/"),
|
|
1457
|
+
children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
1448
1458
|
},
|
|
1449
1459
|
{
|
|
1450
1460
|
label: "Organization Settings",
|
|
1451
1461
|
icon: icon("briefcase"),
|
|
1452
|
-
href: abs("/organization-settings"),
|
|
1462
|
+
href: withOrg(abs("/organization-settings")),
|
|
1453
1463
|
children: branches(ORG_SETTINGS_CHILDREN)
|
|
1454
1464
|
}
|
|
1455
1465
|
];
|
|
@@ -1588,6 +1598,7 @@ function NavSidebar({
|
|
|
1588
1598
|
const activeFn = nav.isActive ?? isNavItemActive;
|
|
1589
1599
|
const ModeIcon = mode?.icon;
|
|
1590
1600
|
const orgBg = org?.brandColor || ORG_PILL_DEFAULT;
|
|
1601
|
+
const orgLogoSrc = resolveOrgLogoUrl(org?.logoUrl);
|
|
1591
1602
|
const activeGroupKey = react.useMemo(() => {
|
|
1592
1603
|
for (let i = 0; i < nav.items.length; i++) {
|
|
1593
1604
|
const item = nav.items[i];
|
|
@@ -1655,7 +1666,7 @@ function NavSidebar({
|
|
|
1655
1666
|
{
|
|
1656
1667
|
style: { backgroundColor: orgBg },
|
|
1657
1668
|
className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
|
|
1658
|
-
children:
|
|
1669
|
+
children: orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
|
|
1659
1670
|
}
|
|
1660
1671
|
),
|
|
1661
1672
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1690,7 +1701,14 @@ function NavSidebar({
|
|
|
1690
1701
|
{
|
|
1691
1702
|
style: { backgroundColor: o.brandColor || ORG_PILL_DEFAULT },
|
|
1692
1703
|
className: "flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden rounded-full text-[10px] font-bold text-white",
|
|
1693
|
-
children: o.logoUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1704
|
+
children: resolveOrgLogoUrl(o.logoUrl) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1705
|
+
"img",
|
|
1706
|
+
{
|
|
1707
|
+
src: resolveOrgLogoUrl(o.logoUrl),
|
|
1708
|
+
alt: "",
|
|
1709
|
+
className: "h-full w-full object-cover"
|
|
1710
|
+
}
|
|
1711
|
+
) : (o.name ?? "Org").slice(0, 2).toUpperCase()
|
|
1694
1712
|
}
|
|
1695
1713
|
),
|
|
1696
1714
|
/* @__PURE__ */ jsxRuntime.jsx("span", { title: o.name ?? o.id, className: "truncate", children: o.name ?? o.id.slice(0, 8) })
|
|
@@ -1712,7 +1730,7 @@ function NavSidebar({
|
|
|
1712
1730
|
{
|
|
1713
1731
|
style: { backgroundColor: orgBg },
|
|
1714
1732
|
className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full text-[11px] font-bold text-white",
|
|
1715
|
-
children:
|
|
1733
|
+
children: orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "h-full w-full object-cover" }) : (org.name ?? "Org").slice(0, 2).toUpperCase()
|
|
1716
1734
|
}
|
|
1717
1735
|
),
|
|
1718
1736
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold", children: org.name ?? "No organizations" })
|
|
@@ -2535,6 +2553,66 @@ function resolveActiveOrg(search) {
|
|
|
2535
2553
|
return readActiveOrgCookie();
|
|
2536
2554
|
}
|
|
2537
2555
|
|
|
2556
|
+
// src/nav-preference.ts
|
|
2557
|
+
var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
|
|
2558
|
+
var NAV_DISPLAY_COOKIE = "politogy_nav_display";
|
|
2559
|
+
var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
|
|
2560
|
+
var NAV_DISPLAY_DEFAULT = "both";
|
|
2561
|
+
var VALID2 = ["menu", "tabs", "both"];
|
|
2562
|
+
function isNavDisplayPreference(v) {
|
|
2563
|
+
return typeof v === "string" && VALID2.includes(v);
|
|
2564
|
+
}
|
|
2565
|
+
function readNavDisplayCookie() {
|
|
2566
|
+
if (typeof document === "undefined") return null;
|
|
2567
|
+
try {
|
|
2568
|
+
const m = document.cookie.match(
|
|
2569
|
+
new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
|
|
2570
|
+
);
|
|
2571
|
+
const v = m ? decodeURIComponent(m[1]) : null;
|
|
2572
|
+
return isNavDisplayPreference(v) ? v : null;
|
|
2573
|
+
} catch {
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
function writeNavDisplayCookie(pref) {
|
|
2578
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
2579
|
+
const host = window.location.hostname;
|
|
2580
|
+
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
2581
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
2582
|
+
document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
|
|
2583
|
+
pref
|
|
2584
|
+
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
2585
|
+
}
|
|
2586
|
+
function readNavDisplayLocal() {
|
|
2587
|
+
if (typeof localStorage === "undefined") return null;
|
|
2588
|
+
try {
|
|
2589
|
+
const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
|
|
2590
|
+
if (isNavDisplayPreference(current)) return current;
|
|
2591
|
+
const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
|
|
2592
|
+
return isNavDisplayPreference(legacy) ? legacy : null;
|
|
2593
|
+
} catch {
|
|
2594
|
+
return null;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
function writeNavDisplayLocal(pref) {
|
|
2598
|
+
if (typeof localStorage === "undefined") return;
|
|
2599
|
+
try {
|
|
2600
|
+
localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
|
|
2601
|
+
} catch {
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
function resolveNavDisplay() {
|
|
2605
|
+
return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
|
|
2606
|
+
}
|
|
2607
|
+
`(function(){try{
|
|
2608
|
+
var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
|
|
2609
|
+
var VALID=["menu","tabs","both"];
|
|
2610
|
+
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
2611
|
+
var cookie=fromCookie();
|
|
2612
|
+
if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
2613
|
+
if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
|
|
2614
|
+
}catch(e){}})();`;
|
|
2615
|
+
|
|
2538
2616
|
// src/lib/breadcrumbs.ts
|
|
2539
2617
|
function deriveBreadcrumbs(items, pathname, opts) {
|
|
2540
2618
|
const search = opts?.search ?? (typeof window !== "undefined" ? window.location.search : "");
|
|
@@ -2927,7 +3005,6 @@ var standardNavIcons = {
|
|
|
2927
3005
|
};
|
|
2928
3006
|
var ORG_STORAGE_KEY = "vrm.activeOrg";
|
|
2929
3007
|
var MODE_STORAGE_KEY = "vrm.activeMode";
|
|
2930
|
-
var NAV_DISPLAY_KEY = "vrm.navDisplay";
|
|
2931
3008
|
var CORE_BASE_URL = "https://app.politogyvrm.com";
|
|
2932
3009
|
var ChromeStateContext = react.createContext(null);
|
|
2933
3010
|
function useChromeState() {
|
|
@@ -2938,18 +3015,46 @@ function ChromeStateProvider({
|
|
|
2938
3015
|
children
|
|
2939
3016
|
}) {
|
|
2940
3017
|
const { orgs, loading: orgsFetching, error: orgsError } = useChromeOrgs();
|
|
3018
|
+
const chromeMe = useChromeMe();
|
|
3019
|
+
const chromeFetch = useNavChromeFetcher();
|
|
2941
3020
|
const [orgId, setOrgIdState] = react.useState(null);
|
|
2942
|
-
const [navDisplay, setNavDisplayState] = react.useState(
|
|
3021
|
+
const [navDisplay, setNavDisplayState] = react.useState(NAV_DISPLAY_DEFAULT);
|
|
3022
|
+
const navReconciled = react.useRef(false);
|
|
2943
3023
|
react.useEffect(() => {
|
|
2944
3024
|
try {
|
|
2945
3025
|
const storedOrg = resolveActiveOrg() ?? localStorage.getItem(ORG_STORAGE_KEY);
|
|
2946
3026
|
if (storedOrg) setOrgIdState(storedOrg);
|
|
2947
|
-
const storedNav = localStorage.getItem(NAV_DISPLAY_KEY);
|
|
2948
|
-
if (storedNav === "menu" || storedNav === "tabs" || storedNav === "both") {
|
|
2949
|
-
setNavDisplayState(storedNav);
|
|
2950
|
-
}
|
|
2951
3027
|
} catch {
|
|
2952
3028
|
}
|
|
3029
|
+
setNavDisplayState(resolveNavDisplay());
|
|
3030
|
+
}, []);
|
|
3031
|
+
react.useEffect(() => {
|
|
3032
|
+
if (navReconciled.current || !chromeMe.me) return;
|
|
3033
|
+
const pref = chromeMe.me.navDisplay;
|
|
3034
|
+
if (!isNavDisplayPreference(pref)) return;
|
|
3035
|
+
navReconciled.current = true;
|
|
3036
|
+
setNavDisplayState(pref);
|
|
3037
|
+
writeNavDisplayCookie(pref);
|
|
3038
|
+
writeNavDisplayLocal(pref);
|
|
3039
|
+
}, [chromeMe]);
|
|
3040
|
+
react.useEffect(() => {
|
|
3041
|
+
const onStorage = (e) => {
|
|
3042
|
+
if (e.key === NAV_DISPLAY_STORAGE_KEY && isNavDisplayPreference(e.newValue)) {
|
|
3043
|
+
setNavDisplayState(e.newValue);
|
|
3044
|
+
}
|
|
3045
|
+
};
|
|
3046
|
+
const onWake = () => {
|
|
3047
|
+
const cookie = readNavDisplayCookie();
|
|
3048
|
+
if (cookie) setNavDisplayState(cookie);
|
|
3049
|
+
};
|
|
3050
|
+
window.addEventListener("storage", onStorage);
|
|
3051
|
+
window.addEventListener("focus", onWake);
|
|
3052
|
+
document.addEventListener("visibilitychange", onWake);
|
|
3053
|
+
return () => {
|
|
3054
|
+
window.removeEventListener("storage", onStorage);
|
|
3055
|
+
window.removeEventListener("focus", onWake);
|
|
3056
|
+
document.removeEventListener("visibilitychange", onWake);
|
|
3057
|
+
};
|
|
2953
3058
|
}, []);
|
|
2954
3059
|
react.useEffect(() => {
|
|
2955
3060
|
if (!orgs || orgs.length === 0) return;
|
|
@@ -2963,13 +3068,20 @@ function ChromeStateProvider({
|
|
|
2963
3068
|
}
|
|
2964
3069
|
writeActiveOrgCookie(id);
|
|
2965
3070
|
}, []);
|
|
2966
|
-
const setNavDisplay = react.useCallback(
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
3071
|
+
const setNavDisplay = react.useCallback(
|
|
3072
|
+
(m) => {
|
|
3073
|
+
setNavDisplayState(m);
|
|
3074
|
+
writeNavDisplayLocal(m);
|
|
3075
|
+
writeNavDisplayCookie(m);
|
|
3076
|
+
chromeFetch?.("me/preferences", {
|
|
3077
|
+
method: "PATCH",
|
|
3078
|
+
headers: { "Content-Type": "application/json" },
|
|
3079
|
+
body: JSON.stringify({ navDisplay: m })
|
|
3080
|
+
})?.catch(() => {
|
|
3081
|
+
});
|
|
3082
|
+
},
|
|
3083
|
+
[chromeFetch]
|
|
3084
|
+
);
|
|
2973
3085
|
const value = react.useMemo(() => {
|
|
2974
3086
|
if (controlledOrg) {
|
|
2975
3087
|
return {
|