@uplifted/react 0.23.0 → 0.24.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 (99) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/AddClientSheet.d.ts +10 -1
  3. package/dist/AddClientSheet.d.ts.map +1 -1
  4. package/dist/AddClientSheet.js +26 -21
  5. package/dist/AddClientSheet.js.map +1 -1
  6. package/dist/AiSettingsSheet.d.ts +2 -2
  7. package/dist/AiSettingsSheet.d.ts.map +1 -1
  8. package/dist/AiSettingsSheet.js +30 -97
  9. package/dist/AiSettingsSheet.js.map +1 -1
  10. package/dist/AssistantGrid.d.ts +10 -8
  11. package/dist/AssistantGrid.d.ts.map +1 -1
  12. package/dist/AssistantGrid.js +90 -16
  13. package/dist/AssistantGrid.js.map +1 -1
  14. package/dist/ClientList.d.ts.map +1 -1
  15. package/dist/ClientList.js +5 -5
  16. package/dist/ClientList.js.map +1 -1
  17. package/dist/Composer.d.ts +2 -0
  18. package/dist/Composer.d.ts.map +1 -1
  19. package/dist/Composer.js +5 -6
  20. package/dist/Composer.js.map +1 -1
  21. package/dist/ConnectClientSheet.d.ts +26 -0
  22. package/dist/ConnectClientSheet.d.ts.map +1 -0
  23. package/dist/ConnectClientSheet.js +67 -0
  24. package/dist/ConnectClientSheet.js.map +1 -0
  25. package/dist/ConversationPane.d.ts +3 -1
  26. package/dist/ConversationPane.d.ts.map +1 -1
  27. package/dist/ConversationPane.js +30 -7
  28. package/dist/ConversationPane.js.map +1 -1
  29. package/dist/HostLinkAction.d.ts +10 -0
  30. package/dist/HostLinkAction.d.ts.map +1 -0
  31. package/dist/HostLinkAction.js +14 -0
  32. package/dist/HostLinkAction.js.map +1 -0
  33. package/dist/HostPreviewPane.d.ts +4 -2
  34. package/dist/HostPreviewPane.d.ts.map +1 -1
  35. package/dist/HostPreviewPane.js +6 -6
  36. package/dist/HostPreviewPane.js.map +1 -1
  37. package/dist/ItemActions.d.ts +7 -3
  38. package/dist/ItemActions.d.ts.map +1 -1
  39. package/dist/ItemActions.js +4 -3
  40. package/dist/ItemActions.js.map +1 -1
  41. package/dist/OfferSheet.d.ts +2 -0
  42. package/dist/OfferSheet.d.ts.map +1 -1
  43. package/dist/OfferSheet.js +3 -1
  44. package/dist/OfferSheet.js.map +1 -1
  45. package/dist/QuickSend.d.ts +3 -1
  46. package/dist/QuickSend.d.ts.map +1 -1
  47. package/dist/QuickSend.js +10 -3
  48. package/dist/QuickSend.js.map +1 -1
  49. package/dist/SegmentEditor.d.ts +11 -4
  50. package/dist/SegmentEditor.d.ts.map +1 -1
  51. package/dist/SegmentEditor.js +95 -11
  52. package/dist/SegmentEditor.js.map +1 -1
  53. package/dist/ThreadFeed.d.ts +7 -1
  54. package/dist/ThreadFeed.d.ts.map +1 -1
  55. package/dist/ThreadFeed.js +4 -4
  56. package/dist/ThreadFeed.js.map +1 -1
  57. package/dist/UpliftPanel.d.ts +10 -2
  58. package/dist/UpliftPanel.d.ts.map +1 -1
  59. package/dist/UpliftPanel.js +120 -20
  60. package/dist/UpliftPanel.js.map +1 -1
  61. package/dist/UpliftProvider.d.ts.map +1 -1
  62. package/dist/UpliftProvider.js +16 -2
  63. package/dist/UpliftProvider.js.map +1 -1
  64. package/dist/build-info.json +3 -3
  65. package/dist/channels.d.ts +2 -0
  66. package/dist/channels.d.ts.map +1 -1
  67. package/dist/channels.js +4 -0
  68. package/dist/channels.js.map +1 -1
  69. package/dist/draftContext.d.ts +34 -0
  70. package/dist/draftContext.d.ts.map +1 -0
  71. package/dist/draftContext.js +48 -0
  72. package/dist/draftContext.js.map +1 -0
  73. package/dist/host.d.ts +19 -0
  74. package/dist/host.d.ts.map +1 -1
  75. package/dist/host.js.map +1 -1
  76. package/dist/icons.d.ts +3 -0
  77. package/dist/icons.d.ts.map +1 -1
  78. package/dist/icons.js +4 -0
  79. package/dist/icons.js.map +1 -1
  80. package/dist/index.d.ts +6 -3
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +3 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/segments.d.ts.map +1 -1
  85. package/dist/segments.js +2 -1
  86. package/dist/segments.js.map +1 -1
  87. package/dist/styles.d.ts +1 -1
  88. package/dist/styles.d.ts.map +1 -1
  89. package/dist/styles.js +56 -14
  90. package/dist/styles.js.map +1 -1
  91. package/dist/usePreviewDrafts.d.ts +1 -1
  92. package/dist/usePreviewDrafts.d.ts.map +1 -1
  93. package/dist/usePreviewDrafts.js +8 -1
  94. package/dist/usePreviewDrafts.js.map +1 -1
  95. package/dist/useSend.d.ts +7 -2
  96. package/dist/useSend.d.ts.map +1 -1
  97. package/dist/useSend.js +7 -2
  98. package/dist/useSend.js.map +1 -1
  99. package/package.json +3 -3
@@ -14,12 +14,19 @@ export interface SegmentEditorProps {
14
14
  disabled?: boolean | undefined;
15
15
  /** Nothing can be typed or removed: the box shows fixed text (Uplift's stock intro) and only Send applies. */
16
16
  readOnly?: boolean | undefined;
17
+ /** Esc in the editor: the parent's clear. */
18
+ onEscape?: (() => void) | undefined;
17
19
  }
18
20
  /**
19
21
  * Two modes, like native Uplift's editor: a plain textarea for typing, and a contentEditable
20
- * box that shows an injected draft as coloured pills the coach can delete one by one. The DOM
21
- * of the pill box is owned by hand (written on inject, read on change), never by React, so the
22
- * caret and the browser's own editing stay intact. The parent only ever sees plain text.
22
+ * box that shows an injected draft as pills the coach can delete one by one. The DOM of the
23
+ * pill box is owned by hand (written on inject, read on change), never by React, so the caret
24
+ * and the browser's own editing stay intact. The parent only ever sees plain text.
25
+ *
26
+ * An injected draft first lands "suggested" (native #633): greyed plain text on a tint with a
27
+ * "Suggested draft" label, so it reads as Uplift's words. Send works as is. The first click,
28
+ * tap or keystroke opens the pills; pills stay grey until the coach clicks or types in one.
29
+ * A locked injection (the stock intro) is never suggested.
23
30
  */
