@cosmoops/connect-sdk 0.45.0 → 0.46.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/cjs/client/components/access-gate.js +1 -1
  3. package/dist/cjs/client/components/account-sessions.js +1 -1
  4. package/dist/cjs/client/components/ai-format.js +3 -3
  5. package/dist/cjs/client/components/ai-widgets.js +5 -5
  6. package/dist/cjs/client/components/apps-grid.js +2 -2
  7. package/dist/cjs/client/components/ask-ai-history.js +2 -2
  8. package/dist/cjs/client/components/ask-ai.js +1 -1
  9. package/dist/cjs/client/components/availability-form.js +1 -1
  10. package/dist/cjs/client/components/booking-calendar.js +4 -4
  11. package/dist/cjs/client/components/booking-dialogs.js +2 -2
  12. package/dist/cjs/client/components/call-button.js +6 -6
  13. package/dist/cjs/client/components/create-workspace-form.js +1 -1
  14. package/dist/cjs/client/components/event-type-form.js +1 -1
  15. package/dist/cjs/client/components/filter-tabs.js +1 -1
  16. package/dist/cjs/client/components/grievance-notice.js +1 -1
  17. package/dist/cjs/client/components/integrations-modal.js +2 -2
  18. package/dist/cjs/client/components/plans.js +5 -5
  19. package/dist/cjs/client/components/readiness.js +1 -1
  20. package/dist/cjs/client/components/subscribe-dialog.js +1 -1
  21. package/dist/cjs/client/components/subscription.js +5 -5
  22. package/dist/cjs/client/components/usage-meter.js +2 -2
  23. package/dist/cjs/client/components/user-menu.js +1 -1
  24. package/dist/cjs/client/components/workspace-switcher.js +1 -1
  25. package/dist/cjs/server/client.js +1 -1
  26. package/dist/cjs/server/resources/drive.js +11 -0
  27. package/dist/cjs/ui/page-shell.js +64 -2
  28. package/dist/esm/client/components/access-gate.js +1 -1
  29. package/dist/esm/client/components/account-sessions.js +1 -1
  30. package/dist/esm/client/components/ai-format.js +3 -3
  31. package/dist/esm/client/components/ai-widgets.js +5 -5
  32. package/dist/esm/client/components/apps-grid.js +2 -2
  33. package/dist/esm/client/components/ask-ai-history.js +2 -2
  34. package/dist/esm/client/components/ask-ai.js +1 -1
  35. package/dist/esm/client/components/availability-form.js +1 -1
  36. package/dist/esm/client/components/booking-calendar.js +4 -4
  37. package/dist/esm/client/components/booking-dialogs.js +2 -2
  38. package/dist/esm/client/components/call-button.js +6 -6
  39. package/dist/esm/client/components/create-workspace-form.js +1 -1
  40. package/dist/esm/client/components/event-type-form.js +1 -1
  41. package/dist/esm/client/components/filter-tabs.js +1 -1
  42. package/dist/esm/client/components/grievance-notice.js +1 -1
  43. package/dist/esm/client/components/integrations-modal.js +2 -2
  44. package/dist/esm/client/components/plans.js +5 -5
  45. package/dist/esm/client/components/readiness.js +1 -1
  46. package/dist/esm/client/components/subscribe-dialog.js +1 -1
  47. package/dist/esm/client/components/subscription.js +5 -5
  48. package/dist/esm/client/components/usage-meter.js +2 -2
  49. package/dist/esm/client/components/user-menu.js +1 -1
  50. package/dist/esm/client/components/workspace-switcher.js +1 -1
  51. package/dist/esm/server/client.js +1 -1
  52. package/dist/esm/server/resources/drive.js +11 -0
  53. package/dist/esm/ui/page-shell.js +31 -2
  54. package/dist/theme.css +78 -2
  55. package/dist/types/server/client.d.ts +1 -1
  56. package/dist/types/server/resources/drive.d.ts +8 -1
  57. package/dist/types/types.d.ts +9 -0
  58. package/dist/types/ui/page-shell.d.ts +20 -2
  59. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,61 @@
3
3
  `@cosmoops/connect-sdk` follows semver, with the 0.x convention that **minor
4
4
  versions may carry breaking changes** and patch versions never do.
5
5
 
6
+ ## 0.46.0
7
+
8
+ ### `secondary` buttons are soft indigo
9
+
10
+ `<Button variant="secondary">` and `<ConnectLinkButton variant="secondary">`
11
+ now paint an indigo tint with indigo text instead of the neutral grey,
12
+ so a view reads as one solid green primary action beside indigo secondary
13
+ ones. `tertiary` stays neutral, for quieter in-row controls. New tokens
14
+ `--secondary-soft`, `--secondary-soft-hover` and
15
+ `--secondary-soft-foreground`, in both themes. To keep the old look,
16
+ redefine `.button--secondary` after importing `theme.css`.
17
+
18
+ ### `ConnectPageShell` plays a route transition
19
+
20
+ Every page drawn in `ConnectPageShell` now fades the outgoing page out and
21
+ the arriving one in with a slight rise, using React's `<ViewTransition>`.
22
+ The animations ship in `theme.css` (`connect-page-enter`/`connect-page-exit`)
23
+ and respect `prefers-reduced-motion`. Nothing to wire.
24
+
25
+ - **Next.js App Router only, in practice.** `<ViewTransition>` exists in
26
+ the React canary Next bundles and in no stable React yet. The shell looks
27
+ it up at runtime, so on any other host the page renders exactly as before,
28
+ with no motion and no error.
29
+ - **New prop `transition`** (default `true`). Pass `transition={false}` if
30
+ your app already animates its routes, or the two transitions play over each
31
+ other.
32
+ - Where a *layout* draws the shell, such as a record page with tabs, entering
33
+ and leaving the record animates and switching tabs does not.
34
+
35
+ ### `connect.drive.getUsage()`
36
+
37
+ `connect.drive.getUsage({ workspaceId })` returns `{ usedBytes, limitBytes }`
38
+ for the workspace's Drive - the same limit an upload is refused against with
39
+ `quota_exceeded`, so a usage meter agrees with the refusal. `limitBytes: null`
40
+ is unlimited. Needs `drive:read` and an active subscription to your
41
+ application. New type: `DriveUsage`.
42
+
43
+ ### Components follow HeroUI's colour roles
44
+
45
+ No API changes; these are colour fixes inside the components.
46
+
47
+ - **Links are links.** The calling notices and the grievance contact draw in
48
+ `--link` (the indigo) instead of the green, which is for actions.
49
+ - **State colours as text are legible.** Error messages, the usage meter's
50
+ overdraw, banner text, the trial note and the AI widgets' tone text used the
51
+ fill colours (`text-danger`, `text-accent`, `text-success`, `text-warning`)
52
+ as text, which measures under 3:1 on a light surface. They now use HeroUI's
53
+ `*-soft-foreground` tokens, which HeroUI derives for exactly that and which
54
+ follow a host's re-themed `--accent`/`--danger`.
55
+ - **Chips and destructive buttons use HeroUI's own variants.** Status and
56
+ saving chips are `<Chip color variant="soft">` instead of hand-painted
57
+ classes; Cancel subscription, Sign out and Disconnect are
58
+ `variant="danger-soft"` instead of a tertiary button painted red.
59
+ - The filter tabs' keyboard ring uses `--focus`, like every HeroUI component.
60
+
6
61
  ## 0.45.0
7
62
 
8
63
  ### `theme.css`: a secondary colour
@@ -308,7 +308,7 @@ function PaymentRetryBanner({ blocker, className, }) {
308
308
  const [dismissed, setDismissed] = (0, react_1.useState)(() => dismissKey !== null && typeof window !== "undefined" && window.localStorage.getItem(dismissKey) === "1");
309
309
  if (dismissed)
310
310
  return null;
311
- return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(motion_js_1.m.div, { className: (0, cn_js_1.cn)("flex flex-wrap items-center justify-between gap-3 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent", className), role: "status", initial: { opacity: 0, y: -6 }, animate: { opacity: 1, y: 0 }, transition: motion_js_1.ENTER, children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { className: "size-4 shrink-0", "aria-hidden": "true" }), blocker.message, blocker.graceEndsAt && ` Resolve by ${formatDate(blocker.graceEndsAt)} to avoid losing access.`] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [blocker.resolveUrl && ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "secondary", onPress: () => openConnect(blocker.resolveUrl), children: ["Resolve payment", (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { className: "size-3.5" })] })), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "tertiary", isIconOnly: true, "aria-label": "Dismiss", onPress: () => {
311
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(motion_js_1.m.div, { className: (0, cn_js_1.cn)("flex flex-wrap items-center justify-between gap-3 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent-soft-foreground", className), role: "status", initial: { opacity: 0, y: -6 }, animate: { opacity: 1, y: 0 }, transition: motion_js_1.ENTER, children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { className: "size-4 shrink-0", "aria-hidden": "true" }), blocker.message, blocker.graceEndsAt && ` Resolve by ${formatDate(blocker.graceEndsAt)} to avoid losing access.`] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [blocker.resolveUrl && ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "secondary", onPress: () => openConnect(blocker.resolveUrl), children: ["Resolve payment", (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { className: "size-3.5" })] })), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "tertiary", isIconOnly: true, "aria-label": "Dismiss", onPress: () => {
312
312
  setDismissed(true);
313
313
  if (dismissKey && typeof window !== "undefined")
314
314
  window.localStorage.setItem(dismissKey, "1");
@@ -95,7 +95,7 @@ function ConnectAccountSessions({ className, maxVisible = 4 }) {
95
95
  const hasOtherSessions = sessions.some((session) => !session.isCurrent);
96
96
  const isCollapsible = maxVisible > 0 && sessions.length > maxVisible;
97
97
  const visible = isCollapsible && !showAll ? sessions.slice(0, maxVisible) : sessions;
98
- return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)("section", { className: (0, cn_js_1.cn)("flex flex-col gap-3", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0", children: [(0, jsx_runtime_1.jsxs)("p", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: ["Active sessions", (0, jsx_runtime_1.jsx)(react_2.Chip, { size: "sm", variant: "soft", children: sessions.length })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Devices signed in to your Connect account." })] }), hasOtherSessions && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "tertiary", className: "shrink-0 text-xs text-danger", isPending: isRevokingOthers, isDisabled: isRevokingOthers, onPress: () => {
98
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)("section", { className: (0, cn_js_1.cn)("flex flex-col gap-3", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0", children: [(0, jsx_runtime_1.jsxs)("p", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: ["Active sessions", (0, jsx_runtime_1.jsx)(react_2.Chip, { size: "sm", variant: "soft", children: sessions.length })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Devices signed in to your Connect account." })] }), hasOtherSessions && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "tertiary", className: "shrink-0 text-xs text-danger-soft-foreground", isPending: isRevokingOthers, isDisabled: isRevokingOthers, onPress: () => {
99
99
  setIsRevokingOthers(true);
100
100
  void mutateResource("/sessions/revoke-others")
101
101
  .then(() => {
@@ -123,9 +123,9 @@ function aiStatusTone(value) {
123
123
  /** HeroUI semantic tokens only, so these inherit whatever theme the host defined. */
124
124
  exports.AI_TONE_CHIP = {
125
125
  neutral: "bg-surface-tertiary text-foreground",
126
- positive: "bg-success/15 text-success",
127
- warning: "bg-warning/20 text-warning",
128
- danger: "bg-danger/15 text-danger",
126
+ positive: "bg-success-soft text-success-soft-foreground",
127
+ warning: "bg-warning-soft text-warning-soft-foreground",
128
+ danger: "bg-danger-soft text-danger-soft-foreground",
129
129
  };
130
130
  exports.AI_TONE_DOT = {
131
131
  neutral: "bg-muted",
@@ -34,9 +34,9 @@ function Panel({ title, children }) {
34
34
  }
35
35
  const TONE_TEXT = {
36
36
  neutral: "text-muted",
37
- positive: "text-success",
38
- warning: "text-warning",
39
- danger: "text-danger",
37
+ positive: "text-success-soft-foreground",
38
+ warning: "text-warning-soft-foreground",
39
+ danger: "text-danger-soft-foreground",
40
40
  };
41
41
  function StatusChip({ value }) {
42
42
  return ((0, jsx_runtime_1.jsx)("span", { className: `inline-block rounded-full px-1.5 py-0.5 text-[10px] font-medium ${ai_format_js_1.AI_TONE_CHIP[(0, ai_format_js_1.aiStatusTone)(value)]}`, children: String(value) }));
@@ -206,7 +206,7 @@ function AiMetrics({ title, metrics }) {
206
206
  : metric.deltaMeaning === "up-is-good"
207
207
  ? rising
208
208
  : !rising;
209
- return ((0, jsx_runtime_1.jsxs)("div", { className: "rounded-md bg-surface-secondary p-2.5", children: [(0, jsx_runtime_1.jsx)("p", { className: "truncate text-[11px] text-muted", children: metric.label }), (0, jsx_runtime_1.jsx)("p", { className: "mt-0.5 text-base font-semibold tabular-nums", children: (0, ai_format_js_1.formatAiValue)(metric.value, metric.format) }), delta !== null && ((0, jsx_runtime_1.jsxs)("p", { className: `mt-0.5 flex items-center gap-0.5 text-[11px] tabular-nums ${good === null ? "text-muted" : good ? "text-success" : "text-danger"}`, children: [(0, jsx_runtime_1.jsx)(Arrow, { className: "size-3", "aria-hidden": true }), (0, ai_format_js_1.formatAiValue)(Math.abs(delta), "percent")] })), metric.hint && (0, jsx_runtime_1.jsx)("p", { className: "mt-0.5 text-[10px] text-muted", children: metric.hint })] }, metric.label));
209
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "rounded-md bg-surface-secondary p-2.5", children: [(0, jsx_runtime_1.jsx)("p", { className: "truncate text-[11px] text-muted", children: metric.label }), (0, jsx_runtime_1.jsx)("p", { className: "mt-0.5 text-base font-semibold tabular-nums", children: (0, ai_format_js_1.formatAiValue)(metric.value, metric.format) }), delta !== null && ((0, jsx_runtime_1.jsxs)("p", { className: `mt-0.5 flex items-center gap-0.5 text-[11px] tabular-nums ${good === null ? "text-muted" : good ? "text-success-soft-foreground" : "text-danger-soft-foreground"}`, children: [(0, jsx_runtime_1.jsx)(Arrow, { className: "size-3", "aria-hidden": true }), (0, ai_format_js_1.formatAiValue)(Math.abs(delta), "percent")] })), metric.hint && (0, jsx_runtime_1.jsx)("p", { className: "mt-0.5 text-[10px] text-muted", children: metric.hint })] }, metric.label));
210
210
  }) }) }));
