@campfire-interactive/shell-header 0.5.6 → 0.6.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/dist/index.d.ts CHANGED
@@ -38,6 +38,12 @@ interface LocaleOption {
38
38
  /** Human-readable label shown in the dropdown, e.g. "English", "Deutsch". */
39
39
  label: string;
40
40
  }
41
+ interface CurrencyOption {
42
+ /** ISO-4217 code, e.g. "USD", "EUR", "JPY". */
43
+ code: string;
44
+ /** Human-readable label shown in the dropdown, e.g. "US Dollar", "Euro". */
45
+ label: string;
46
+ }
41
47
  /**
42
48
  * Subset of the platform-notifications `Notification` shape that the bell UI
43
49
  * actually renders. Hosts typically map their fetched items (e.g., from
@@ -123,13 +129,31 @@ interface ShellHeaderProps {
123
129
  * pick up the change.
124
130
  */
125
131
  onLocaleChange?: (locale: string) => void | Promise<void>;
132
+ /**
133
+ * Current display currency (ISO-4217, e.g. "USD"). When provided alongside
134
+ * `supportedCurrencies` and `onCurrencyChange`, a Currency section renders
135
+ * inside the dropdown. Omitting any of the three hides it.
136
+ *
137
+ * The picker is a UI-only surface — this package neither knows nor cares
138
+ * about FX rates or conversion. Hosts handle rate tables, conversion, and
139
+ * persistence themselves.
140
+ */
141
+ currency?: string;
142
+ /** Currencies the user can pick from. */
143
+ supportedCurrencies?: ReadonlyArray<CurrencyOption>;
144
+ /**
145
+ * Called when the user picks a different currency. Consumer is responsible
146
+ * for persisting the choice (typically to localStorage or a user-prefs
147
+ * endpoint) and for propagating it through the rest of the UI.
148
+ */
149
+ onCurrencyChange?: (currency: string) => void | Promise<void>;
126
150
  /** Fixed width for the app brand area (e.g., to align with a sidebar below). */
127
151
  brandWidth?: number;
128
152
  /** Optional content in the left/center area (filters, search, breadcrumbs, etc.) */
129
153
  children?: React.ReactNode;
130
154
  }
131
155
 
132
- declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, tenant, tenants, onTenantSwitch, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
156
+ declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, currency, supportedCurrencies, onCurrencyChange, tenant, tenants, onTenantSwitch, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
133
157
 