24
- export declare function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel, disabled, readOnly }: SegmentEditorProps): import("react").JSX.Element;
31
+ export declare function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel, disabled, readOnly, onEscape }: SegmentEditorProps): import("react").JSX.Element;
25
32
  //# sourceMappingURL=SegmentEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentEditor.d.ts","sourceRoot":"","sources":["../src/SegmentEditor.tsx"],"names":[],"mappings":"AAGA,6IAA6I;AAC7I,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE;AAEtF,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BA6GxH"}
1
+ {"version":3,"file":"SegmentEditor.d.ts","sourceRoot":"","sources":["../src/SegmentEditor.tsx"],"names":[],"mappings":"AAIA,6IAA6I;AAC7I,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE;AAEtF,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BA+LlI"}
@@ -1,18 +1,29 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
3
+ import { flushSync } from "react-dom";
3
4
  import { reconstructMessage, SEG_CLASS, SEG_DELETE_CLASS, toLockedPillHtml, toPillHtml } from "./segments.js";
4
5
  /**
5
6
  * Two modes, like native Uplift's editor: a plain textarea for typing, and a contentEditable
6
- * box that shows an injected draft as coloured pills the coach can delete one by one. The DOM
7
- * of the pill box is owned by hand (written on inject, read on change), never by React, so the
8
- * caret and the browser's own editing stay intact. The parent only ever sees plain text.
7
+ * box that shows an injected draft as pills the coach can delete one by one. The DOM of the
8
+ * pill box is owned by hand (written on inject, read on change), never by React, so the caret
9
+ * and the browser's own editing stay intact. The parent only ever sees plain text.
10
+ *
11
+ * An injected draft first lands "suggested" (native #633): greyed plain text on a tint with a
12
+ * "Suggested draft" label, so it reads as Uplift's words. Send works as is. The first click,
13
+ * tap or keystroke opens the pills; pills stay grey until the coach clicks or types in one.
14
+ * A locked injection (the stock intro) is never suggested.
9
15
  */
10
- export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel, disabled, readOnly }) {
16
+ export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel, disabled, readOnly, onEscape }) {
11
17
  const [rich, setRich] = useState(false);
18
+ const [suggested, setSuggested] = useState(false);
19
+ // Set while engage() hands a suggested draft to the pills: it focuses itself, inside the tap.
20
+ const engaging = useRef(false);
12
21
  const boxRef = useRef(null);
13
22
  const taRef = useRef(null);
14
23
  const lastKey = useRef(null);
15
24
  const pendingHtml = useRef(null);
25
+ // Bumped on every inject, so a second pick redraws the pills even when already in pill mode.
26
+ const [injected, setInjected] = useState(0);
16
27
  // Inject: switch to pills. Done in a layout effect so the box exists before we write to it.
17
28
  useEffect(() => {
18
29
  if (!inject || !inject.text.trim() || inject.key === lastKey.current)
@@ -20,15 +31,19 @@ export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel,
20
31
  lastKey.current = inject.key;
21
32
  pendingHtml.current = inject.locked ? toLockedPillHtml(inject.text, inject.key) : toPillHtml(inject.text, inject.key);
22
33
  setRich(true);
34
+ setSuggested(!inject.locked);
35
+ setInjected((n) => n + 1);
23
36
  }, [inject]);
24
37
  useLayoutEffect(() => {
25
38
  if (!rich || pendingHtml.current === null)
26
39
  return;
27
40
  const el = boxRef.current;
28
41
  if (!el)
29
- return;
42
+ return; // still suggested: the pills are written when the coach engages
30
43
  el.innerHTML = pendingHtml.current;
31
44
  pendingHtml.current = null;
45
+ if (engaging.current)
46
+ return;
32
47
  // Caret at the end, after the last pill, so typing continues the message. Native does the same.
33
48
  const t = setTimeout(() => {
34
49
  el.focus();
@@ -43,19 +58,49 @@ export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel,
43
58
  el.removeChild(marker);
44
59
  }, 80);
45
60
  return () => clearTimeout(t);
46
- }, [rich]);
61
+ }, [rich, injected, suggested]);
47
62
  // The parent cleared the text (sent, or switched client): leave pill mode.
48
63
  useEffect(() => {
49
64
  if (rich && value === "") {
50
65
  setRich(false);
66
+ setSuggested(false);
67
+ pendingHtml.current = null;
51
68
  if (boxRef.current)
52
69
  boxRef.current.innerHTML = "";
53
70
  }
54
71
  }, [value, rich]);