211
211
  }
212
212
  /** `showTimeline`: dated events, oldest first, on a single rail. */
@@ -219,7 +219,7 @@ function AiDetails({ title, fields }) {
219
219
  }
220
220
  /** `showSteps`: an ordered procedure. `renderDetail` is how the panel feeds each step back through its markdown renderer. */
221
221
  function AiSteps({ title, steps, renderDetail, }) {
222
- return ((0, jsx_runtime_1.jsx)(Panel, { title: title, children: (0, jsx_runtime_1.jsx)("ol", { className: "space-y-2.5", children: steps.map((step, index) => ((0, jsx_runtime_1.jsxs)("li", { className: "flex gap-2.5", children: [(0, jsx_runtime_1.jsx)("span", { className: "mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[10px] font-semibold text-accent", children: index + 1 }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium", children: step.title }), step.detail && ((0, jsx_runtime_1.jsx)("div", { className: "mt-0.5 text-xs text-muted", children: renderDetail ? renderDetail(step.detail) : (0, jsx_runtime_1.jsx)("span", { className: "whitespace-pre-wrap", children: step.detail }) }))] })] }, step.title))) }) }));
222
+ return ((0, jsx_runtime_1.jsx)(Panel, { title: title, children: (0, jsx_runtime_1.jsx)("ol", { className: "space-y-2.5", children: steps.map((step, index) => ((0, jsx_runtime_1.jsxs)("li", { className: "flex gap-2.5", children: [(0, jsx_runtime_1.jsx)("span", { className: "mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full bg-accent-soft text-[10px] font-semibold text-accent-soft-foreground", children: index + 1 }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-medium", children: step.title }), step.detail && ((0, jsx_runtime_1.jsx)("div", { className: "mt-0.5 text-xs text-muted", children: renderDetail ? renderDetail(step.detail) : (0, jsx_runtime_1.jsx)("span", { className: "whitespace-pre-wrap", children: step.detail }) }))] })] }, step.title))) }) }));
223
223
  }
224
224
  /**
225
225
  * `showSources`: what a grounded answer actually rested on. The point of a
@@ -58,7 +58,7 @@ function AppTile({ app, onOpen }) {
58
58
  // there is nothing to open and nothing to buy.
59
59
  const disabled = app.subscribed && app.launchUrl === null;
60
60
  const shared = "group/tile flex w-full flex-col items-center gap-2 rounded-2xl p-3 text-center outline-offset-2 transition-colors duration-200 focus-visible:outline-2 focus-visible:outline-focus";
61
- const body = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "relative flex size-14 items-center justify-center overflow-hidden rounded-[0.8125rem] bg-surface-secondary text-muted transition-colors duration-200 group-hover/tile:bg-default group-hover/tile:text-foreground", children: [(0, jsx_runtime_1.jsx)(AppGlyph, { app: app }), app.needsAttention && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-warning text-warning-foreground", children: (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: "size-3", "aria-hidden": "true" }) })), !app.subscribed && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-default text-muted opacity-0 transition-opacity duration-200 group-hover/tile:opacity-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-3", "aria-hidden": "true" }) }))] }), (0, jsx_runtime_1.jsx)("span", { className: "line-clamp-2 text-xs font-medium leading-tight text-foreground", children: app.name }), app.isCurrent ? ((0, jsx_runtime_1.jsx)("span", { className: "text-[0.625rem] uppercase tracking-wide text-accent", children: "Current" })) : (!app.subscribed && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-0.5 text-[0.625rem] uppercase tracking-wide text-muted opacity-0 transition-opacity duration-200 group-hover/tile:opacity-100", children: ["Subscribe", (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUpRight, { className: "size-2.5", "aria-hidden": "true" })] })))] }));
61
+ const body = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "relative flex size-14 items-center justify-center overflow-hidden rounded-[0.8125rem] bg-surface-secondary text-muted transition-colors duration-200 group-hover/tile:bg-default group-hover/tile:text-foreground", children: [(0, jsx_runtime_1.jsx)(AppGlyph, { app: app }), app.needsAttention && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-warning text-warning-foreground", children: (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: "size-3", "aria-hidden": "true" }) })), !app.subscribed && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-default text-muted opacity-0 transition-opacity duration-200 group-hover/tile:opacity-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-3", "aria-hidden": "true" }) }))] }), (0, jsx_runtime_1.jsx)("span", { className: "line-clamp-2 text-xs font-medium leading-tight text-foreground", children: app.name }), app.isCurrent ? ((0, jsx_runtime_1.jsx)("span", { className: "text-[0.625rem] uppercase tracking-wide text-accent-soft-foreground", children: "Current" })) : (!app.subscribed && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-0.5 text-[0.625rem] uppercase tracking-wide text-muted opacity-0 transition-opacity duration-200 group-hover/tile:opacity-100", children: ["Subscribe", (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUpRight, { className: "size-2.5", "aria-hidden": "true" })] })))] }));
62
62
  if (disabled) {
63
63
  return ((0, jsx_runtime_1.jsx)("div", { className: `${shared} cursor-default opacity-60`, title: `${app.name} has no launch URL configured`, children: body }));
64
64
  }
@@ -139,7 +139,7 @@ function ConnectAppsGrid({ className, label = "Switch app", variant = "row" }) {
139
139
  };
140
140
  const showSearch = apps.length > SEARCH_THRESHOLD;
141
141
  const isEmpty = !isLoading && !error && mine.length === 0 && explore.length === 0;
142
- return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal, { children: [variant === "row" ? ((0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "tertiary", "aria-label": label, className: (0, shell_context_js_1.sidebarRowClass)({ className }), children: [(0, jsx_runtime_1.jsx)("span", { className: "flex size-5 shrink-0 items-center justify-center", children: (0, jsx_runtime_1.jsx)(lucide_react_1.LayoutGrid, { className: "size-5" }) }), (0, jsx_runtime_1.jsx)(shell_context_js_1.SidebarLabel, { children: label })] })) : ((0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, variant: "primary", "aria-label": label, className: className, children: (0, jsx_runtime_1.jsx)(lucide_react_1.LayoutGrid, { className: "size-5" }) })), (0, jsx_runtime_1.jsx)(react_1.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal.Dialog, { className: "sm:max-w-lg", children: [(0, jsx_runtime_1.jsx)(react_1.Modal.CloseTrigger, {}), (0, jsx_runtime_1.jsx)(react_1.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Heading, { children: "Your apps" }) }), (0, jsx_runtime_1.jsxs)(react_1.Modal.Body, { className: "space-y-4", children: [showSearch && ((0, jsx_runtime_1.jsxs)(react_1.TextField, { className: "relative", variant: "secondary", value: query, onChange: setQuery, children: [(0, jsx_runtime_1.jsx)(react_1.Label, { className: "sr-only", children: "Filter apps" }), (0, jsx_runtime_1.jsx)(react_1.Input, { className: "pr-9", placeholder: "Filter apps" }), (0, jsx_runtime_1.jsx)(lucide_react_1.Search, { className: "pointer-events-none absolute right-3 top-1/2 size-4 -translate-y-1/2 text-muted", "aria-hidden": "true" })] })), isLoading && (0, jsx_runtime_1.jsx)(GridSkeleton, {}), !isLoading && error && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-danger", children: "Could not load your apps." })), isEmpty && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-muted", children: query
142
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal, { children: [variant === "row" ? ((0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "tertiary", "aria-label": label, className: (0, shell_context_js_1.sidebarRowClass)({ className }), children: [(0, jsx_runtime_1.jsx)("span", { className: "flex size-5 shrink-0 items-center justify-center", children: (0, jsx_runtime_1.jsx)(lucide_react_1.LayoutGrid, { className: "size-5" }) }), (0, jsx_runtime_1.jsx)(shell_context_js_1.SidebarLabel, { children: label })] })) : ((0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, variant: "primary", "aria-label": label, className: className, children: (0, jsx_runtime_1.jsx)(lucide_react_1.LayoutGrid, { className: "size-5" }) })), (0, jsx_runtime_1.jsx)(react_1.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal.Dialog, { className: "sm:max-w-lg", children: [(0, jsx_runtime_1.jsx)(react_1.Modal.CloseTrigger, {}), (0, jsx_runtime_1.jsx)(react_1.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Heading, { children: "Your apps" }) }), (0, jsx_runtime_1.jsxs)(react_1.Modal.Body, { className: "space-y-4", children: [showSearch && ((0, jsx_runtime_1.jsxs)(react_1.TextField, { className: "relative", variant: "secondary", value: query, onChange: setQuery, children: [(0, jsx_runtime_1.jsx)(react_1.Label, { className: "sr-only", children: "Filter apps" }), (0, jsx_runtime_1.jsx)(react_1.Input, { className: "pr-9", placeholder: "Filter apps" }), (0, jsx_runtime_1.jsx)(lucide_react_1.Search, { className: "pointer-events-none absolute right-3 top-1/2 size-4 -translate-y-1/2 text-muted", "aria-hidden": "true" })] })), isLoading && (0, jsx_runtime_1.jsx)(GridSkeleton, {}), !isLoading && error && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-danger-soft-foreground", children: "Could not load your apps." })), isEmpty && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-muted", children: query
143
143
  ? `Nothing matches “${query}”.`
144
144
  : "No apps yet. Anything this workspace can open shows up here." })), !isLoading && !error && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(AppsSection, { title: "Your apps", hint: "Open", apps: mine, offset: 0, onOpen: openApp }), (0, jsx_runtime_1.jsx)(AppsSection, { title: "Explore", hint: "Subscribe on Connect", apps: explore, offset: mine.length, onOpen: openApp })] }))] })] }) }) })] }) }));
145
145
  }
@@ -96,9 +96,9 @@ function AskAiHistory({ refreshKey, activeConversationId, onOpenConversation, })
96
96
  return ((0, jsx_runtime_1.jsx)("div", { className: "space-y-2 p-4", "aria-busy": "true", children: [0, 1, 2].map((row) => ((0, jsx_runtime_1.jsx)("div", { className: "h-9 animate-pulse rounded-md bg-surface-secondary" }, row))) }));
97
97
  }
98
98
  if (conversations.length === 0) {
99
- return ((0, jsx_runtime_1.jsx)("div", { className: "p-4", children: error ? ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-danger", children: error })) : ((0, jsx_runtime_1.jsx)("p", { className: "text-center text-xs text-muted", children: "Nothing here yet. Conversations you have are saved automatically." })) }));
99
+ return ((0, jsx_runtime_1.jsx)("div", { className: "p-4", children: error ? ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-danger-soft-foreground", children: error })) : ((0, jsx_runtime_1.jsx)("p", { className: "text-center text-xs text-muted", children: "Nothing here yet. Conversations you have are saved automatically." })) }));
100
100
  }
101
- return ((0, jsx_runtime_1.jsxs)("div", { className: "p-2", children: [error && (0, jsx_runtime_1.jsx)("p", { className: "px-2 pb-2 text-xs text-danger", children: error }), (0, jsx_runtime_1.jsx)("ul", { className: "space-y-0.5", children: conversations.map((conversation) => {
101
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-2", children: [error && (0, jsx_runtime_1.jsx)("p", { className: "px-2 pb-2 text-xs text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsx)("ul", { className: "space-y-0.5", children: conversations.map((conversation) => {
102
102
  const isConfirming = confirmingId === conversation.id;
103
103
  const isActive = conversation.id === activeConversationId;
104
104
  return ((0, jsx_runtime_1.jsx)("li", { children: isConfirming ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 rounded-md border border-border px-2 py-1.5", children: [(0, jsx_runtime_1.jsx)("span", { className: "flex-1 truncate text-xs text-muted", children: "Delete this conversation?" }), (0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "danger", className: "h-7 px-2 text-xs", isDisabled: busyId === conversation.id, onPress: () => void remove(conversation.id), children: "Delete" }), (0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "tertiary", className: "h-7 px-2 text-xs", onPress: () => setConfirmingId(null), children: "Cancel" })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: `group flex items-center gap-1 rounded-md ${isActive ? "bg-surface-secondary" : ""}`, children: [(0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "ghost", className: "h-auto min-w-0 flex-1 justify-start gap-2 px-2 py-1.5 text-start", isDisabled: busyId === conversation.id, onPress: () => void open(conversation.id), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.MessageSquare, { className: "size-3.5 shrink-0 text-muted" }), (0, jsx_runtime_1.jsx)("span", { className: "min-w-0 flex-1 truncate text-xs font-normal", children: conversation.title })] }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "ghost", className: "shrink-0", "aria-label": `Delete "${conversation.title}"`, onPress: () => setConfirmingId(conversation.id), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { className: "size-3.5 text-muted" }) })] })) }, conversation.id));
@@ -547,7 +547,7 @@ function ConnectAskAi({ title = "Ask AI", assistantName = "Assistant", placehold
547
547
  // Disabled on an empty one rather than hidden: a control that
548
548
  // appears and disappears as you use the panel is harder to find
549
549
  // than one that is always in the same place.
550
- isDisabled: turns.length === 0, onPress: startNewConversation, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": showHistory ? "Hide past conversations" : "Past conversations", "aria-pressed": showHistory, onPress: () => setShowHistory((open) => !open), children: (0, jsx_runtime_1.jsx)(lucide_react_1.History, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Close", onPress: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "size-4" }) })] }), showHistory ? ((0, jsx_runtime_1.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: (0, jsx_runtime_1.jsx)(ask_ai_history_js_1.AskAiHistory, { refreshKey: writeCount, activeConversationId: conversationId, onOpenConversation: openConversation }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [turns.length === 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: hint }), currentScreen?.suggestions?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-1.5", children: currentScreen.suggestions.map((suggestion) => ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "h-auto rounded-full px-2.5 py-1 text-start text-xs whitespace-normal", isDisabled: isBusy, onPress: () => void send(suggestion), children: suggestion }, suggestion))) })) : null] })), rendered, isBusy && lastTurn?.role === "user" && ((0, jsx_runtime_1.jsxs)("div", { className: "rounded-md border border-border bg-accent/5 p-2.5 text-sm", children: [(0, jsx_runtime_1.jsx)("p", { className: "mb-1 text-[11px] font-semibold tracking-wide text-muted uppercase", children: assistantName }), (0, jsx_runtime_1.jsx)(ThinkingShimmer, {})] })), error && ((0, jsx_runtime_1.jsxs)("div", { role: "alert", className: "flex items-start gap-2 rounded-md border border-danger/30 bg-danger/5 p-2.5 text-xs text-danger", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.TriangleAlert, { className: "mt-px size-3.5 shrink-0", "aria-hidden": true }), (0, jsx_runtime_1.jsx)("p", { className: "flex-1", children: error.message }), error.retry && ((0, jsx_runtime_1.jsxs)(react_2.Button, { size: "sm", variant: "tertiary", className: "h-6 shrink-0 px-2 text-xs", onPress: retry, isDisabled: isBusy, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "size-3", "aria-hidden": true }), "Try again"] }))] })), (0, jsx_runtime_1.jsx)("div", { ref: bottomRef })] })), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex gap-2 border-t border-border p-3", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", className: "flex-1", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { className: "sr-only", children: placeholder }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: placeholder, value: input, onChange: (event) => setInput(event.currentTarget.value), disabled: isBusy })] }), isBusy ? ((0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", isIconOnly: true, variant: "secondary", "aria-label": "Stop generating", onPress: stop, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Square, { className: "size-3.5" }) })) : ((0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", isIconOnly: true, variant: "primary", "aria-label": "Send", isDisabled: !input.trim(), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Send, { className: "size-3.5" }) }))] })] }) })] }));
550
+ isDisabled: turns.length === 0, onPress: startNewConversation, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": showHistory ? "Hide past conversations" : "Past conversations", "aria-pressed": showHistory, onPress: () => setShowHistory((open) => !open), children: (0, jsx_runtime_1.jsx)(lucide_react_1.History, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Close", onPress: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "size-4" }) })] }), showHistory ? ((0, jsx_runtime_1.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: (0, jsx_runtime_1.jsx)(ask_ai_history_js_1.AskAiHistory, { refreshKey: writeCount, activeConversationId: conversationId, onOpenConversation: openConversation }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [turns.length === 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: hint }), currentScreen?.suggestions?.length ? ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap gap-1.5", children: currentScreen.suggestions.map((suggestion) => ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "h-auto rounded-full px-2.5 py-1 text-start text-xs whitespace-normal", isDisabled: isBusy, onPress: () => void send(suggestion), children: suggestion }, suggestion))) })) : null] })), rendered, isBusy && lastTurn?.role === "user" && ((0, jsx_runtime_1.jsxs)("div", { className: "rounded-md border border-border bg-accent/5 p-2.5 text-sm", children: [(0, jsx_runtime_1.jsx)("p", { className: "mb-1 text-[11px] font-semibold tracking-wide text-muted uppercase", children: assistantName }), (0, jsx_runtime_1.jsx)(ThinkingShimmer, {})] })), error && ((0, jsx_runtime_1.jsxs)("div", { role: "alert", className: "flex items-start gap-2 rounded-md border border-danger/30 bg-danger-soft p-2.5 text-xs text-danger-soft-foreground", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.TriangleAlert, { className: "mt-px size-3.5 shrink-0", "aria-hidden": true }), (0, jsx_runtime_1.jsx)("p", { className: "flex-1", children: error.message }), error.retry && ((0, jsx_runtime_1.jsxs)(react_2.Button, { size: "sm", variant: "tertiary", className: "h-6 shrink-0 px-2 text-xs", onPress: retry, isDisabled: isBusy, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.RotateCcw, { className: "size-3", "aria-hidden": true }), "Try again"] }))] })), (0, jsx_runtime_1.jsx)("div", { ref: bottomRef })] })), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex gap-2 border-t border-border p-3", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", className: "flex-1", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { className: "sr-only", children: placeholder }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: placeholder, value: input, onChange: (event) => setInput(event.currentTarget.value), disabled: isBusy })] }), isBusy ? ((0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", isIconOnly: true, variant: "secondary", "aria-label": "Stop generating", onPress: stop, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Square, { className: "size-3.5" }) })) : ((0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", isIconOnly: true, variant: "primary", "aria-label": "Send", isDisabled: !input.trim(), children: (0, jsx_runtime_1.jsx)(lucide_react_1.Send, { className: "size-3.5" }) }))] })] }) })] }));
551
551
  }
552
552
  /** Hoisted for the same reference-equality reason as `ANIMATED` - Streamdown compares it by identity. */
553
553
  const LINK_SAFETY = { enabled: false };
@@ -99,5 +99,5 @@ function ScheduleFields({ editing, onCancel, onSaved, }) {
99
99
  const interval = weeklyHours[day][0];
100
100
  const isOpenDay = interval !== undefined;
101
101
  return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)(react_2.Switch, { isSelected: isOpenDay, onChange: (open) => toggleDay(day, open), isDisabled: isPending, children: (0, jsx_runtime_1.jsxs)(react_2.Switch.Content, { children: [(0, jsx_runtime_1.jsx)(react_2.Switch.Control, { children: (0, jsx_runtime_1.jsx)(react_2.Switch.Thumb, {}) }), (0, jsx_runtime_1.jsx)("span", { className: "w-24 shrink-0 text-sm", children: WEEKDAY_LABELS[day] })] }) }), isOpenDay && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Input, { type: "time", value: minutesToTimeInput(interval.startMinute), onChange: (e) => setDayTime(day, "startMinute", e.currentTarget.value), disabled: isPending }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-muted", children: "to" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "time", value: minutesToTimeInput(interval.endMinute), onChange: (e) => setDayTime(day, "endMinute", e.currentTarget.value), disabled: isPending })] }))] }, day));
102
- }) }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Saving..." : isEdit ? "Save changes" : "Save" })] })] }));
102
+ }) }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Saving..." : isEdit ? "Save changes" : "Save" })] })] }));
103
103
  }
@@ -69,7 +69,7 @@ function ConnectBookingCalendar({ timeZone, hostMemberId, window: visibleWindow
69
69
  const marks = (0, react_2.useMemo)(() => (0, booking_grid_js_1.hourMarks)(visibleWindow), [visibleWindow]);
70
70
  const shiftWeek = (weeks) => setWeekAnchor((anchor) => new Date(anchor.getTime() + weeks * 7 * 24 * 60 * 60_000));
71
71
  const eventTypeById = (0, react_2.useMemo)(() => new Map(eventTypes.map((eventType) => [eventType.id, eventType])), [eventTypes]);
72
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("flex flex-col gap-4", className), children: [(0, jsx_runtime_1.jsxs)("header", { className: "flex flex-wrap items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Previous week", onPress: () => shiftWeek(-1), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "secondary", onPress: () => setWeekAnchor(startOfWeek(new Date(), zone)), children: "Today" }), (0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Next week", onPress: () => shiftWeek(1), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)("p", { className: "ml-2 text-sm font-medium", children: weekLabel(columns, zone) })] }), canBook && eventTypes.length > 0 && ((0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "primary", onPress: () => setBooking({ startAt: nextHour(now) }), children: "New appointment" }))] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), isLoading ? ((0, jsx_runtime_1.jsx)(react_1.Skeleton, { className: "h-96 w-full rounded-lg" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Card, { className: "hidden overflow-hidden sm:block", children: (0, jsx_runtime_1.jsx)(WeekGrid, { columns: columns, marks: marks, window: visibleWindow, positioned: positioned, eventTypeById: eventTypeById, zone: zone, onSelect: setSelected, onPickEmpty: canBook ? (startAt) => setBooking({ startAt }) : undefined }) }), (0, jsx_runtime_1.jsx)("div", { className: "sm:hidden", children: (0, jsx_runtime_1.jsx)(AgendaView, { columns: columns, bookings: bookings, eventTypeById: eventTypeById, zone: zone, onSelect: setSelected }) })] })), booking && ((0, jsx_runtime_1.jsx)(booking_dialogs_js_1.ConnectBookingDialog, { isOpen: true, onOpenChange: (open) => !open && setBooking(null), eventTypes: eventTypes, initialStartAt: booking.startAt, timeZone: zone, onBooked: () => {
72
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("flex flex-col gap-4", className), children: [(0, jsx_runtime_1.jsxs)("header", { className: "flex flex-wrap items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Previous week", onPress: () => shiftWeek(-1), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "secondary", onPress: () => setWeekAnchor(startOfWeek(new Date(), zone)), children: "Today" }), (0, jsx_runtime_1.jsx)(react_1.Button, { isIconOnly: true, size: "sm", variant: "tertiary", "aria-label": "Next week", onPress: () => shiftWeek(1), children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { className: "size-4", "aria-hidden": true }) }), (0, jsx_runtime_1.jsx)("p", { className: "ml-2 text-sm font-medium", children: weekLabel(columns, zone) })] }), canBook && eventTypes.length > 0 && ((0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", variant: "primary", onPress: () => setBooking({ startAt: nextHour(now) }), children: "New appointment" }))] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), isLoading ? ((0, jsx_runtime_1.jsx)(react_1.Skeleton, { className: "h-96 w-full rounded-lg" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Card, { className: "hidden overflow-hidden sm:block", children: (0, jsx_runtime_1.jsx)(WeekGrid, { columns: columns, marks: marks, window: visibleWindow, positioned: positioned, eventTypeById: eventTypeById, zone: zone, onSelect: setSelected, onPickEmpty: canBook ? (startAt) => setBooking({ startAt }) : undefined }) }), (0, jsx_runtime_1.jsx)("div", { className: "sm:hidden", children: (0, jsx_runtime_1.jsx)(AgendaView, { columns: columns, bookings: bookings, eventTypeById: eventTypeById, zone: zone, onSelect: setSelected }) })] })), booking && ((0, jsx_runtime_1.jsx)(booking_dialogs_js_1.ConnectBookingDialog, { isOpen: true, onOpenChange: (open) => !open && setBooking(null), eventTypes: eventTypes, initialStartAt: booking.startAt, timeZone: zone, onBooked: () => {
73
73
  setBooking(null);
74
74
  refetch();
75
75
  } })), selected && ((0, jsx_runtime_1.jsx)(booking_dialogs_js_1.ConnectBookingDetail, { booking: selected, eventType: eventTypeById.get(selected.eventTypeId) ?? null, timeZone: zone, onOpenChange: (open) => !open && setSelected(null), onChanged: () => {
@@ -79,7 +79,7 @@ function ConnectBookingCalendar({ timeZone, hostMemberId, window: visibleWindow
79
79
  }
80
80
  function WeekGrid({ columns, marks, window: visibleWindow, positioned, eventTypeById, zone, onSelect, onPickEmpty, }) {
81
81
  const span = visibleWindow.endMinute - visibleWindow.startMinute;
82
- return ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-[3rem_repeat(7,minmax(0,1fr))]", children: [(0, jsx_runtime_1.jsx)("div", { className: "border-b border-separator" }), columns.map((column) => ((0, jsx_runtime_1.jsx)("div", { className: `border-b border-l border-separator px-2 py-2 text-center ${column.isToday ? "bg-accent/5" : ""}`, children: (0, jsx_runtime_1.jsx)("p", { className: `text-xs font-medium ${column.isToday ? "text-accent" : ""}`, children: column.label }) }, column.dateKey))), (0, jsx_runtime_1.jsx)("div", { className: "relative", style: { height: `${(span / 60) * 3}rem` }, children: marks.map((mark) => ((0, jsx_runtime_1.jsx)("span", { className: "absolute right-1 -translate-y-1/2 text-[0.625rem] text-muted", style: { top: `${((mark.minute - visibleWindow.startMinute) / span) * 100}%` }, children: mark.label }, mark.minute))) }), columns.map((column) => ((0, jsx_runtime_1.jsxs)("div", { className: `relative border-l border-separator ${column.isToday ? "bg-accent/5" : ""}`, style: { height: `${(span / 60) * 3}rem` }, children: [marks.map((mark) => ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-x-0 border-t border-separator/60", style: { top: `${((mark.minute - visibleWindow.startMinute) / span) * 100}%` } }, mark.minute))), onPickEmpty &&
82
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-[3rem_repeat(7,minmax(0,1fr))]", children: [(0, jsx_runtime_1.jsx)("div", { className: "border-b border-separator" }), columns.map((column) => ((0, jsx_runtime_1.jsx)("div", { className: `border-b border-l border-separator px-2 py-2 text-center ${column.isToday ? "bg-accent/5" : ""}`, children: (0, jsx_runtime_1.jsx)("p", { className: `text-xs font-medium ${column.isToday ? "text-accent-soft-foreground" : ""}`, children: column.label }) }, column.dateKey))), (0, jsx_runtime_1.jsx)("div", { className: "relative", style: { height: `${(span / 60) * 3}rem` }, children: marks.map((mark) => ((0, jsx_runtime_1.jsx)("span", { className: "absolute right-1 -translate-y-1/2 text-[0.625rem] text-muted", style: { top: `${((mark.minute - visibleWindow.startMinute) / span) * 100}%` }, children: mark.label }, mark.minute))) }), columns.map((column) => ((0, jsx_runtime_1.jsxs)("div", { className: `relative border-l border-separator ${column.isToday ? "bg-accent/5" : ""}`, style: { height: `${(span / 60) * 3}rem` }, children: [marks.map((mark) => ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-x-0 border-t border-separator/60", style: { top: `${((mark.minute - visibleWindow.startMinute) / span) * 100}%` } }, mark.minute))), onPickEmpty &&
83
83
  marks.map((mark) => ((0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": `Book ${column.label} at ${mark.label}`, className: "absolute inset-x-0 cursor-pointer transition-colors hover:bg-accent/10", style: {
84
84
  top: `${((mark.minute - visibleWindow.startMinute) / span) * 100}%`,
85
85
  height: `${(60 / span) * 100}%`,
@@ -94,7 +94,7 @@ function WeekGrid({ columns, marks, window: visibleWindow, positioned, eventType
94
94
  // gap so two adjacent blocks read as two things.
95
95
  left: `${(entry.column / entry.columns) * 100}%`,
96
96
  width: `calc(${(1 / entry.columns) * 100}% - 2px)`,
97
- }, children: [(0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem] font-medium text-accent", children: timeLabel(new Date(entry.booking.startAt), zone) }), (0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem]", children: entry.booking.attendee.name }), eventType && ((0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem] text-muted", children: eventType.name }))] }, entry.booking.id));
97
+ }, children: [(0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem] font-medium text-accent-soft-foreground", children: timeLabel(new Date(entry.booking.startAt), zone) }), (0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem]", children: entry.booking.attendee.name }), eventType && ((0, jsx_runtime_1.jsx)("span", { className: "block truncate text-[0.625rem] text-muted", children: eventType.name }))] }, entry.booking.id));
98
98
  })] }, column.dateKey)))] }));