134
158
  interface LocaleSwitcherProps {
135
159
  currentLocale: string;
package/dist/index.js CHANGED
@@ -66,7 +66,8 @@ import {
66
66
  LogOut,
67
67
  Globe,
68
68
  ChevronDown,
69
- Check
69
+ Check,
70
+ Coins
70
71
  } from "lucide-react";
71
72
  import { jsx, jsxs } from "react/jsx-runtime";
72
73
  var iconMap = {
@@ -262,12 +263,16 @@ function UserMenu({
262
263
  locale,
263
264
  supportedLocales,
264
265
  onLocaleChange,
266
+ currency,
267
+ supportedCurrencies,
268
+ onCurrencyChange,
265
269
  tenant,
266
270
  tenants,
267
271
  onTenantSwitch
268
272
  }) {
269
273
  const [open, setOpen] = useState3(false);
270
274
  const [langExpanded, setLangExpanded] = useState3(false);
275
+ const [currExpanded, setCurrExpanded] = useState3(false);
271
276
  const [tenantExpanded, setTenantExpanded] = useState3(false);
272
277
  const [updating, setUpdating] = useState3(false);
273
278
  const ref = useRef3(null);
@@ -276,6 +281,7 @@ function UserMenu({
276
281
  if (ref.current && !ref.current.contains(e.target)) {
277
282
  setOpen(false);
278
283
  setLangExpanded(false);
284
+ setCurrExpanded(false);
279
285
  setTenantExpanded(false);
280
286
  }
281
287
  }
@@ -285,6 +291,7 @@ function UserMenu({
285
291
  useEffect3(() => {
286
292
  if (!open) {
287
293
  setLangExpanded(false);
294
+ setCurrExpanded(false);
288
295
  setTenantExpanded(false);
289
296
  }
290
297
  }, [open]);
@@ -305,6 +312,22 @@ function UserMenu({
305
312
  setOpen(false);
306
313
  }
307
314
  }
315
+ const showCurrency = currency !== void 0 && supportedCurrencies !== void 0 && supportedCurrencies.length > 0 && onCurrencyChange !== void 0;
316
+ const currentCurrency = showCurrency ? supportedCurrencies.find((c) => c.code === currency) : void 0;
317
+ async function handleCurrencySelect(code) {
318
+ if (code === currency || !onCurrencyChange) {
319
+ setCurrExpanded(false);
320
+ return;
321
+ }
322
+ setUpdating(true);
323
+ try {
324
+ await onCurrencyChange(code);
325
+ } finally {
326
+ setUpdating(false);
327
+ setCurrExpanded(false);
328
+ setOpen(false);
329
+ }
330
+ }
308
331
  const showTenant = tenant !== void 0;
309
332
  const canSwitchTenant = showTenant && onTenantSwitch !== void 0 && Array.isArray(tenants) && tenants.length > 1;
310
333
  async function handleTenantSelect(tenantId) {
@@ -417,6 +440,43 @@ function UserMenu({
417
440
  loc.code
418
441
  )) })
419
442
  ] }),
443
+ showCurrency && /* @__PURE__ */ jsxs4(Fragment, { children: [
444
+ /* @__PURE__ */ jsx4("div", { className: "cfi-sh-divider" }),
445
+ /* @__PURE__ */ jsxs4(
446
+ "button",
447
+ {
448
+ className: "cfi-sh-menu-item cfi-sh-locale-row",
449
+ onClick: () => setCurrExpanded(!currExpanded),
450
+ "aria-expanded": currExpanded,
451
+ disabled: updating,
452
+ children: [
453
+ /* @__PURE__ */ jsx4(Coins, { size: 14 }),
454
+ /* @__PURE__ */ jsx4("span", { className: "cfi-sh-locale-row-label", children: "Currency" }),
455
+ /* @__PURE__ */ jsx4("span", { className: "cfi-sh-locale-row-current", children: currentCurrency?.code ?? currency }),
456
+ /* @__PURE__ */ jsx4(
457
+ ChevronDown,
458
+ {
459
+ size: 14,
460
+ className: currExpanded ? "cfi-sh-locale-chevron cfi-sh-locale-chevron-open" : "cfi-sh-locale-chevron"
461
+ }
462
+ )
463
+ ]
464
+ }
465
+ ),
466
+ currExpanded && /* @__PURE__ */ jsx4("div", { className: "cfi-sh-locale-sublist", children: supportedCurrencies.map((cur) => /* @__PURE__ */ jsxs4(
467
+ "button",
468
+ {
469
+ className: cur.code === currency ? "cfi-sh-menu-item cfi-sh-locale-sub-item cfi-sh-locale-item-active" : "cfi-sh-menu-item cfi-sh-locale-sub-item",
470
+ onClick: () => handleCurrencySelect(cur.code),
471
+ disabled: updating,
472
+ children: [
473
+ /* @__PURE__ */ jsx4("span", { className: "cfi-sh-locale-item-label", children: cur.label }),
474
+ /* @__PURE__ */ jsx4("span", { className: "cfi-sh-locale-item-code", children: cur.code })
475
+ ]
476
+ },
477
+ cur.code
478
+ )) })
479
+ ] }),
420
480
  /* @__PURE__ */ jsx4("div", { className: "cfi-sh-divider" }),
421
481
  /* @__PURE__ */ jsxs4(
422
482
  "button",
@@ -453,6 +513,9 @@ function ShellHeader({
453
513
  locale,
454
514
  supportedLocales,
455
515
  onLocaleChange,
516
+ currency,
517
+ supportedCurrencies,
518
+ onCurrencyChange,
456
519
  tenant,
457
520
  tenants,
458
521
  onTenantSwitch,
@@ -491,6 +554,9 @@ function ShellHeader({
491
554
  locale,
492
555
  supportedLocales,
493
556
  onLocaleChange,
557
+ currency,
558
+ supportedCurrencies,
559
+ onCurrencyChange,
494
560
  tenant,
495
561
  tenants,
496
562
  onTenantSwitch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campfire-interactive/shell-header",
3
- "version": "0.5.6",
3
+ "version": "0.6.1",
4
4
  "description": "Shared shell header with app switcher for Campfire Suite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",