72
+ // First click, tap, focus or keystroke on a suggested draft: hand it to the pills. Synchronous
73
+ // (flushSync) so focus lands inside the same tap, which is what opens the keyboard on iOS.
74
+ const engage = useCallback(() => {
75
+ if (!suggested || disabled)
76
+ return;
77
+ engaging.current = true;
78
+ flushSync(() => setSuggested(false));
79
+ engaging.current = false;
80
+ const el = boxRef.current;
81
+ if (!el)
82
+ return;
83
+ el.focus();
84
+ const range = document.createRange();
85
+ range.selectNodeContents(el);
86
+ range.collapse(false);
87
+ const sel = window.getSelection();
88
+ sel?.removeAllRanges();
89
+ sel?.addRange(range);
90
+ }, [suggested, disabled]);
91
+ // Mark the pill under the caret as the coach's (white, full-strength text).
92
+ const touchAtCaret = useCallback(() => {
93
+ const node = window.getSelection()?.anchorNode;
94
+ const el = node && (node.nodeType === 1 ? node : node.parentElement);
95
+ const seg = el?.closest(`.${SEG_CLASS}`);
96
+ if (seg && boxRef.current?.contains(seg))
97
+ seg.classList.add("touched");
98
+ }, []);
55
99
  const readBack = useCallback(() => {
56
100
  const el = boxRef.current;
57
101
  if (!el)
58
102
  return;
103
+ touchAtCaret();
59
104
  const html = el.innerHTML;
60
105
  const plain = reconstructMessage(html);
61
106
  onChange(plain);
@@ -64,7 +109,7 @@ export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel,
64
109
  setRich(false);
65
110
  if (!html.includes(SEG_CLASS) && !plain)
66
111
  setRich(false);
67
- }, [onChange]);
112
+ }, [onChange, touchAtCaret]);
68
113
  const removePill = useCallback((id) => {
69
114
  const el = boxRef.current?.querySelector(`.${SEG_CLASS}[data-seg="${id}"]`);
70
115
  if (!el)
@@ -78,18 +123,57 @@ export function SegmentEditor({ value, onChange, inject, placeholder, ariaLabel,
78
123
  e.preventDefault();
79
124
  e.stopPropagation();
80
125
  removePill(t.getAttribute("data-seg") ?? "");
126
+ return;
81
127
  }
128
+ const seg = t.closest(`.${SEG_CLASS}`);
129
+ boxRef.current?.querySelectorAll(`.${SEG_CLASS}.active`).forEach((s) => { if (s !== seg)
130
+ s.classList.remove("active"); });
131
+ if (seg && !seg.classList.contains("u-seg-lock"))
132
+ seg.classList.add("active", "touched");
82
133
  }, [removePill]);
134
+ const onBlur = useCallback(() => {
135
+ boxRef.current?.querySelectorAll(`.${SEG_CLASS}.active`).forEach((s) => s.classList.remove("active"));
136
+ }, []);
83
137
  const onKeyDown = useCallback((e) => {
84
138
  const t = e.target;
85
139
  if (t.classList.contains(SEG_DELETE_CLASS) && (e.key === "Enter" || e.key === " ")) {
86
140
  e.preventDefault();
87
141
  removePill(t.getAttribute("data-seg") ?? "");
142
+ return;
88
143
  }
89
- }, [removePill]);
144
+ if (e.key === "Escape" && onEscape) {
145
+ e.preventDefault();
146
+ onEscape();
147
+ }
148
+ }, [removePill, onEscape]);
149
+ if (rich && suggested) {
150
+ return (
151
+ // Distinct keys: both boxes are <div>s in the same slot, and React would otherwise reuse
152
+ // one node, keeping the hand-written pills inside the suggested box (native #634).
153
+ _jsxs("div", { className: "u-editor u-editor-rich u-editor-sugg", role: "textbox", "aria-multiline": "true", "aria-label": ariaLabel, "aria-description": "Suggested draft. Click or start typing to edit.", "aria-disabled": disabled || undefined, tabIndex: disabled ? -1 : 0, "data-testid": "suggested-draft", onFocus: engage, onClick: engage, onKeyDown: (e) => {
154
+ if (e.key === "Escape") {
155
+ if (onEscape) {
156
+ e.preventDefault();
157
+ onEscape();
158
+ }
159
+ return;
160
+ }
161
+ if (e.key === "Tab" || e.metaKey || e.ctrlKey || e.altKey)
162
+ return;
163
+ engage();
164
+ // The first character typed lands at the end of the draft, not nowhere.
165
+ if (e.key.length === 1) {
166
+ e.preventDefault();
167
+ document.execCommand("insertText", false, e.key);
168
+ }
169
+ }, children: [_jsxs("span", { className: "u-sugg-label", "aria-hidden": "true", children: [_jsx("i", {}), "Suggested draft ", _jsx("em", { children: "\u00B7 click to edit" })] }), _jsx("span", { className: "u-sugg-text", children: value })] }, "suggested"));
170
+ }
90
171
  if (rich) {
91
- return (_jsx("div", { ref: boxRef, className: `u-editor u-editor-rich${readOnly ? " u-editor-locked" : ""}`, role: "textbox", "aria-multiline": "true", "aria-label": ariaLabel, "aria-disabled": disabled || undefined, "aria-readonly": readOnly || undefined, contentEditable: !disabled && !readOnly, suppressContentEditableWarning: true, "data-placeholder": placeholder, onInput: readBack, onClick: onClick, onKeyDown: onKeyDown }));
172
+ return (_jsx("div", { ref: boxRef, className: `u-editor u-editor-rich${readOnly ? " u-editor-locked" : ""}`, role: "textbox", "aria-multiline": "true", "aria-label": ariaLabel, "aria-disabled": disabled || undefined, "aria-readonly": readOnly || undefined, contentEditable: !disabled && !readOnly, suppressContentEditableWarning: true, "data-placeholder": placeholder, onInput: readBack, onClick: onClick, onKeyDown: onKeyDown, onBlur: onBlur }, "rich"));
92
173
  }
93
- return (_jsx("textarea", { ref: taRef, className: "u-editor", "aria-label": ariaLabel, placeholder: placeholder, value: value, disabled: disabled, readOnly: readOnly, onChange: (e) => onChange(e.target.value), rows: 3 }));
174
+ return (_jsx("textarea", { ref: taRef, className: "u-editor", "aria-label": ariaLabel, placeholder: placeholder, value: value, disabled: disabled, readOnly: readOnly, onChange: (e) => onChange(e.target.value), onKeyDown: (e) => { if (e.key === "Escape" && onEscape) {
175
+ e.preventDefault();
176
+ onEscape();
177
+ } }, rows: 3 }));
94
178
  }