99
99
  }
100
100
  function AgendaView({ columns, bookings, eventTypeById, zone, onSelect, }) {
@@ -113,7 +113,7 @@ function AgendaView({ columns, bookings, eventTypeById, zone, onSelect, }) {
113
113
  if (populated.length === 0) {
114
114
  return ((0, jsx_runtime_1.jsx)(empty_state_js_1.ConnectEmptyState, { variant: "dashed", icon: (0, jsx_runtime_1.jsx)(lucide_react_1.CalendarDays, { "aria-hidden": true }), title: "Nothing booked this week", description: "Appointments booked here, on your public link, or by a voice agent all show up together." }));
115
115
  }
116
- return ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-4", children: populated.map((column) => ((0, jsx_runtime_1.jsxs)("section", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: `text-sm font-medium ${column.isToday ? "text-accent" : ""}`, children: column.label }), (byDay.get(column.dateKey) ?? []).map((booking) => {
116
+ return ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-4", children: populated.map((column) => ((0, jsx_runtime_1.jsxs)("section", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("h3", { className: `text-sm font-medium ${column.isToday ? "text-accent-soft-foreground" : ""}`, children: column.label }), (byDay.get(column.dateKey) ?? []).map((booking) => {
117
117
  const eventType = eventTypeById.get(booking.eventTypeId);
118
118
  const Icon = eventType ? LOCATION_ICON[eventType.locationKind] : lucide_react_1.CalendarDays;
119
119
  return ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: () => onSelect(booking), children: (0, jsx_runtime_1.jsx)(react_1.Card, { className: "transition-colors hover:bg-surface", children: (0, jsx_runtime_1.jsxs)(react_1.Card.Content, { className: "flex items-center gap-3 py-3 text-left", children: [(0, jsx_runtime_1.jsx)(Icon, { className: "size-4 shrink-0 text-muted", "aria-hidden": true }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "truncate text-sm font-medium", children: booking.attendee.name }), (0, jsx_runtime_1.jsxs)("p", { className: "truncate text-xs text-muted", children: [timeLabel(new Date(booking.startAt), zone), eventType ? ` · ${eventType.name}` : ""] })] }), booking.source === "agent-call" && ((0, jsx_runtime_1.jsxs)(react_1.Chip, { size: "sm", variant: "secondary", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Phone, { className: "size-3", "aria-hidden": true }), "Agent"] }))] }) }) }, booking.id));
@@ -38,7 +38,7 @@ function ConnectBookingDialog({ isOpen, onOpenChange, eventTypes, initialStartAt
38
38
  // The old pick belongs to the old type's grid and is
39
39
  // almost never a legal slot on the new one.
40
40
  setChosen(null);
41
- }, children: eventType.name }, eventType.id))) })), (0, jsx_runtime_1.jsx)(SlotPicker, { slots: slots, isLoading: isLoading, chosen: chosen, onChoose: setChosen, timeZone: timeZone }), (0, jsx_runtime_1.jsxs)(react_1.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_1.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_1.Input, { value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_1.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_1.Label, { children: "Phone" }), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "tel", value: phone, onChange: (e) => setPhone(e.currentTarget.value), disabled: isPending })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { variant: "secondary", onPress: () => onOpenChange(false), isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "primary", isDisabled: !canSubmit, onPress: async () => {
41
+ }, children: eventType.name }, eventType.id))) })), (0, jsx_runtime_1.jsx)(SlotPicker, { slots: slots, isLoading: isLoading, chosen: chosen, onChoose: setChosen, timeZone: timeZone }), (0, jsx_runtime_1.jsxs)(react_1.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_1.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_1.Input, { value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_1.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_1.Label, { children: "Phone" }), (0, jsx_runtime_1.jsx)(react_1.Input, { type: "tel", value: phone, onChange: (e) => setPhone(e.currentTarget.value), disabled: isPending })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { variant: "secondary", onPress: () => onOpenChange(false), isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "primary", isDisabled: !canSubmit, onPress: async () => {
42
42
  clearError();
43
43
  const booked = await createBooking({
44
44
  eventTypeId,
@@ -66,7 +66,7 @@ function ConnectBookingDetail({ booking, eventType, timeZone, onOpenChange, onCh
66
66
  to: new Date(start.getTime() + SEARCH_DAYS * 24 * 60 * 60_000),
67
67
  }), [start]);
68
68
  const { slots, isLoading } = (0, use_scheduling_js_1.useAvailableSlots)(isMoving ? { eventTypeId: booking.eventTypeId, ...window, excludeBookingId: booking.id } : null);
69
- return ((0, jsx_runtime_1.jsx)(react_1.Modal, { isOpen: true, onOpenChange: onOpenChange, children: (0, jsx_runtime_1.jsx)(react_1.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal.Dialog, { children: [(0, jsx_runtime_1.jsx)(react_1.Modal.Header, { children: booking.attendee.name }), (0, jsx_runtime_1.jsxs)(react_1.Modal.Body, { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1", children: [(0, jsx_runtime_1.jsxs)("p", { className: "flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Clock, { className: "size-4 text-muted", "aria-hidden": true }), longLabel(start, timeZone)] }), eventType && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: eventType.name }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: booking.attendee.phone }), booking.notes && (0, jsx_runtime_1.jsx)("p", { className: "pt-1 text-sm", children: booking.notes })] }), isMoving && ((0, jsx_runtime_1.jsx)(SlotPicker, { slots: slots, isLoading: isLoading, chosen: chosen, onChoose: setChosen, timeZone: timeZone })), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap justify-end gap-2", children: isMoving ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Button, { variant: "secondary", onPress: () => setMoving(false), isDisabled: isPending, children: "Back" }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "primary", isDisabled: !chosen || isPending, onPress: async () => {
69
+ return ((0, jsx_runtime_1.jsx)(react_1.Modal, { isOpen: true, onOpenChange: onOpenChange, children: (0, jsx_runtime_1.jsx)(react_1.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_1.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_1.Modal.Dialog, { children: [(0, jsx_runtime_1.jsx)(react_1.Modal.Header, { children: booking.attendee.name }), (0, jsx_runtime_1.jsxs)(react_1.Modal.Body, { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-1", children: [(0, jsx_runtime_1.jsxs)("p", { className: "flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Clock, { className: "size-4 text-muted", "aria-hidden": true }), longLabel(start, timeZone)] }), eventType && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: eventType.name }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: booking.attendee.phone }), booking.notes && (0, jsx_runtime_1.jsx)("p", { className: "pt-1 text-sm", children: booking.notes })] }), isMoving && ((0, jsx_runtime_1.jsx)(SlotPicker, { slots: slots, isLoading: isLoading, chosen: chosen, onChoose: setChosen, timeZone: timeZone })), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-wrap justify-end gap-2", children: isMoving ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Button, { variant: "secondary", onPress: () => setMoving(false), isDisabled: isPending, children: "Back" }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "primary", isDisabled: !chosen || isPending, onPress: async () => {
70
70
  clearError();