95
179
  //# sourceMappingURL=SegmentEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentEditor.js","sourceRoot":"","sources":["../src/SegmentEditor.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SegmentEditor.js","sourceRoot":"","sources":["../src/SegmentEditor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAuC,MAAM,OAAO,CAAC;AACvH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAmB9G;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAsB;IACjI,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,8FAA8F;IAC9F,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAA6B,IAAI,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAChD,6FAA6F;IAC7F,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE5C,4FAA4F;IAC5F,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,GAAG,KAAK,OAAO,CAAC,OAAO;YAAE,OAAO;QAC7E,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;QAC7B,WAAW,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QACtH,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,YAAY,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC7B,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,eAAe,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI;YAAE,OAAO;QAClD,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,gEAAgE;QACjF,EAAE,CAAC,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC;QACnC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAC3B,IAAI,QAAQ,CAAC,OAAO;YAAE,OAAO;QAC7B,gGAAgG;QAChG,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE;YACxB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAC5C,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACvB,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;YACrC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;YAClC,GAAG,EAAE,eAAe,EAAE,CAAC;YACvB,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YACrB,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAEhC,2EAA2E;IAC3E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,IAAI,MAAM,CAAC,OAAO;gBAAE,MAAM,CAAC,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC;QACpD,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAElB,+FAA+F;IAC/F,2FAA2F;IAC3F,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,SAAS,IAAI,QAAQ;YAAE,OAAO;QACnC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACrC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACrC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;QAClC,GAAG,EAAE,eAAe,EAAE,CAAC;QACvB,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE1B,4EAA4E;IAC5E,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,EAAE,EAAE,UAAU,CAAC;QAC/C,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAE,IAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACtF,MAAM,GAAG,GAAG,EAAE,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;QACzC,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzE,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,YAAY,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC;QAC1B,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACvC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChB,wEAAwE;QACxE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE7B,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAC5C,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,SAAS,cAAc,EAAE,IAAI,CAAC,CAAC;QAC5E,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,EAAE,CAAC,MAAM,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;IACb,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAA6B,EAAE,EAAE;QAC5D,MAAM,CAAC,GAAG,CAAC,CAAC,MAAqB,CAAC;QAClC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC3C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,CAAC,CAAC,eAAe,EAAE,CAAC;YACpB,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,IAAI,SAAS,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1H,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC3F,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,IAAI,SAAS,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxG,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAgC,EAAE,EAAE;QACjE,MAAM,CAAC,GAAG,CAAC,CAAC,MAAqB,CAAC;QAClC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;YACnF,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAAC,CAAC,CAAC,cAAc,EAAE,CAAC;YAAC,QAAQ,EAAE,CAAC;QAAC,CAAC;IACzE,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE3B,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;QACtB,OAAO;QACL,yFAAyF;QACzF,mFAAmF;QACnF,eAEE,SAAS,EAAC,sCAAsC,EAChD,IAAI,EAAC,SAAS,oBACC,MAAM,gBACT,SAAS,sBACJ,iDAAiD,mBACnD,QAAQ,IAAI,SAAS,EACpC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBACf,iBAAiB,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;gBACf,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;oBAAC,IAAI,QAAQ,EAAE,CAAC;wBAAC,CAAC,CAAC,cAAc,EAAE,CAAC;wBAAC,QAAQ,EAAE,CAAC;oBAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACrF,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM;oBAAE,OAAO;gBAClE,MAAM,EAAE,CAAC;gBACT,wEAAwE;gBACxE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAAC,CAAC,CAAC,cAAc,EAAE,CAAC;oBAAC,QAAQ,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;gBAAC,CAAC;YACnG,CAAC,aAED,gBAAM,SAAS,EAAC,cAAc,iBAAa,MAAM,aAAC,aAAK,sBAAgB,gDAAwB,IAAO,EACtG,eAAM,SAAS,EAAC,aAAa,YAAE,KAAK,GAAQ,KApBxC,WAAW,CAqBX,CACP,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CACL,cAEE,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,yBAAyB,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,EACxE,IAAI,EAAC,SAAS,oBACC,MAAM,gBACT,SAAS,mBACN,QAAQ,IAAI,SAAS,mBACrB,QAAQ,IAAI,SAAS,EACpC,eAAe,EAAE,CAAC,QAAQ,IAAI,CAAC,QAAQ,EACvC,8BAA8B,4BACZ,WAAW,EAC7B,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,IAdV,MAAM,CAeV,CACH,CAAC;IACJ,CAAC;IACD,OAAO,CACL,mBACE,GAAG,EAAE,KAAK,EACV,SAAS,EAAC,UAAU,gBACR,SAAS,EACrB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAAC,CAAC,CAAC,cAAc,EAAE,CAAC;YAAC,QAAQ,EAAE,CAAC;QAAC,CAAC,CAAC,CAAC,EAC7F,IAAI,EAAE,CAAC,GACP,CACH,CAAC;AACJ,CAAC"}
@@ -11,8 +11,14 @@ export interface ThreadFeedProps {
11
11
  actions?: (m: Message) => ReactNode;
12
12
  /** Rendered at the foot of the feed (the closed-window ghost). */
13
13
  foot?: ReactNode;
14
+ /**
15
+ * On cards for messages the client sent in another conversation (`eventType` "externalMessage"):
16
+ * the way to that conversation, e.g. the host's "Open in Pulse". Rendered under the card only when
17
+ * the card has no action row; with one, pass it to that row instead (ItemActions `extra`).
18
+ */
19
+ externalMessageAction?: ReactNode;
14
20
  }
15
- export declare function ThreadFeed({ thread, clientName, activitySourceLabel, now, actions, foot }: ThreadFeedProps): import("react").JSX.Element;
21
+ export declare function ThreadFeed({ thread, clientName, activitySourceLabel, now, actions, foot, externalMessageAction }: ThreadFeedProps): import("react").JSX.Element;
16
22
  type FeedItem = {
17
23
  type: "day";
18
24
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadFeed.d.ts","sourceRoot":"","sources":["../src/ThreadFeed.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAK7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,IAAI,CAAC;IACV,wHAAwH;IACxH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC;IACpC,kEAAkE;IAClE,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,eAAe,+BAwC1G;AAED,KAAK,QAAQ,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjG,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAYxD"}
1
+ {"version":3,"file":"ThreadFeed.d.ts","sourceRoot":"","sources":["../src/ThreadFeed.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAK7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,IAAI,CAAC;IACV,wHAAwH;IACxH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC;IACpC,kEAAkE;IAClE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,SAAS,CAAC;CACnC;AAED,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,EAAE,eAAe,+BAwCjI;AAED,KAAK,QAAQ,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjG,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAYxD"}
@@ -5,12 +5,12 @@ import { EventIcon } from "./icons.js";
5
5
  import { MediaAttachment } from "./MediaAttachment.js";
6
6
  import { clockLabel, dayKey, dayLabel } from "./time.js";
7
7
  import { useStickToBottom } from "./useStickToBottom.js";
8
- export function ThreadFeed({ thread, clientName, activitySourceLabel, now, actions, foot }) {
8
+ export function ThreadFeed({ thread, clientName, activitySourceLabel, now, actions, foot, externalMessageAction }) {
9
9
  const first = clientName.split(" ")[0] ?? clientName;
10
10
  const stick = useStickToBottom(thread.messages[0]?.id);
11
11
  return (_jsxs("div", { className: "u-feed", role: "log", "aria-label": `Conversation with ${clientName}`, "aria-busy": thread.status === "loading", ...stick, children: [thread.status === "loading" && (_jsxs(_Fragment, { children: [_jsx("div", { className: "u-skel", style: { width: "40%", alignSelf: "flex-end" } }), _jsx("div", { className: "u-skel", style: { width: "60%" } }), _jsx("div", { className: "u-skel", style: { width: "35%", alignSelf: "center" } })] })), thread.status === "error" && (_jsxs("div", { className: "u-state", role: "alert", children: [_jsx("h3", { children: "Couldn't load this conversation" }), _jsx("p", { children: thread.error?.message }), _jsx("button", { type: "button", className: "u-retry", onClick: thread.reload, children: "Retry" })] })), thread.status === "ready" && thread.messages.length === 0 && (_jsx("div", { className: "u-state", children: _jsxs("p", { children: ["No messages or activity yet. Send ", first, " the first one below."] }) })), thread.status === "ready" && thread.hasMore && (_jsx("button", { type: "button", className: "u-older", onClick: thread.loadOlder, disabled: thread.loadingOlder, children: thread.loadingOlder ? "Loading…" : "Show older" })), thread.status === "ready" && !thread.hasMore && thread.messages.length > 0 && _jsx("span", { className: "u-hist-start", children: "\u2014 beginning of history \u2014" }), thread.status === "ready" && withDays(thread.messages).map((item) => item.type === "day"
12
12
  ? _jsx("span", { className: "u-day", children: dayLabel(item.at, now) }, item.key)
13
- : (_jsx(Item, { m: item.message, first: first, source: activitySourceLabel, children: actions ? actions(item.message) : null }, item.message.id))), thread.status === "ready" && foot] }));
13
+ : (_jsx(Item, { m: item.message, first: first, source: activitySourceLabel, externalAction: externalMessageAction, children: actions ? actions(item.message) : null }, item.message.id))), thread.status === "ready" && foot] }));
14
14
  }
15
15
  /** Insert a day separator wherever the local calendar day changes. */
16
16
  export function withDays(messages) {
@@ -26,11 +26,11 @@ export function withDays(messages) {
26
26
  }
27
27
  return out;
28
28
  }
29
- function Item({ m, first, source, children }) {
29
+ function Item({ m, first, source, children, externalAction }) {
30
30
  const time = clockLabel(m.sentAt);
31
31
  const [showTemplate, setShowTemplate] = useState(false);
32
32
  if (m.kind === "event") {
33
- return (_jsxs("div", { className: "u-ev", children: [_jsx(EventIcon, { type: m.eventType }), _jsxs("div", { children: [_jsx("b", { children: m.body }), _jsxs("div", { className: "u-meta", children: ["From ", source, time ? ` · ${time}` : ""] }), children] })] }));
33
+ return (_jsxs("div", { className: "u-ev", children: [_jsx(EventIcon, { type: m.eventType }), _jsxs("div", { children: [_jsx("b", { children: m.body }), _jsxs("div", { className: "u-meta", children: ["From ", source, time ? ` · ${time}` : ""] }), m.eventType === "externalMessage" && externalAction && !children && _jsx("div", { className: "u-ev-open", children: externalAction }), children] })] }));
34
34
  }
35
35
  const out = m.direction !== "inbound";
36
36
  const atts = m.attachments ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadFeed.js","sourceRoot":"","sources":["../src/ThreadFeed.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ThreadFeed.js","sourceRoot":"","sources":["../src/ThreadFeed.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Channel, Client } from "@uplifted/sdk";
2
- import { type HostActivityLoader, type HostClient } from "./host.js";
2
+ import { type HostActivityLoader, type HostClient, type HostContactLoader } from "./host.js";
3
3
  export interface UpliftPanelProps {
4
4
  /** Header title. Default "Messages". */
5
5
  title?: string;
@@ -26,6 +26,14 @@ export interface UpliftPanelProps {
26
26
  hostClients?: ReadonlyArray<HostClient>;
27
27
  /** Loads a not-connected host client's recent activity for the preview feed and drafts. */
28
28
  hostActivity?: HostActivityLoader;
29
+ /**
30
+ * Reads a host client's phone when the coach connects them. With a phone, and the channel's rules
31
+ * already confirmed (`acknowledgedChannels`), Connect needs no form: the channel follows the number
32
+ * (+1 SMS, anything else WhatsApp). Without it the connect sheet asks for the phone.
33
+ */
34
+ hostContact?: HostContactLoader;
35
+ /** Open a client's `hostLink` yourself (for example to navigate an embedding parent). Default: a link to a new tab. */
36
+ onOpenHostLink?: (host: HostClient) => void;
29
37
  /** The coach's name, so preview drafts can be signed the way the real ones are. */
30
38
  coachName?: string;
31
39
  /** Fallback roster and open-thread refresh interval while the tab is visible and the stream is down. 0 disables. Default 20000. */
@@ -36,5 +44,5 @@ export interface UpliftPanelProps {
36
44
  now?: () => Date;
37
45
  className?: string;
38
46
  }
39
- export declare function UpliftPanel({ title, hostName, initialClientId, onCheckout, onSent, onClientAdded, acknowledgedChannels, onChannelAcknowledged, hostClients, hostActivity, coachName, now, className, pollMs, live: liveUpdates }: UpliftPanelProps): import("react").JSX.Element;
47
+ export declare function UpliftPanel({ title, hostName, initialClientId, onCheckout, onSent, onClientAdded, acknowledgedChannels, onChannelAcknowledged, hostClients, hostActivity, hostContact, onOpenHostLink, coachName, now, className, pollMs, live: liveUpdates }: UpliftPanelProps): import("react").JSX.Element;
40
48
  //# sourceMappingURL=UpliftPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UpliftPanel.d.ts","sourceRoot":"","sources":["../src/UpliftPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAKrD,OAAO,EAAgD,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAiBnH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,sCAAsC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sCAAsC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,+FAA+F;IAC/F,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAC;IACjC,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACxC,2FAA2F;IAC3F,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mIAAmI;IACnI,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD,wBAAgB,WAAW,CAAC,EAAE,KAAkB,EAAE,QAAqB,EAAE,eAAsB,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,gBAAgB,+BAqTnR"}
1
+ {"version":3,"file":"UpliftPanel.d.ts","sourceRoot":"","sources":["../src/UpliftPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAS,MAAM,eAAe,CAAC;AAS5D,OAAO,EAAgD,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAiB3I,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,sCAAsC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sCAAsC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,+FAA+F;IAC/F,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAC;IACjC,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACxC,2FAA2F;IAC3F,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,uHAAuH;IACvH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mIAAmI;IACnI,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD,wBAAgB,WAAW,CAAC,EAAE,KAAkB,EAAE,QAAqB,EAAE,eAAsB,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,gBAAgB,+BAoZhT"}
@@ -1,11 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useInsertionEffect, useMemo, useState, useRef } from "react";
3
- import { AddClientSheet } from "./AddClientSheet.js";
3
+ import { AddClientSheet, describeAddError } from "./AddClientSheet.js";
4
+ import { ConnectClientSheet } from "./ConnectClientSheet.js";
5
+ import { channelForPhone } from "./channels.js";
6
+ import { coerceToE164, validatePhone } from "./phone.js";
4
7
  import { ClientList } from "./ClientList.js";
5
8
  import { ConversationPane } from "./ConversationPane.js";
6
9
  import { HostPreviewPane } from "./HostPreviewPane.js";
10
+ import { HostLinkAction } from "./HostLinkAction.js";
7
11
  import { HOST_SEL, hostOnlyRows, hostSelId, isHostSel } from "./host.js";
8
- import { OfferSheet } from "./OfferSheet.js";
12
+ import { FREE_CLIENTS, OfferSheet } from "./OfferSheet.js";
9
13
  import { ProactiveOptionsSheet } from "./ProactiveOptionsSheet.js";
10
14
  import { useProactiveOptions } from "./useProactiveOptions.js";
11
15
  import { useInstructions } from "./useInstructions.js";
@@ -36,7 +40,7 @@ function loadSort() {
36
40
  catch { /* private mode / SSR */ }
37
41
  return "priority";
38
42
  }
39
- export function UpliftPanel({ title = "Messages", hostName = "your app", initialClientId = null, onCheckout, onSent, onClientAdded, acknowledgedChannels, onChannelAcknowledged, hostClients, hostActivity, coachName, now, className, pollMs, live: liveUpdates }) {
43
+ export function UpliftPanel({ title = "Messages", hostName = "your app", initialClientId = null, onCheckout, onSent, onClientAdded, acknowledgedChannels, onChannelAcknowledged, hostClients, hostActivity, hostContact, onOpenHostLink, coachName, now, className, pollMs, live: liveUpdates }) {
40
44
  useInsertionEffect(() => { injectStyles(); }, []);
41
45
  const list = useClients();
42
46
  const { client: api } = useUplift();
@@ -84,11 +88,31 @@ export function UpliftPanel({ title = "Messages", hostName = "your app", initial
84
88
  /** Host clients connected during this session, so they leave the not-connected rows at once. */
85
89
  const [linkedHere, setLinkedHere] = useState(() => new Set());
86
90
  const [connectFor, setConnectFor] = useState(null);
91
+ /** Host clients connected in this session, by Uplift client id, so their header keeps the host link. */
92
+ const [hostByClient, setHostByClient] = useState(() => new Map());
87
93
  // What the coach had written to a client they then connected: it waits in the new conversation.
88
94
  const [carry, setCarry] = useState(null);
89
95
  const [carryFor, setCarryFor] = useState(null);
96
+ // Read after awaits (the phone lookup, the add), where the render's values would be stale.
97
+ const connectForRef = useRef(connectFor);
98
+ connectForRef.current = connectFor;
99
+ const carryRef = useRef(carry);
100
+ carryRef.current = carry;
101
+ const acksRef = useRef(acks);
102
+ acksRef.current = acks;
103
+ /** The connect sheet: the phone the host had (null while loading), and why the last try failed. */
104
+ const [conn, setConn] = useState(null);
90
105
  // Why the paywall opened, and the add the coach was making (completed for them once they have paid).
106
+ // `upgradeFirst`: Connect hit the plan wall before the coach entered anything, so after paying the
107
+ // connect form opens for that client.
91
108
  const [offer, setOffer] = useState({ reason: "pitch" });
109
+ // The coach's plan, so Connect can show the offer before any form (Yusef, #75: the third client sees the
110
+ // offer first). Unknown until loaded, or if it fails: then Uplift's own refusal on the add opens it.
111
+ const [plan, setPlan] = useState(null);
112
+ useEffect(() => {
113
+ api.me().then((c) => setPlan({ subscription: c.subscription, freeLimit: c.freeClientLimit === undefined ? FREE_CLIENTS : c.freeClientLimit }), () => { });
114
+ }, [api]);
115
+ const planActive = () => setPlan((p) => (p ? { ...p, subscription: "active" } : p));
92
116
  // The add form reopened prefilled, only when finishing the add after an upgrade failed.
93
117
  const [resumeAdd, setResumeAdd] = useState(null);
94
118
  const clock = now ? now() : new Date();
@@ -123,35 +147,100 @@ export function UpliftPanel({ title = "Messages", hostName = "your app", initial
123
147
  }, [list.status, selected, selectedHost, sorted, hostOnly, selectedId]);
124
148
  const open = useCallback((c) => { setSelectedId(c.id); setShowThread(true); }, []);
125
149
  const openHost = useCallback((h) => { setSelectedId(hostSelId(h.id)); setShowThread(true); }, []);
126
- const connect = useCallback((h, draft) => {
127
- setConnectFor(h);
128
- setCarry(draft?.trim() ? { hostId: h.id, text: draft } : null);
129
- setSheet("add");
130
- }, []);
131
150
  const acknowledge = useCallback((ch) => {
132
151
  setAcks((s) => new Set(s).add(ch));
133
152
  onChannelAcknowledged?.(ch);
134
153
  }, [onChannelAcknowledged]);
135
- const added = useCallback((c, hostId = connectFor?.id) => {
154
+ const added = useCallback((c, hostId = connectForRef.current?.id) => {
155
+ const from = connectForRef.current;
156
+ const draft = carryRef.current;
136
157
  list.upsert(c);
137
- if (connectFor)
138
- setLinkedHere((s) => new Set(s).add(connectFor.id));
139
- if (carry && carry.hostId === hostId)
140
- setCarryFor({ clientId: c.id, text: carry.text });
158
+ if (from)
159
+ setLinkedHere((s) => new Set(s).add(from.id));
160
+ if (hostId)
161
+ setHostByClient((m) => new Map(m).set(c.id, hostId));
162
+ if (draft && draft.hostId === hostId)
163
+ setCarryFor({ clientId: c.id, text: draft.text });
141
164
  setCarry(null);
142
165
  setConnectFor(null);
166
+ setConn(null);
143
167
  setSheet(null);
144
168
  setSelectedId(c.id);
145
169
  setShowThread(true);
146
170
  setLive(`${firstName(c.name)} added to Uplift`);
147
171
  onClientAdded?.(c);
148
- }, [list, onClientAdded, connectFor, carry]);
172
+ }, [list, onClientAdded]);
173
+ /** Connects a host client with a known phone. A plan refusal opens the offer; anything else goes back to the sheet. */
174
+ const connectNow = useCallback(async (h, phone, channel) => {
175
+ setConn({ phone, busy: true });
176
+ setSheet("connect");
177
+ const attempt = { name: h.name, phone, channel, hostClientId: h.id };
178
+ const confirm = () => { if (!acksRef.current.has(channel))
179
+ acknowledge(channel); };
180
+ try {
181
+ const c = await api.addClient(attempt);
182
+ confirm();
183
+ added(c, h.id);
184
+ }
185
+ catch (err) {
186
+ const ue = asUpliftError(err);
187
+ if (ue.code === "subscription_required" || ue.code === "plan_inactive") {
188
+ confirm();
189
+ setConn(null);
190
+ setOffer({ reason: ue.code === "plan_inactive" ? "plan_inactive" : "client_limit", attempt });
191
+ setSheet("offer");
192
+ return;
193
+ }
194
+ setConn({ phone, busy: false, error: describeAddError(ue, phone, list.clients) });
195
+ }
196
+ }, [api, added, acknowledge, list.clients]);
197
+ /** Gets the host's phone for them, then connects at once if the channel's rules are confirmed, else asks. */
198
+ const startConnect = useCallback(async (h) => {
199
+ setConn({ phone: null, busy: false });
200
+ setSheet("connect");
201
+ let phone;
202
+ if (hostContact) {
203
+ try {
204
+ const p = coerceToE164((await hostContact(h.id)).phone ?? "");
205
+ if (p && validatePhone(p).valid)
206
+ phone = p;
207
+ }
208
+ catch { /* the sheet asks for it */ }
209
+ }
210
+ if (connectForRef.current?.id !== h.id)
211
+ return; // closed or switched meanwhile
212
+ if (phone && acksRef.current.has(channelForPhone(phone)))
213
+ await connectNow(h, phone, channelForPhone(phone));
214
+ else
215
+ setConn({ phone, busy: false });
216
+ }, [hostContact, connectNow]);
217
+ const connect = useCallback((h, draft) => {
218
+ setConnectFor(h);
219
+ connectForRef.current = h;
220
+ const keep = draft?.trim() ? { hostId: h.id, text: draft } : null;
221
+ setCarry(keep);
222
+ carryRef.current = keep;
223
+ const wall = plan?.subscription === "inactive" ? "plan_inactive"
224
+ : plan?.subscription === "free" && plan.freeLimit !== null && list.clients.length >= plan.freeLimit ? "client_limit" : null;
225
+ if (wall) {
226
+ setOffer({ reason: wall, upgradeFirst: h });
227
+ setSheet("offer");
228
+ }
229
+ else
230
+ void startConnect(h);
231
+ }, [plan, list.clients.length, startConnect]);
149
232
  const finishAdd = useCallback(async (attempt) => {
150
233
  try {
151
234
  added(await api.addClient(attempt.hostClientId ? attempt : { name: attempt.name, phone: attempt.phone, channel: attempt.channel }), attempt.hostClientId ?? undefined);
152
235
  }
153
236
  catch (err) {
154
- setResumeAdd({ ...attempt, error: asUpliftError(err).message || "Couldn't add this client. Try again." });
237
+ const message = asUpliftError(err).message || "Couldn't add this client. Try again.";
238
+ if (attempt.hostClientId && connectForRef.current) {
239
+ setConn({ phone: attempt.phone, busy: false, error: { form: message } });
240
+ setSheet("connect");
241
+ return;
242
+ }
243
+ setResumeAdd({ ...attempt, error: message });
155
244
  setSheet("add");
156
245
  }
157
246
  }, [api, added]);
@@ -201,19 +290,30 @@ export function UpliftPanel({ title = "Messages", hostName = "your app", initial
201
290
  const paneDrafts = selected ? bulk.results[selected.id] ?? null : null;
202
291
  // AI settings + full screen: the right end of the conversation header (and, on narrow panels where
203
292
  // the list shows alone, the list toolbar).
293
+ /** The host client behind an Uplift client: linked by the host (`upliftClientId`) or connected in this session. */
294
+ const hostClientFor = (clientId) => {
295
+ const viaSession = hostByClient.get(clientId);
296
+ return hostClients?.find((h) => h.upliftClientId === clientId || h.id === viaSession) ?? null;
297
+ };
298
+ const hostActionFor = (h) => (h?.hostLink
299
+ ? _jsx(HostLinkAction, { link: h.hostLink, onOpen: onOpenHostLink ? () => onOpenHostLink(h) : undefined })
300
+ : null);
204
301
  const headActions = (_jsxs("span", { className: "u-head-acts", children: [_jsxs("button", { type: "button", className: "u-iconbtn u-iconbtn-pair", "aria-label": "AI settings", title: "AI settings: your rules for drafts, and the \u2728 message options",
205
302
  // Like Config AI: with no client connected yet, connecting comes first.
206
303
  onClick: () => setSheet(list.clients.length === 0 && hostClients !== undefined ? "add" : "ai"), children: [_jsx("span", { className: "u-ai-spark", children: _jsx(IconSparkles, {}) }), _jsx(IconSliders, {})] }), _jsx("button", { type: "button", className: "u-iconbtn", "aria-pressed": full, "aria-label": full ? "Exit full screen" : "Full screen", title: full ? "Exit full screen (Esc)" : "Full screen", onClick: () => setFull((f) => !f), children: full ? _jsx(IconMinimize, {}) : _jsx(IconMaximize, {}) })] }));
207
304
  return (_jsxs("section", { className: `uplift${full ? " u-full" : ""}${className ? ` ${className}` : ""}`, "aria-label": "Uplift messages", children: [_jsx("h2", { className: "u-sr", children: title }), bulk.blocked
208
305
  ? (_jsxs("div", { className: "u-banner", role: "status", children: [_jsx("span", { children: "Your Uplift plan isn't active, so Bulk generate is paused." }), _jsx("span", { className: "u-sp" }), _jsx("button", { type: "button", className: "u-linkbtn", onClick: () => { setOffer({ reason: "plan_inactive" }); setSheet("offer"); }, children: "Reactivate" })] }))
209
306
  : null, _jsxs("div", { ref: split, className: `u-split${showThread ? " u-show-thread" : ""}`, children: [_jsx(ClientList, { status: list.status, error: list.error, rows: rows, totalCount: clients.length + hostOnly.length, search: search, onSearch: setSearch, sort: sort, onSort: setSort, selectedId: selectedId, onOpen: open, onRetry: list.reload, onAddClient: () => setSheet("add"), onBulk: () => setSheet("bulk"), headActions: headActions, bulkDisabled: bulk.running || clients.length + hostOnly.length === 0, hostManaged: hostClients !== undefined, drafts: bulk.results, bulkStatus: bulk.status, onQuickSent: quickSent, hostName: hostName, onOpenHost: openHost, onConnectHost: connect, now: clock }), selectedHost
210
- ? (_jsx(HostPreviewPane, { host: selectedHost, hostName: hostName, coachName: coachName, loadActivity: hostActivity, now: clock, onBack: () => setShowThread(false), onConnect: connect, purposes: proactive.purposes, onCustomize: () => setSheet("proactive"), instructions: instructions, connectedCount: list.clients.length, onPlanInactive: () => { setOffer({ reason: "plan_inactive" }); setSheet("offer"); }, cachedDrafts: bulk.results[hostSelId(selectedHost.id)] ?? null, headActions: headActions }, HOST_SEL + selectedHost.id))
307
+ ? (_jsx(HostPreviewPane, { host: selectedHost, hostName: hostName, coachName: coachName, loadActivity: hostActivity, now: clock, onBack: () => setShowThread(false), onConnect: connect, purposes: proactive.purposes, onCustomize: () => setSheet("proactive"), instructions: instructions, connectedCount: list.clients.length, onPlanInactive: () => { setOffer({ reason: "plan_inactive" }); setSheet("offer"); }, cachedDrafts: bulk.results[hostSelId(selectedHost.id)] ?? null, headActions: headActions, hostAction: hostActionFor(selectedHost) }, HOST_SEL + selectedHost.id))
211
308
  : selected
212
- ? (_jsx(ConversationPane, { client: selected, activitySourceLabel: hostName, now: clock, onBack: () => setShowThread(false), announce: setLive, onSent: sent, onNeedsPlan: (reason) => { setOffer({ reason: reason ?? "client_limit" }); setSheet("offer"); }, initialText: carryFor?.clientId === selected.id ? carryFor.text : undefined, cachedDrafts: paneDrafts, purposes: proactive.purposes, onCustomize: () => setSheet("proactive"), onRead: read, instructions: instructions, refreshKey: poll + threadPing, headActions: headActions }, selected.id))
213
- : _jsx("div", { className: "u-pane", children: _jsx("div", { className: "u-pane-head u-pane-head-empty", children: headActions }) })] }), sheet === "add" && (_jsx(AddClientSheet, { onClose: () => { setSheet(null); setConnectFor(null); setCarry(null); setResumeAdd(null); }, onAdded: (c) => { setResumeAdd(null); added(c); }, onNeedsPlan: (ctx) => { setOffer(ctx); setSheet("offer"); }, acknowledged: acks, onAcknowledge: acknowledge, hostClients: hostClients?.filter((h) => !h.upliftClientId && !linkedHere.has(h.id)), existing: list.clients, hostName: hostName, prefill: resumeAdd ?? (connectFor ? { name: connectFor.name, hostClientId: connectFor.id } : undefined) })), sheet === "bulk" && (_jsx(BulkGenerateSheet, { candidates: sortInbox(clients, hostOnly, sort).map((r) => (r.kind === "client"
309
+ ? (_jsx(ConversationPane, { client: selected, activitySourceLabel: hostName, now: clock, onBack: () => setShowThread(false), announce: setLive, onSent: sent, onNeedsPlan: (reason) => { setOffer({ reason: reason ?? "client_limit" }); setSheet("offer"); }, initialText: carryFor?.clientId === selected.id ? carryFor.text : undefined, cachedDrafts: paneDrafts, purposes: proactive.purposes, onCustomize: () => setSheet("proactive"), onRead: read, instructions: instructions, refreshKey: poll + threadPing, headActions: headActions, hostAction: hostActionFor(hostClientFor(selected.id)) }, selected.id))
310
+ : _jsx("div", { className: "u-pane", children: _jsx("div", { className: "u-pane-head u-pane-head-empty", children: headActions }) })] }), sheet === "add" && (_jsx(AddClientSheet, { onClose: () => { setSheet(null); setConnectFor(null); setCarry(null); setResumeAdd(null); }, onAdded: (c) => { setResumeAdd(null); added(c); }, onNeedsPlan: (ctx) => { setOffer(ctx); setSheet("offer"); }, acknowledged: acks, onAcknowledge: acknowledge, hostClients: hostClients?.filter((h) => !h.upliftClientId && !linkedHere.has(h.id)), existing: list.clients, hostName: hostName, prefill: resumeAdd ?? (connectFor ? { name: connectFor.name, hostClientId: connectFor.id } : undefined) })), sheet === "connect" && connectFor && conn && (_jsx(ConnectClientSheet, { name: connectFor.name, phone: conn.phone, error: conn.error, acknowledged: acks, busy: conn.busy, onConnect: (phone, channel) => { void connectNow(connectFor, phone, channel); }, onClose: () => { setSheet(null); setConnectFor(null); setCarry(null); setConn(null); } }, connectFor.id)), sheet === "bulk" && (_jsx(BulkGenerateSheet, { candidates: sortInbox(clients, hostOnly, sort).map((r) => (r.kind === "client"
214
311
  ? { target: { kind: "client", id: r.client.id }, name: r.client.name, lastActiveAt: r.client.lastActivity?.at ?? r.client.lastContactAt, connected: true }
215
- : { target: { kind: "host", id: r.host.id, name: r.host.name }, name: r.host.name, lastActiveAt: r.host.lastActiveAt ?? null, connected: false })), now: clock, onClose: () => setSheet(null), onGenerate: bulk.start, onEditInstructions: instructions.data?.canEdit ? () => setSheet("ai") : undefined })), sheet === "proactive" && _jsx(ProactiveOptionsSheet, { state: proactive, onClose: () => setSheet(null) }), sheet === "ai" && _jsx(AiSettingsSheet, { instructions: instructions, proactive: proactive, hostName: hostName, onClose: () => setSheet(null), onUpgrade: () => { setOffer({ reason: "feature" }); setSheet("offer"); } }), sheet === "offer" && (_jsx(OfferSheet, { onClose: () => { setSheet(null); setConnectFor(null); }, onCheckout: onCheckout, hostName: hostName, reason: offer.reason, connecting: offer.attempt?.name, connected: list.clients.map((c) => ({ id: c.id, name: c.name })),
312
+ : { target: { kind: "host", id: r.host.id, name: r.host.name }, name: r.host.name, lastActiveAt: r.host.lastActiveAt ?? null, connected: false })), now: clock, onClose: () => setSheet(null), onGenerate: bulk.start, onEditInstructions: instructions.data?.canEdit ? () => setSheet("ai") : undefined })), sheet === "proactive" && _jsx(ProactiveOptionsSheet, { state: proactive, onClose: () => setSheet(null) }), sheet === "ai" && _jsx(AiSettingsSheet, { instructions: instructions, proactive: proactive, hostName: hostName, onClose: () => setSheet(null), onUpgrade: () => { setOffer({ reason: "feature" }); setSheet("offer"); } }), sheet === "offer" && (_jsx(OfferSheet, { onClose: () => { setSheet(null); setConnectFor(null); setCarry(null); }, onCheckout: onCheckout, hostName: hostName, reason: offer.reason, freeClients: plan?.freeLimit ?? undefined, connecting: offer.attempt?.name ?? offer.upgradeFirst?.name, connected: list.clients.map((c) => ({ id: c.id, name: c.name })),
216
313
  // Paid: finish the add the coach was making. Only if that fails does the form come back, prefilled.
217
- onUpgraded: offer.attempt ? () => { void finishAdd(offer.attempt); } : undefined })), _jsx("div", { className: "u-sr", "aria-live": "polite", children: live })] }));
314
+ // Upgraded before entering anything: the connect form opens for that client.
315
+ onUpgraded: offer.attempt ? () => { planActive(); void finishAdd(offer.attempt); }
316
+ : offer.upgradeFirst ? () => { planActive(); void startConnect(offer.upgradeFirst); }
317
+ : undefined })), _jsx("div", { className: "u-sr", "aria-live": "polite", children: live })] }));
218
318
  }
219
319
  //# sourceMappingURL=UpliftPanel.js.map