71
71
  const moved = await rescheduleBooking({
72
72
  bookingId: booking.id,
@@ -360,7 +360,7 @@ function unavailableReason(availability) {
360
360
  function ConnectCallUnavailable({ availability, className, }) {
361
361
  const { text, action } = unavailableReason(availability);
362
362
  const href = (0, portal_links_js_1.useConnectPortalUrl)(action?.path ?? "/calling");
363
- return ((0, jsx_runtime_1.jsxs)("p", { className: (0, cn_js_1.cn)("text-xs text-muted", className), children: [text, " ", action && ((0, jsx_runtime_1.jsx)("a", { href: href, className: "font-medium text-accent hover:underline", children: action.label }))] }));
363
+ return ((0, jsx_runtime_1.jsxs)("p", { className: (0, cn_js_1.cn)("text-xs text-muted", className), children: [text, " ", action && ((0, jsx_runtime_1.jsx)("a", { href: href, className: "font-medium text-link hover:underline", children: action.label }))] }));
364
364
  }
365
365
  function formatRupees(paise) {
366
366
  return `₹${(paise / 100).toLocaleString("en-IN", {
@@ -382,13 +382,13 @@ function ConnectCallingStatus({ className }) {
382
382
  return (0, jsx_runtime_1.jsx)("div", { className: (0, cn_js_1.cn)("h-24 animate-pulse rounded-lg bg-surface-secondary", className) });
383
383
  }
384
384
  const rate = formatRupees(availability.ratePaisePerMinute);
385
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("space-y-3 rounded-lg border border-separator bg-surface p-4", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Business number" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium tabular-nums", children: availability.number ?? (availability.status === "number_pending" ? "Being set up…" : "None") })] }), availability.number && ((0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Calling minutes" }), (0, jsx_runtime_1.jsxs)("p", { className: (0, cn_js_1.cn)("text-sm font-medium tabular-nums", availability.lowBalance && "text-danger"), children: [formatRupees(availability.available), " \u00B7 about ", availability.availableMinutes, " min"] })] }))] }), availability.status === "no_permission" ? ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "You don't have permission to make calls here." })) : !availability.number ? ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-muted", children: ["Call customers from their record, from your own business number. Calls are not recorded, and minutes are prepaid at ", rate, " + GST a minute.", " ", availability.status === "number_pending"
386
- ? availability.canManageNumber && ((0, jsx_runtime_1.jsx)("a", { href: callingHref, className: "font-medium text-accent hover:underline", children: "Check on your number" }))
385
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("space-y-3 rounded-lg border border-separator bg-surface p-4", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "min-w-0", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Business number" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium tabular-nums", children: availability.number ?? (availability.status === "number_pending" ? "Being set up…" : "None") })] }), availability.number && ((0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "Calling minutes" }), (0, jsx_runtime_1.jsxs)("p", { className: (0, cn_js_1.cn)("text-sm font-medium tabular-nums", availability.lowBalance && "text-danger-soft-foreground"), children: [formatRupees(availability.available), " \u00B7 about ", availability.availableMinutes, " min"] })] }))] }), availability.status === "no_permission" ? ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: "You don't have permission to make calls here." })) : !availability.number ? ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-muted", children: ["Call customers from their record, from your own business number. Calls are not recorded, and minutes are prepaid at ", rate, " + GST a minute.", " ", availability.status === "number_pending"
386
+ ? availability.canManageNumber && ((0, jsx_runtime_1.jsx)("a", { href: callingHref, className: "font-medium text-link hover:underline", children: "Check on your number" }))
387
387
  : availability.canManageNumber && availability.offer
388
- ? ((0, jsx_runtime_1.jsxs)("a", { href: offerHref, className: "font-medium text-accent hover:underline", children: ["Add ", availability.offer.addonName, " (", formatRupees(availability.offer.price), " + GST)"] }))
388
+ ? ((0, jsx_runtime_1.jsxs)("a", { href: offerHref, className: "font-medium text-link hover:underline", children: ["Add ", availability.offer.addonName, " (", formatRupees(availability.offer.price), " + GST)"] }))
389
389
  : "Ask a workspace admin to add a business number."] })) : ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-muted", children: [availability.lowBalance
390
390
  ? "Calling minutes are running low. "
391
- : `Calls cost ${rate} + GST a minute, from prepaid minutes. `, availability.canTopUp ? ((0, jsx_runtime_1.jsx)("a", { href: callingHref, className: "font-medium text-accent hover:underline", children: "Top up minutes" })) : ("A workspace admin can top up.")] }))] }));
391
+ : `Calls cost ${rate} + GST a minute, from prepaid minutes. `, availability.canTopUp ? ((0, jsx_runtime_1.jsx)("a", { href: callingHref, className: "font-medium text-link hover:underline", children: "Top up minutes" })) : ("A workspace admin can top up.")] }))] }));
392
392
  }
393
393
  const PHASE_LABEL = {
394
394
  connecting: "Connecting…",
@@ -410,7 +410,7 @@ function ConnectActiveCallBar({ call, onHangUp, onToggleMute, className, }) {
410
410
  ? `Call ended · ${formatSeconds(call.endedAfterSeconds)}`
411
411
  : PHASE_LABEL[call.phase];
412
412
  const remaining = call.phase === "ended" ? minutesLeftLabel(call.minutesLeft) : null;
413
- return ((0, jsx_runtime_1.jsx)("div", { role: "status", "aria-live": "polite", className: (0, cn_js_1.cn)("fixed inset-x-0 bottom-4 z-50 flex justify-center px-4", className), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex w-full max-w-sm items-center gap-3 rounded-2xl border border-separator bg-surface p-3 shadow-lg", children: [(0, jsx_runtime_1.jsx)("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-accent-soft text-accent", children: (0, jsx_runtime_1.jsx)(lucide_react_1.PhoneOutgoing, { "aria-hidden": true, className: "size-4" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "truncate text-sm font-medium", children: call.label }), (0, jsx_runtime_1.jsxs)("p", { className: "truncate text-xs text-muted tabular-nums", children: [status, call.notice ? ` · ${call.notice}` : call.label === call.number ? "" : ` · ${call.number}`] }), remaining && (0, jsx_runtime_1.jsx)("p", { className: "truncate text-xs text-muted tabular-nums", children: remaining })] }), live && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "secondary", "aria-label": call.muted ? "Unmute" : "Mute", isDisabled: call.phase !== "in-call", onPress: onToggleMute, children: call.muted ? (0, jsx_runtime_1.jsx)(lucide_react_1.MicOff, { className: "size-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Mic, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "danger", "aria-label": "Hang up", onPress: onHangUp, children: (0, jsx_runtime_1.jsx)(lucide_react_1.PhoneOff, { className: "size-4" }) })] }))] }) }));
413
+ return ((0, jsx_runtime_1.jsx)("div", { role: "status", "aria-live": "polite", className: (0, cn_js_1.cn)("fixed inset-x-0 bottom-4 z-50 flex justify-center px-4", className), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex w-full max-w-sm items-center gap-3 rounded-2xl border border-separator bg-surface p-3 shadow-lg", children: [(0, jsx_runtime_1.jsx)("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-accent-soft text-accent-soft-foreground", children: (0, jsx_runtime_1.jsx)(lucide_react_1.PhoneOutgoing, { "aria-hidden": true, className: "size-4" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "min-w-0 flex-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "truncate text-sm font-medium", children: call.label }), (0, jsx_runtime_1.jsxs)("p", { className: "truncate text-xs text-muted tabular-nums", children: [status, call.notice ? ` · ${call.notice}` : call.label === call.number ? "" : ` · ${call.number}`] }), remaining && (0, jsx_runtime_1.jsx)("p", { className: "truncate text-xs text-muted tabular-nums", children: remaining })] }), live && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "secondary", "aria-label": call.muted ? "Unmute" : "Mute", isDisabled: call.phase !== "in-call", onPress: onToggleMute, children: call.muted ? (0, jsx_runtime_1.jsx)(lucide_react_1.MicOff, { className: "size-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Mic, { className: "size-4" }) }), (0, jsx_runtime_1.jsx)(react_2.Button, { isIconOnly: true, size: "sm", variant: "danger", "aria-label": "Hang up", onPress: onHangUp, children: (0, jsx_runtime_1.jsx)(lucide_react_1.PhoneOff, { className: "size-4" }) })] }))] }) }));
414
414
  }
415
415
  /** "42 min of calling left", once the post-call balance read has landed. */
416
416
  function minutesLeftLabel(minutes) {
@@ -62,5 +62,5 @@ function CreateWorkspaceFields({ onCancel, onCreated, }) {
62
62
  if (created)
63
63
  onCreated(created);
64
64
  };
65
- return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: "Acme Logistics", value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending, autoFocus: true })] }), (0, jsx_runtime_1.jsxs)(react_2.RadioGroup, { variant: "secondary", value: type, onChange: (value) => setType(value), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Type" }), (0, jsx_runtime_1.jsx)("div", { className: "mt-1.5 flex flex-col gap-2", children: WORKSPACE_TYPES.map((option) => ((0, jsx_runtime_1.jsx)(react_2.Radio, { value: option.id, children: (0, jsx_runtime_1.jsxs)(react_2.Radio.Content, { children: [(0, jsx_runtime_1.jsx)(react_2.Radio.Control, { children: (0, jsx_runtime_1.jsx)(react_2.Radio.Indicator, {}) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium", children: option.label }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: option.hint })] })] }) }, option.id))) })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Creating…" : "Create" })] })] }));
65
+ return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: "Acme Logistics", value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending, autoFocus: true })] }), (0, jsx_runtime_1.jsxs)(react_2.RadioGroup, { variant: "secondary", value: type, onChange: (value) => setType(value), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Type" }), (0, jsx_runtime_1.jsx)("div", { className: "mt-1.5 flex flex-col gap-2", children: WORKSPACE_TYPES.map((option) => ((0, jsx_runtime_1.jsx)(react_2.Radio, { value: option.id, children: (0, jsx_runtime_1.jsxs)(react_2.Radio.Content, { children: [(0, jsx_runtime_1.jsx)(react_2.Radio.Control, { children: (0, jsx_runtime_1.jsx)(react_2.Radio.Indicator, {}) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-medium", children: option.label }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-muted", children: option.hint })] })] }) }, option.id))) })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Creating…" : "Create" })] })] }));
66
66
  }
@@ -152,5 +152,5 @@ function EventTypeFields({ editing, schedules, members, onCancel, onSaved, }) {
152
152
  if (saved)
153
153
  onSaved(saved);
154
154
  };
155
- return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: "Consultation", value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending, autoFocus: true })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Description" }), (0, jsx_runtime_1.jsx)(react_2.TextArea, { placeholder: "What this appointment is for", value: description, onChange: (e) => setDescription(e.currentTarget.value), disabled: isPending, rows: 2 })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid gap-4 sm:grid-cols-3", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Length (min)" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(durationMinutes), onChange: (e) => setDurationMinutes(Number(e.currentTarget.value)), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Gap before" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(bufferBefore), onChange: (e) => setBufferBefore(Number(e.currentTarget.value)), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Gap after" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(bufferAfter), onChange: (e) => setBufferAfter(Number(e.currentTarget.value)), disabled: isPending })] })] }), schedules.length > 1 && ((0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: effectiveScheduleId, onChange: (value) => setScheduleId(String(value)), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Availability" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: schedules.map((schedule) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: schedule.id, textValue: schedule.name, children: [schedule.name, (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, schedule.id))) }) })] })), members.length > 1 && ((0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: effectiveHostMemberId, onChange: (value) => setHostMemberId(String(value)), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Who hosts it" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: members.map((member) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: member.memberId, textValue: member.displayName ?? member.email, children: [member.displayName ?? member.email, (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, member.memberId))) }) })] })), (0, jsx_runtime_1.jsxs)("div", { className: "grid gap-4 sm:grid-cols-2", children: [(0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: locationKind, onChange: (value) => setLocationKind(value), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Where" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: LOCATION_KINDS.map((kind) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: kind, textValue: LOCATION_LABELS[kind], children: [LOCATION_LABELS[kind], (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, kind))) }) })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Details" }), (0, jsx_runtime_1.jsx)(react_2.TextArea, { placeholder: locationKind === "address" ? "Where to come" : "Left blank is fine", value: locationValue, onChange: (e) => setLocationValue(e.currentTarget.value), disabled: isPending, rows: 2 })] })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Saving..." : isEdit ? "Save changes" : "Create" })] })] }));
155
+ return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Name" }), (0, jsx_runtime_1.jsx)(react_2.Input, { placeholder: "Consultation", value: name, onChange: (e) => setName(e.currentTarget.value), disabled: isPending, autoFocus: true })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Description" }), (0, jsx_runtime_1.jsx)(react_2.TextArea, { placeholder: "What this appointment is for", value: description, onChange: (e) => setDescription(e.currentTarget.value), disabled: isPending, rows: 2 })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid gap-4 sm:grid-cols-3", children: [(0, jsx_runtime_1.jsxs)(react_2.TextField, { isRequired: true, variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Length (min)" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(durationMinutes), onChange: (e) => setDurationMinutes(Number(e.currentTarget.value)), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Gap before" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(bufferBefore), onChange: (e) => setBufferBefore(Number(e.currentTarget.value)), disabled: isPending })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Gap after" }), (0, jsx_runtime_1.jsx)(react_2.Input, { type: "number", value: String(bufferAfter), onChange: (e) => setBufferAfter(Number(e.currentTarget.value)), disabled: isPending })] })] }), schedules.length > 1 && ((0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: effectiveScheduleId, onChange: (value) => setScheduleId(String(value)), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Availability" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: schedules.map((schedule) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: schedule.id, textValue: schedule.name, children: [schedule.name, (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, schedule.id))) }) })] })), members.length > 1 && ((0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: effectiveHostMemberId, onChange: (value) => setHostMemberId(String(value)), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Who hosts it" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: members.map((member) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: member.memberId, textValue: member.displayName ?? member.email, children: [member.displayName ?? member.email, (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, member.memberId))) }) })] })), (0, jsx_runtime_1.jsxs)("div", { className: "grid gap-4 sm:grid-cols-2", children: [(0, jsx_runtime_1.jsxs)(react_2.Select, { variant: "secondary", value: locationKind, onChange: (value) => setLocationKind(value), isDisabled: isPending, children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Where" }), (0, jsx_runtime_1.jsxs)(react_2.Select.Trigger, { children: [(0, jsx_runtime_1.jsx)(react_2.Select.Value, {}), (0, jsx_runtime_1.jsx)(react_2.Select.Indicator, {})] }), (0, jsx_runtime_1.jsx)(react_2.Select.Popover, { children: (0, jsx_runtime_1.jsx)(react_2.ListBox, { children: LOCATION_KINDS.map((kind) => ((0, jsx_runtime_1.jsxs)(react_2.ListBox.Item, { id: kind, textValue: LOCATION_LABELS[kind], children: [LOCATION_LABELS[kind], (0, jsx_runtime_1.jsx)(react_2.ListBox.ItemIndicator, {})] }, kind))) }) })] }), (0, jsx_runtime_1.jsxs)(react_2.TextField, { variant: "secondary", children: [(0, jsx_runtime_1.jsx)(react_2.Label, { children: "Details" }), (0, jsx_runtime_1.jsx)(react_2.TextArea, { placeholder: locationKind === "address" ? "Where to come" : "Left blank is fine", value: locationValue, onChange: (e) => setLocationValue(e.currentTarget.value), disabled: isPending, rows: 2 })] })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-2", children: [(0, jsx_runtime_1.jsx)(react_2.Button, { type: "button", variant: "secondary", onPress: onCancel, isDisabled: isPending, children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { type: "submit", variant: "primary", isDisabled: !isFormValid, children: isPending ? "Saving..." : isEdit ? "Save changes" : "Create" })] })] }));
156
156
  }
@@ -37,6 +37,6 @@ function ConnectFilterTabs({ options, value, onChange, label, className, }) {
37
37
  */
38
38
  (0, jsx_runtime_1.jsx)("div", { role: "radiogroup", "aria-label": label, className: (0, cn_js_1.cn)("-mx-1 flex flex-wrap gap-2 px-1", className), children: options.map((option) => {
39
39
  const isSelected = option.value === value;
40
- return ((0, jsx_runtime_1.jsx)("button", { type: "button", role: "radio", "aria-checked": isSelected, onClick: () => onChange(option.value), className: "shrink-0 rounded-full focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent", children: (0, jsx_runtime_1.jsxs)(react_1.Chip, { variant: isSelected ? "primary" : "soft", color: isSelected ? "accent" : "default", className: "min-h-8 px-3.5 py-1.5 text-sm", children: [option.label, option.count !== undefined && (0, jsx_runtime_1.jsx)("span", { className: "ml-1 opacity-70", children: option.count })] }) }, option.value ?? "__all"));
40
+ return ((0, jsx_runtime_1.jsx)("button", { type: "button", role: "radio", "aria-checked": isSelected, onClick: () => onChange(option.value), className: "shrink-0 rounded-full focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus", children: (0, jsx_runtime_1.jsxs)(react_1.Chip, { variant: isSelected ? "primary" : "soft", color: isSelected ? "accent" : "default", className: "min-h-8 px-3.5 py-1.5 text-sm", children: [option.label, option.count !== undefined && (0, jsx_runtime_1.jsx)("span", { className: "ml-1 opacity-70", children: option.count })] }) }, option.value ?? "__all"));
41
41
  }) }));
42
42
  }
@@ -27,5 +27,5 @@ function ConnectGrievanceNotice({ title = "Grievance redressal", applicationName
27
27
  if (!profile)
28
28
  return null;
29
29
  const { grievance } = profile;
30
- return ((0, jsx_runtime_1.jsxs)("section", { className: (0, cn_js_1.cn)("space-y-3", className), children: [title !== null && (0, jsx_runtime_1.jsx)("h3", { className: "text-base font-semibold", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-muted", children: [applicationName ? `${applicationName} is operated on ` : "This service runs on ", "the CosmoOps Connect platform. ", (0, jsx_runtime_1.jsx)("strong", { className: "font-medium text-foreground", children: profile.legalName }), " ", "is the Data Fiduciary for personal data processed here, under the Digital Personal Data Protection Act, 2023."] }), (0, jsx_runtime_1.jsxs)("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-3 text-sm sm:grid-cols-[auto_1fr]", children: [(0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Grievance Officer" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: grievance.officerName }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Email" }), (0, jsx_runtime_1.jsx)("dd", { children: (0, jsx_runtime_1.jsx)("a", { className: "text-accent underline underline-offset-2", href: `mailto:${grievance.officerEmail}`, children: grievance.officerEmail }) }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Contactable" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: grievance.hours }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Registered address" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: profile.registeredAddress })] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-muted", children: ["Complaints are acknowledged and resolved within ", grievance.responseDays, " days of receipt."] })] }));
30
+ return ((0, jsx_runtime_1.jsxs)("section", { className: (0, cn_js_1.cn)("space-y-3", className), children: [title !== null && (0, jsx_runtime_1.jsx)("h3", { className: "text-base font-semibold", children: title }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-muted", children: [applicationName ? `${applicationName} is operated on ` : "This service runs on ", "the CosmoOps Connect platform. ", (0, jsx_runtime_1.jsx)("strong", { className: "font-medium text-foreground", children: profile.legalName }), " ", "is the Data Fiduciary for personal data processed here, under the Digital Personal Data Protection Act, 2023."] }), (0, jsx_runtime_1.jsxs)("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-3 text-sm sm:grid-cols-[auto_1fr]", children: [(0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Grievance Officer" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: grievance.officerName }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Email" }), (0, jsx_runtime_1.jsx)("dd", { children: (0, jsx_runtime_1.jsx)("a", { className: "text-link underline underline-offset-2", href: `mailto:${grievance.officerEmail}`, children: grievance.officerEmail }) }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Contactable" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: grievance.hours }), (0, jsx_runtime_1.jsx)("dt", { className: "text-muted", children: "Registered address" }), (0, jsx_runtime_1.jsx)("dd", { className: "text-foreground", children: profile.registeredAddress })] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-muted", children: ["Complaints are acknowledged and resolved within ", grievance.responseDays, " days of receipt."] })] }));
31
31
  }
@@ -42,7 +42,7 @@ function ToolkitTile({ toolkit, isPending, onConnect, onDisconnect }) {
42
42
  // Deliberately a plain `<img>`: this package ships into any React app
43
43
  // and cannot assume `next/image` or any other framework loader.
44
44
  // eslint-disable-next-line @next/next/no-img-element
45
- (0, jsx_runtime_1.jsx)("img", { src: toolkit.logoUrl, alt: "", className: "size-full object-cover" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Puzzle, { className: "size-6 text-muted", "aria-hidden": "true" })), toolkit.status === "failed" && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-danger text-danger-foreground", children: (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: "size-3", "aria-hidden": "true" }) }))] }), (0, jsx_runtime_1.jsx)("span", { className: "line-clamp-2 text-center text-xs font-medium text-foreground", children: toolkit.name }), (0, jsx_runtime_1.jsx)(react_2.Chip, { size: "sm", variant: "soft", color: STATUS_COLOR[toolkit.status], children: STATUS_LABEL[toolkit.status] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex w-full flex-col gap-1.5 pt-1", children: [CAN_CONNECT.has(toolkit.status) && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "w-full text-xs", isPending: isPending, isDisabled: isPending, onPress: onConnect, children: "Connect" })), toolkit.status === "active" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "w-full text-xs", isPending: isPending, isDisabled: isPending, onPress: onConnect, children: "Reconnect" }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog, { isOpen: confirmingDisconnect, onOpenChange: setConfirmingDisconnect, children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "tertiary", className: "w-full text-xs text-danger", isDisabled: isPending, children: "Disconnect" }), (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Container, { children: (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Dialog, { className: "sm:max-w-100", children: [(0, jsx_runtime_1.jsx)(react_2.AlertDialog.CloseTrigger, {}), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Header, { children: [(0, jsx_runtime_1.jsx)(react_2.AlertDialog.Icon, { status: "danger" }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Heading, { children: ["Disconnect ", toolkit.name, "?"] })] }), (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Body, { children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: "Every member loses this connection immediately - it can be reconnected later." }) }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Footer, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { slot: "close", variant: "secondary", className: "text-xs", children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { slot: "close", variant: "danger", className: "text-xs", onPress: onDisconnect, children: "Disconnect" })] })] }) }) })] })] })), toolkit.status === "pending" && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "tertiary", className: "w-full text-xs text-danger", isDisabled: isPending, onPress: onDisconnect, children: "Cancel" }))] })] }));
45
+ (0, jsx_runtime_1.jsx)("img", { src: toolkit.logoUrl, alt: "", className: "size-full object-cover" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Puzzle, { className: "size-6 text-muted", "aria-hidden": "true" })), toolkit.status === "failed" && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-danger text-danger-foreground", children: (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: "size-3", "aria-hidden": "true" }) }))] }), (0, jsx_runtime_1.jsx)("span", { className: "line-clamp-2 text-center text-xs font-medium text-foreground", children: toolkit.name }), (0, jsx_runtime_1.jsx)(react_2.Chip, { size: "sm", variant: "soft", color: STATUS_COLOR[toolkit.status], children: STATUS_LABEL[toolkit.status] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex w-full flex-col gap-1.5 pt-1", children: [CAN_CONNECT.has(toolkit.status) && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "w-full text-xs", isPending: isPending, isDisabled: isPending, onPress: onConnect, children: "Connect" })), toolkit.status === "active" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "secondary", className: "w-full text-xs", isPending: isPending, isDisabled: isPending, onPress: onConnect, children: "Reconnect" }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog, { isOpen: confirmingDisconnect, onOpenChange: setConfirmingDisconnect, children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "danger-soft", className: "w-full text-xs", isDisabled: isPending, children: "Disconnect" }), (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Container, { children: (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Dialog, { className: "sm:max-w-100", children: [(0, jsx_runtime_1.jsx)(react_2.AlertDialog.CloseTrigger, {}), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Header, { children: [(0, jsx_runtime_1.jsx)(react_2.AlertDialog.Icon, { status: "danger" }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Heading, { children: ["Disconnect ", toolkit.name, "?"] })] }), (0, jsx_runtime_1.jsx)(react_2.AlertDialog.Body, { children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: "Every member loses this connection immediately - it can be reconnected later." }) }), (0, jsx_runtime_1.jsxs)(react_2.AlertDialog.Footer, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { slot: "close", variant: "secondary", className: "text-xs", children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_2.Button, { slot: "close", variant: "danger", className: "text-xs", onPress: onDisconnect, children: "Disconnect" })] })] }) }) })] })] })), toolkit.status === "pending" && ((0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "danger-soft", className: "w-full text-xs", isDisabled: isPending, onPress: onDisconnect, children: "Cancel" }))] })] }));
46
46
  }
47
47
  /**
48
48
  * A grid of every Composio-hosted toolkit this workspace can connect -
@@ -91,5 +91,5 @@ function ConnectIntegrationsModal({ className, label = "Integrations" }) {
91
91
  })
92
92
  .finally(() => setPendingSlug(null));
93
93
  };
94
- return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(react_2.Modal, { children: [(0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "secondary", className: className, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Puzzle, { className: "size-4" }), label] }), (0, jsx_runtime_1.jsx)(react_2.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_2.Modal.Dialog, { className: "sm:max-w-lg", children: [(0, jsx_runtime_1.jsx)(react_2.Modal.CloseTrigger, {}), (0, jsx_runtime_1.jsx)(react_2.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Heading, { children: "Integrations" }) }), (0, jsx_runtime_1.jsxs)(react_2.Modal.Body, { children: [isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3", children: Array.from({ length: 6 }, (_, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center gap-2 rounded-xl border border-separator p-3", children: [(0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "size-12 rounded-xl" }), (0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "h-3 w-16" }), (0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "h-7 w-full rounded-lg" })] }, index))) })), !isLoading && error && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-danger", children: "Could not load integrations." })), !isLoading && !error && toolkits.length === 0 && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-muted", children: "No integrations are enabled on this platform yet." })), !isLoading && !error && toolkits.length > 0 && ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { className: "grid grid-cols-2 gap-3 sm:grid-cols-3", variants: { show: { transition: { staggerChildren: 0.04 } } }, initial: "hidden", animate: "show", children: toolkits.map((toolkit) => ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { variants: { hidden: { opacity: 0, y: 8 }, show: { opacity: 1, y: 0, transition: motion_js_1.ENTER } }, children: (0, jsx_runtime_1.jsx)(ToolkitTile, { toolkit: toolkit, isPending: pendingSlug === toolkit.slug, onConnect: () => connect(toolkit.slug), onDisconnect: () => disconnect(toolkit.slug) }) }, toolkit.slug))) }))] })] }) }) })] }) }));
94
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)(react_2.Modal, { children: [(0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "secondary", className: className, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Puzzle, { className: "size-4" }), label] }), (0, jsx_runtime_1.jsx)(react_2.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Container, { children: (0, jsx_runtime_1.jsxs)(react_2.Modal.Dialog, { className: "sm:max-w-lg", children: [(0, jsx_runtime_1.jsx)(react_2.Modal.CloseTrigger, {}), (0, jsx_runtime_1.jsx)(react_2.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Heading, { children: "Integrations" }) }), (0, jsx_runtime_1.jsxs)(react_2.Modal.Body, { children: [isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3", children: Array.from({ length: 6 }, (_, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center gap-2 rounded-xl border border-separator p-3", children: [(0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "size-12 rounded-xl" }), (0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "h-3 w-16" }), (0, jsx_runtime_1.jsx)(react_2.Skeleton, { className: "h-7 w-full rounded-lg" })] }, index))) })), !isLoading && error && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-danger-soft-foreground", children: "Could not load integrations." })), !isLoading && !error && toolkits.length === 0 && ((0, jsx_runtime_1.jsx)("p", { className: "py-6 text-center text-sm text-muted", children: "No integrations are enabled on this platform yet." })), !isLoading && !error && toolkits.length > 0 && ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { className: "grid grid-cols-2 gap-3 sm:grid-cols-3", variants: { show: { transition: { staggerChildren: 0.04 } } }, initial: "hidden", animate: "show", children: toolkits.map((toolkit) => ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { variants: { hidden: { opacity: 0, y: 8 }, show: { opacity: 1, y: 0, transition: motion_js_1.ENTER } }, children: (0, jsx_runtime_1.jsx)(ToolkitTile, { toolkit: toolkit, isPending: pendingSlug === toolkit.slug, onConnect: () => connect(toolkit.slug), onDisconnect: () => disconnect(toolkit.slug) }) }, toolkit.slug))) }))] })] }) }) })] }) }));
95
95
  }
@@ -112,9 +112,9 @@ function ConnectPlans({ planIds, hideCoupon = false, className }) {
112
112
  return (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: "Sign in to see your plan options." });
113
113
  }
114
114
  if (error) {
115
- return (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger", children: "Could not load plans." });
115
+ return (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-danger-soft-foreground", children: "Could not load plans." });
116
116
  }
117
- return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("flex flex-col gap-6", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [hasAnnual && hasMonthly && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: showAnnual ? "text-sm text-muted" : "text-sm font-medium text-foreground", children: "Monthly" }), (0, jsx_runtime_1.jsx)(react_1.Switch, { "aria-label": "Bill annually", isSelected: showAnnual, onChange: setAnnual, children: (0, jsx_runtime_1.jsx)(react_1.Switch.Content, { children: (0, jsx_runtime_1.jsx)(react_1.Switch.Control, { children: (0, jsx_runtime_1.jsx)(react_1.Switch.Thumb, {}) }) }) }), (0, jsx_runtime_1.jsx)("span", { className: showAnnual ? "text-sm font-medium text-foreground" : "text-sm text-muted", children: "Annual" }), bestSaving !== null && ((0, jsx_runtime_1.jsxs)(react_1.Chip, { className: "bg-accent-soft text-accent", children: ["Save up to ", bestSaving, "%"] }))] })), !hideCoupon && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Tag, { className: "size-4 text-muted", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)(react_1.Input, { "aria-label": "Coupon code", placeholder: "Coupon code", value: coupon, onChange: (event) => setCoupon(event.target.value.toUpperCase()), className: "w-40" })] }))] }), subscription?.subscription?.appliedDiscount && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { className: "size-4 shrink-0", "aria-hidden": "true" }), (0, jsx_runtime_1.jsxs)("span", { children: [(0, plan_pricing_js_1.discountLabel)(subscription.subscription.appliedDiscount), subscription.subscription.appliedDiscount.code
117
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.MotionProvider, { children: (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_js_1.cn)("flex flex-col gap-6", className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [hasAnnual && hasMonthly && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: showAnnual ? "text-sm text-muted" : "text-sm font-medium text-foreground", children: "Monthly" }), (0, jsx_runtime_1.jsx)(react_1.Switch, { "aria-label": "Bill annually", isSelected: showAnnual, onChange: setAnnual, children: (0, jsx_runtime_1.jsx)(react_1.Switch.Content, { children: (0, jsx_runtime_1.jsx)(react_1.Switch.Control, { children: (0, jsx_runtime_1.jsx)(react_1.Switch.Thumb, {}) }) }) }), (0, jsx_runtime_1.jsx)("span", { className: showAnnual ? "text-sm font-medium text-foreground" : "text-sm text-muted", children: "Annual" }), bestSaving !== null && ((0, jsx_runtime_1.jsxs)(react_1.Chip, { color: "accent", variant: "soft", children: ["Save up to ", bestSaving, "%"] }))] })), !hideCoupon && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Tag, { className: "size-4 text-muted", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)(react_1.Input, { "aria-label": "Coupon code", placeholder: "Coupon code", value: coupon, onChange: (event) => setCoupon(event.target.value.toUpperCase()), className: "w-40" })] }))] }), subscription?.subscription?.appliedDiscount && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent-soft-foreground", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { className: "size-4 shrink-0", "aria-hidden": "true" }), (0, jsx_runtime_1.jsxs)("span", { children: [(0, plan_pricing_js_1.discountLabel)(subscription.subscription.appliedDiscount), subscription.subscription.appliedDiscount.code
118
118
  ? ` - code ${subscription.subscription.appliedDiscount.code}`
119
119
  : ""] })] })), (0, jsx_runtime_1.jsx)(ConnectCheckoutStatusRow, { checkout: checkout }), (0, jsx_runtime_1.jsx)(motion_js_1.m.div, { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", variants: { show: { transition: { staggerChildren: 0.06 } } }, initial: "hidden", animate: "show", children: tiers.map((tier) => {
120
120
  // The price point this card is showing. A tier missing the toggled
@@ -134,7 +134,7 @@ function ConnectPlans({ planIds, hideCoupon = false, className }) {
134
134
  tier.oneTime?.id === subscription.plan.id);
135
135
  const isCurrent = action === "current";
136
136
  const cadenceUnavailable = showAnnual ? tier.annual === null : tier.monthly === null;
137
- return ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { variants: { hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0, transition: motion_js_1.ENTER } }, children: (0, jsx_runtime_1.jsxs)(react_1.Card, { className: isCurrentTier ? "h-full border-accent" : "h-full", children: [(0, jsx_runtime_1.jsxs)(react_1.Card.Header, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Card.Title, { children: tier.name }), (0, jsx_runtime_1.jsxs)("div", { className: "flex shrink-0 items-center gap-1.5", children: [tier.annualSavingPercent !== null && showAnnual && ((0, jsx_runtime_1.jsxs)(react_1.Chip, { className: "bg-accent-soft text-accent", children: ["Save ", tier.annualSavingPercent, "%"] })), isCurrentTier && (0, jsx_runtime_1.jsx)(react_1.Chip, { className: "bg-accent-soft text-accent", children: "Current" })] })] }), tier.description && (0, jsx_runtime_1.jsx)(react_1.Card.Description, { children: tier.description })] }), (0, jsx_runtime_1.jsxs)(react_1.Card.Content, { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(motion_js_1.AnimatePresence, { mode: "popLayout", initial: false, children: (0, jsx_runtime_1.jsx)(motion_js_1.m.div, { initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, transition: { duration: 0.15 }, children: (0, plan_pricing_js_1.isFreePlan)(plan.price) ? ((0, jsx_runtime_1.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: "Free" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: (0, plan_pricing_js_1.formatPrice)(plan.price) }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-muted", children: (0, plan_pricing_js_1.pricePerLabel)(plan.billingInterval) })] })) }, plan.billingInterval) }), !(0, plan_pricing_js_1.isFreePlan)(plan.price) && ((0, jsx_runtime_1.jsxs)("p", { className: "mt-1 text-xs text-muted", children: ["+", plan.gstRate, "% GST"] })), cadenceUnavailable && ((0, jsx_runtime_1.jsxs)("p", { className: "mt-1 text-xs text-muted", children: ["Only sold ", (0, plan_pricing_js_1.intervalLabel)(plan.billingInterval).adverb, "."] }))] }), plan.trialDays && !(0, plan_pricing_js_1.isFreePlan)(plan.price) ? ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs font-medium text-accent", children: [plan.trialDays, "-day free trial"] })) : null, plan.features.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "flex flex-col gap-1.5", children: plan.features.map((feature) => (
137
+ return ((0, jsx_runtime_1.jsx)(motion_js_1.m.div, { variants: { hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0, transition: motion_js_1.ENTER } }, children: (0, jsx_runtime_1.jsxs)(react_1.Card, { className: isCurrentTier ? "h-full border-accent" : "h-full", children: [(0, jsx_runtime_1.jsxs)(react_1.Card.Header, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Card.Title, { children: tier.name }), (0, jsx_runtime_1.jsxs)("div", { className: "flex shrink-0 items-center gap-1.5", children: [tier.annualSavingPercent !== null && showAnnual && ((0, jsx_runtime_1.jsxs)(react_1.Chip, { color: "accent", variant: "soft", children: ["Save ", tier.annualSavingPercent, "%"] })), isCurrentTier && (0, jsx_runtime_1.jsx)(react_1.Chip, { color: "accent", variant: "soft", children: "Current" })] })] }), tier.description && (0, jsx_runtime_1.jsx)(react_1.Card.Description, { children: tier.description })] }), (0, jsx_runtime_1.jsxs)(react_1.Card.Content, { className: "flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(motion_js_1.AnimatePresence, { mode: "popLayout", initial: false, children: (0, jsx_runtime_1.jsx)(motion_js_1.m.div, { initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, transition: { duration: 0.15 }, children: (0, plan_pricing_js_1.isFreePlan)(plan.price) ? ((0, jsx_runtime_1.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: "Free" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: (0, plan_pricing_js_1.formatPrice)(plan.price) }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-muted", children: (0, plan_pricing_js_1.pricePerLabel)(plan.billingInterval) })] })) }, plan.billingInterval) }), !(0, plan_pricing_js_1.isFreePlan)(plan.price) && ((0, jsx_runtime_1.jsxs)("p", { className: "mt-1 text-xs text-muted", children: ["+", plan.gstRate, "% GST"] })), cadenceUnavailable && ((0, jsx_runtime_1.jsxs)("p", { className: "mt-1 text-xs text-muted", children: ["Only sold ", (0, plan_pricing_js_1.intervalLabel)(plan.billingInterval).adverb, "."] }))] }), plan.trialDays && !(0, plan_pricing_js_1.isFreePlan)(plan.price) ? ((0, jsx_runtime_1.jsxs)("p", { className: "text-xs font-medium text-accent-soft-foreground", children: [plan.trialDays, "-day free trial"] })) : null, plan.features.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "flex flex-col gap-1.5", children: plan.features.map((feature) => (
138
138
  // `name`, not `key` - the key is an identifier
139
139
  // ("campaign-module"), and printing it here is what this
140
140
  // card used to do. The description rides along as a
@@ -170,7 +170,7 @@ function CheckoutStatusRowContent({ checkout, }) {
170
170
  return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 rounded-lg border border-separator px-3 py-2 text-sm text-muted", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "size-4 shrink-0 animate-spin", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("span", { children: "Finish up in the Connect window. This page updates on its own." })] }));
171
171
  }
172
172
  if (checkout.status === "completed") {
173
- return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-3 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent", children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CheckCircle2, { className: "size-4 shrink-0", "aria-hidden": "true" }), "Your plan is updated."] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "tertiary", onPress: checkout.reset, children: "Dismiss" })] }));
173
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-3 rounded-lg bg-accent-soft px-3 py-2 text-sm text-accent-soft-foreground", children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.CheckCircle2, { className: "size-4 shrink-0", "aria-hidden": "true" }), "Your plan is updated."] }), (0, jsx_runtime_1.jsx)(react_1.Button, { variant: "tertiary", onPress: checkout.reset, children: "Dismiss" })] }));
174
174
  }
175
175
  // `blocked` and `abandoned` share a row: both mean nothing changed, and both
176
176
  // are fixed by going to the same URL - so offer it rather than explaining.
@@ -205,7 +205,7 @@ function ConnectUnsubscribeRow({ subscription, appUrl, checkout, }) {
205
205
  if (subscription.cancelAtPeriodEnd) {
206
206
  return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-separator pt-4", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-muted", children: ["Cancels", endsOn ? ` on ${new Date(endsOn).toLocaleDateString()}` : " at the end of this cycle", ". You keep access until then."] }), (0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "tertiary", onPress: () => openConnect(`/billing/subscriptions/${encodeURIComponent(subscription.id)}`), children: ["View on Connect", (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { className: "size-3.5" })] })] }));
207
207
  }
208
- return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-separator pt-4", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: "Cancel any time. Access continues to the end of the paid cycle." }), (0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "tertiary", className: "text-danger", isDisabled: checkout.status === "waiting", onPress: () => checkout.start({
208
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-separator pt-4", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: "Cancel any time. Access continues to the end of the paid cycle." }), (0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "danger-soft", isDisabled: checkout.status === "waiting", onPress: () => checkout.start({
209
209
  url: (0, use_checkout_js_1.buildCancelUrl)({ appUrl, subscriptionId: subscription.id }),
210
210
  // A paused subscription cancels outright (`status` goes to
211
211
  // `"cancelled"`); an active one is deferred to the cycle end