@burdenoff/microfe-conversations 2026.930.1 → 2026.1006.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,19 @@
1
1
  import { useConversations as e } from "../providers/ConversationsProvider.js";
2
2
  import { useTr as t } from "../utils/i18n.js";
3
3
  import { cn as n } from "../utils/cn.js";
4
- import { useCreateConversation as r } from "../hooks/useConversationQueries.js";
5
- import { QuotaExhaustedDialog as ee } from "./QuotaExhaustedDialog.js";
6
- import { nativeImpact as te, nativeNotify as i } from "../../utils/nativeBridge.js";
7
- import { MemberPicker as a } from "./MemberPicker.js";
4
+ import { useCreateConversation as ee, useStartDirectConversation as r } from "../hooks/useConversationQueries.js";
5
+ import { QuotaExhaustedDialog as i } from "./QuotaExhaustedDialog.js";
6
+ import { nativeImpact as te, nativeNotify as a } from "../../utils/nativeBridge.js";
7
+ import { MemberPicker as ne } from "./MemberPicker.js";
8
8
  import { useCallback as o, useMemo as s, useState as c } from "react";
9
- import { Globe as l, Hash as u, Lock as d, Megaphone as ne, MessageCircle as re, Shield as ie, Users as ae } from "lucide-react";
10
- import { useNavigate as oe } from "react-router";
11
- import { isQuotaExhaustedError as f } from "@burdenoff/fe-libs/shared/utils";
12
- import { useEventBus as se } from "@burdenoff/fe-libs/shared/events";
13
- import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
14
- import { Dialog as g, DialogContent as _, DialogDescription as v, DialogFooter as y, DialogHeader as ce, DialogTitle as le } from "@burdenoff/fe-libs/ui";
9
+ import { Globe as l, Hash as u, Lock as d, Megaphone as f, MessageCircle as p, Shield as re, Users as ie } from "lucide-react";
10
+ import { useNavigate as ae } from "react-router";
11
+ import { isQuotaExhaustedError as m } from "@burdenoff/fe-libs/shared/utils";
12
+ import { useEventBus as oe } from "@burdenoff/fe-libs/shared/events";
13
+ import { Fragment as se, jsx as h, jsxs as g } from "react/jsx-runtime";
14
+ import { Dialog as ce, DialogContent as le, DialogDescription as ue, DialogFooter as _, DialogHeader as de, DialogTitle as v } from "@burdenoff/fe-libs/ui";
15
15
  //#region src/conversations/components/NewConversationDialog.tsx
16
- function ue(e) {
16
+ function y(e) {
17
17
  if ("graphQLErrors" in e) {
18
18
  let t = e.graphQLErrors;
19
19
  if (t && t.length > 0 && t[0]?.message) return t[0].message;
@@ -21,251 +21,253 @@ function ue(e) {
21
21
  return e.message;
22
22
  }
23
23
  function b({ open: b, onOpenChange: x, onQuotaExhausted: S, onQuotaDialogClose: C, onCreated: w }) {
24
- let { createConversation: T, loading: E, error: D } = r(), { currentUser: O } = e(), k = se(), A = t(), j = oe(), [M, N] = c(!1), P = s(() => [
24
+ let { createConversation: T, loading: fe, error: pe } = ee(), { startDirectConversation: E, loading: me, error: he } = r(), { currentUser: D } = e(), O = oe(), k = t(), A = ae(), [j, M] = c(!1), N = s(() => [
25
25
  {
26
26
  type: "DIRECT",
27
- label: A("conversations.directMessage", "Direct Message"),
28
- description: A("conversations.directMessageDescription", "One-on-one private conversation"),
29
- icon: /* @__PURE__ */ m(re, { size: 20 })
27
+ label: k("conversations.directMessage", "Direct Message"),
28
+ description: k("conversations.directMessageDescription", "One-on-one private conversation"),
29
+ icon: /* @__PURE__ */ h(p, { size: 20 })
30
30
  },
31
31
  {
32
32
  type: "GROUP",
33
- label: A("conversations.groupChat", "Group Chat"),
34
- description: A("conversations.groupChatDescription", "Invite multiple people to a group conversation"),
35
- icon: /* @__PURE__ */ m(ae, { size: 20 })
33
+ label: k("conversations.groupChat", "Group Chat"),
34
+ description: k("conversations.groupChatDescription", "Invite multiple people to a group conversation"),
35
+ icon: /* @__PURE__ */ h(ie, { size: 20 })
36
36
  },
37
37
  {
38
38
  type: "CHANNEL",
39
- label: A("conversations.channel", "Channel"),
40
- description: A("conversations.channelDescription", "A topic-based channel that anyone can join"),
41
- icon: /* @__PURE__ */ m(u, { size: 20 })
39
+ label: k("conversations.channel", "Channel"),
40
+ description: k("conversations.channelDescription", "A topic-based channel that anyone can join"),
41
+ icon: /* @__PURE__ */ h(u, { size: 20 })
42
42
  },
43
43
  {
44
44
  type: "ANNOUNCEMENT",
45
- label: A("conversations.announcement", "Announcement"),
46
- description: A("conversations.announcementDescription", "Broadcast messages to a large audience"),
47
- icon: /* @__PURE__ */ m(ne, { size: 20 })
45
+ label: k("conversations.announcement", "Announcement"),
46
+ description: k("conversations.announcementDescription", "Broadcast messages to a large audience"),
47
+ icon: /* @__PURE__ */ h(f, { size: 20 })
48
48
  }
49
- ], [A]), F = s(() => [
49
+ ], [k]), P = s(() => [
50
50
  {
51
51
  value: "PUBLIC",
52
- label: A("conversations.public", "Public"),
53
- description: A("conversations.publicDescription", "Anyone in the workspace can discover and join"),
54
- icon: /* @__PURE__ */ m(l, { size: 16 })
52
+ label: k("conversations.public", "Public"),
53
+ description: k("conversations.publicDescription", "Anyone in the workspace can discover and join"),
54
+ icon: /* @__PURE__ */ h(l, { size: 16 })
55
55
  },
56
56
  {
57
57
  value: "PRIVATE",
58
- label: A("conversations.private", "Private"),
59
- description: A("conversations.privateDescription", "Only invited members can access"),
60
- icon: /* @__PURE__ */ m(d, { size: 16 })
58
+ label: k("conversations.private", "Private"),
59
+ description: k("conversations.privateDescription", "Only invited members can access"),
60
+ icon: /* @__PURE__ */ h(d, { size: 16 })
61
61
  },
62
62
  {
63
63
  value: "PROTECTED",
64
- label: A("conversations.protected", "Protected"),
65
- description: A("conversations.protectedDescription", "Discoverable but requires approval to join"),
66
- icon: /* @__PURE__ */ m(ie, { size: 16 })
64
+ label: k("conversations.protected", "Protected"),
65
+ description: k("conversations.protectedDescription", "Discoverable but requires approval to join"),
66
+ icon: /* @__PURE__ */ h(re, { size: 16 })
67
67
  }
68
- ], [A]), [I, L] = c("GROUP"), [R, z] = c(""), [B, V] = c(""), [H, U] = c("PRIVATE"), [W, G] = c([]), K = I === "DIRECT", q = !K, J = s(() => W.map((e) => e.id), [W]), Y = o(() => {
69
- L("GROUP"), z(""), V(""), U("PRIVATE"), G([]);
70
- }, []), de = o((e) => {
71
- G((t) => t.some((t) => t.id === e.id) ? t : K ? [e] : [...t, e]);
72
- }, [K]), X = o((e) => {
73
- G((t) => t.filter((t) => t.id !== e));
74
- }, []), Z = I === "DIRECT" || I === "GROUP", fe = s(() => O?.id ? [O.id] : [], [O?.id]), Q = o((e) => {
75
- e || Y(), x(e);
76
- }, [x, Y]), pe = o(async () => {
77
- if (!(Z && J.length === 0) && !(q && !R.trim())) {
68
+ ], [k]), [F, I] = c("GROUP"), [L, R] = c(""), [z, B] = c(""), [V, H] = c("PRIVATE"), [U, W] = c([]), G = F === "DIRECT", K = !G, q = G ? he : pe, J = G ? me : fe, Y = s(() => U.map((e) => e.id), [U]), X = o(() => {
69
+ I("GROUP"), R(""), B(""), H("PRIVATE"), W([]);
70
+ }, []), ge = o((e) => {
71
+ W((t) => t.some((t) => t.id === e.id) ? t : G ? [e] : [...t, e]);
72
+ }, [G]), _e = o((e) => {
73
+ W((t) => t.filter((t) => t.id !== e));
74
+ }, []), Z = F === "DIRECT" || F === "GROUP", ve = s(() => D?.id ? [D.id] : [], [D?.id]), Q = o((e) => {
75
+ e || X(), x(e);
76
+ }, [x, X]), ye = o(async () => {
77
+ if (!(Z && Y.length === 0) && !(K && !L.trim())) {
78
78
  te("light");
79
79
  try {
80
- let e = await T({
81
- type: I,
82
- title: q ? R.trim() : void 0,
83
- description: B.trim() || void 0,
84
- participantIds: J,
85
- visibility: H
80
+ let e = G ? await E(Y[0]) : await T({
81
+ type: F,
82
+ title: K ? L.trim() : void 0,
83
+ description: z.trim() || void 0,
84
+ participantIds: Y,
85
+ visibility: V
86
86
  });
87
87
  if (!e) {
88
- i("error");
88
+ a("error");
89
89
  return;
90
90
  }
91
- i("success"), k.emit("conversations.conversation.created", {
91
+ a("success"), O.emit("conversations.conversation.created", {
92
92
  conversationId: e.id,
93
- conversationType: I,
93
+ conversationType: F,
94
94
  source: "new-conversation-dialog"
95
- }), Y(), x(!1), w?.(e.id);
95
+ }), X(), x(!1), w?.(e.id);
96
96
  } catch (e) {
97
- if (f(e)) {
98
- Y(), N(!0), S ? S() : x(!1);
97
+ if (m(e)) {
98
+ X(), M(!0), S ? S() : x(!1);
99
99
  return;
100
100
  }
101
- throw i("error"), e;
101
+ throw a("error"), e;
102
102
  }
103
103
  }
104
104
  }, [
105
- k,
105
+ O,
106
106
  Z,
107
- J,
108
- q,
109
- R,
110
- T,
111
- I,
112
- B,
113
- H,
114
107
  Y,
108
+ K,
109
+ L,
110
+ T,
111
+ E,
112
+ F,
113
+ z,
114
+ V,
115
+ X,
115
116
  x,
116
117
  S,
117
- w
118
- ]), me = o(() => {
119
- N(!1), C?.();
120
- }, [C]), $ = (!Z || J.length > 0) && (!q || R.trim().length > 0);
121
- return /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m(g, {
118
+ w,
119
+ G
120
+ ]), be = o(() => {
121
+ M(!1), C?.();
122
+ }, [C]), $ = (!Z || Y.length > 0) && (!K || L.trim().length > 0);
123
+ return /* @__PURE__ */ g(se, { children: [/* @__PURE__ */ h(ce, {
122
124
  open: b,
123
125
  onOpenChange: Q,
124
- children: /* @__PURE__ */ h(_, {
126
+ children: /* @__PURE__ */ g(le, {
125
127
  className: "sm:max-w-[640px] max-h-[90vh] overflow-y-auto",
126
128
  "data-tour": "new-conversation-dialog",
127
129
  children: [
128
- /* @__PURE__ */ h(ce, { children: [/* @__PURE__ */ m(le, { children: A("conversations.newConversation", "New Conversation") }), /* @__PURE__ */ m(v, { children: A("conversations.newConversationSubtitle", "Start a new conversation with your team") })] }),
129
- /* @__PURE__ */ h("div", {
130
+ /* @__PURE__ */ g(de, { children: [/* @__PURE__ */ h(v, { children: k("conversations.newConversation", "New Conversation") }), /* @__PURE__ */ h(ue, { children: k("conversations.newConversationSubtitle", "Start a new conversation with your team") })] }),
131
+ /* @__PURE__ */ g("div", {
130
132
  className: "space-y-6",
131
133
  children: [
132
- /* @__PURE__ */ h("section", {
134
+ /* @__PURE__ */ g("section", {
133
135
  "data-tour": "conversation-type-selector",
134
136
  className: "space-y-3",
135
- children: [/* @__PURE__ */ m("h3", {
137
+ children: [/* @__PURE__ */ h("h3", {
136
138
  className: "text-sm font-semibold text-text-primary",
137
- children: A("conversations.conversationType", "Conversation Type")
138
- }), /* @__PURE__ */ m("div", {
139
+ children: k("conversations.conversationType", "Conversation Type")
140
+ }), /* @__PURE__ */ h("div", {
139
141
  className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
140
- children: P.map((e) => /* @__PURE__ */ h("button", {
142
+ children: N.map((e) => /* @__PURE__ */ g("button", {
141
143
  type: "button",
142
144
  onClick: () => {
143
- L(e.type), e.type === "DIRECT" && G((e) => e.slice(0, 1));
145
+ I(e.type), e.type === "DIRECT" && W((e) => e.slice(0, 1));
144
146
  },
145
- className: n("flex items-start gap-3 p-4 rounded-xl border text-left transition-all duration-150", I === e.type ? "border-primary bg-action-primary-bg/5 ring-1 ring-primary/20" : "border-border-subtle hover:border-muted-foreground/30 hover:bg-bg-sunken/30"),
146
- children: [/* @__PURE__ */ m("div", {
147
- className: n("p-2 rounded-lg", I === e.type ? "bg-action-primary-bg/10 text-primary" : "bg-bg-sunken text-text-secondary"),
147
+ className: n("flex items-start gap-3 p-4 rounded-xl border text-left transition-all duration-150", F === e.type ? "border-primary bg-action-primary-bg/5 ring-1 ring-primary/20" : "border-border-subtle hover:border-muted-foreground/30 hover:bg-bg-sunken/30"),
148
+ children: [/* @__PURE__ */ h("div", {
149
+ className: n("p-2 rounded-lg", F === e.type ? "bg-action-primary-bg/10 text-primary" : "bg-bg-sunken text-text-secondary"),
148
150
  children: e.icon
149
- }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
151
+ }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
150
152
  className: "text-sm font-medium text-text-primary",
151
153
  children: e.label
152
- }), /* @__PURE__ */ m("p", {
154
+ }), /* @__PURE__ */ h("p", {
153
155
  className: "text-xs text-text-secondary mt-0.5",
154
156
  children: e.description
155
157
  })] })]
156
158
  }, e.type))
157
159
  })]
158
160
  }),
159
- !K && /* @__PURE__ */ h("section", {
161
+ !G && /* @__PURE__ */ g("section", {
160
162
  "data-tour": "conversation-visibility-selector",
161
163
  className: "space-y-3",
162
164
  children: [
163
- /* @__PURE__ */ m("h3", {
165
+ /* @__PURE__ */ h("h3", {
164
166
  className: "text-sm font-semibold text-text-primary",
165
- children: A("conversations.visibility", "Visibility")
167
+ children: k("conversations.visibility", "Visibility")
166
168
  }),
167
- /* @__PURE__ */ m("div", {
169
+ /* @__PURE__ */ h("div", {
168
170
  className: "flex gap-2 flex-wrap",
169
- children: F.map((e) => /* @__PURE__ */ h("button", {
171
+ children: P.map((e) => /* @__PURE__ */ g("button", {
170
172
  type: "button",
171
- onClick: () => U(e.value),
172
- className: n("flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm transition-all", H === e.value ? "border-primary bg-action-primary-bg/5 text-primary font-medium" : "border-border-subtle text-text-secondary hover:text-text-primary hover:bg-bg-sunken/30"),
173
+ onClick: () => H(e.value),
174
+ className: n("flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm transition-all", V === e.value ? "border-primary bg-action-primary-bg/5 text-primary font-medium" : "border-border-subtle text-text-secondary hover:text-text-primary hover:bg-bg-sunken/30"),
173
175
  children: [e.icon, e.label]
174
176
  }, e.value))
175
177
  }),
176
- /* @__PURE__ */ m("p", {
178
+ /* @__PURE__ */ h("p", {
177
179
  className: "text-xs text-text-secondary",
178
- children: F.find((e) => e.value === H)?.description
180
+ children: P.find((e) => e.value === V)?.description
179
181
  })
180
182
  ]
181
183
  }),
182
- q && /* @__PURE__ */ h("section", {
184
+ K && /* @__PURE__ */ g("section", {
183
185
  "data-tour": "conversation-create-details",
184
186
  className: "space-y-3",
185
- children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("label", {
187
+ children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ g("label", {
186
188
  htmlFor: "conv-title",
187
189
  className: "text-sm font-semibold text-text-primary",
188
190
  children: [
189
- A("conversations.name", "Name"),
191
+ k("conversations.name", "Name"),
190
192
  " ",
191
- /* @__PURE__ */ m("span", {
193
+ /* @__PURE__ */ h("span", {
192
194
  className: "text-status-error-text",
193
195
  children: "*"
194
196
  })
195
197
  ]
196
- }), /* @__PURE__ */ m("input", {
198
+ }), /* @__PURE__ */ h("input", {
197
199
  id: "conv-title",
198
200
  type: "text",
199
- value: R,
200
- onChange: (e) => z(e.target.value),
201
- placeholder: I === "CHANNEL" ? A("conversations.channelNamePlaceholder", "e.g., engineering-general") : A("conversations.conversationNamePlaceholder", "e.g., Product Launch Q1"),
201
+ value: L,
202
+ onChange: (e) => R(e.target.value),
203
+ placeholder: F === "CHANNEL" ? k("conversations.channelNamePlaceholder", "e.g., engineering-general") : k("conversations.conversationNamePlaceholder", "e.g., Product Launch Q1"),
202
204
  maxLength: 200,
203
205
  className: "mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
204
- })] }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("label", {
206
+ })] }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
205
207
  htmlFor: "conv-desc",
206
208
  className: "text-sm font-semibold text-text-primary",
207
- children: A("conversations.description", "Description")
208
- }), /* @__PURE__ */ m("textarea", {
209
+ children: k("conversations.description", "Description")
210
+ }), /* @__PURE__ */ h("textarea", {
209
211
  id: "conv-desc",
210
- value: B,
211
- onChange: (e) => V(e.target.value),
212
- placeholder: A("conversations.descriptionPlaceholder", "What is this conversation about?"),
212
+ value: z,
213
+ onChange: (e) => B(e.target.value),
214
+ placeholder: k("conversations.descriptionPlaceholder", "What is this conversation about?"),
213
215
  rows: 2,
214
216
  maxLength: 1e3,
215
217
  className: "mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none"
216
218
  })] })]
217
219
  }),
218
- /* @__PURE__ */ h("section", {
220
+ /* @__PURE__ */ g("section", {
219
221
  "data-tour": "conversation-participants",
220
222
  className: "space-y-3",
221
- children: [/* @__PURE__ */ h("h3", {
223
+ children: [/* @__PURE__ */ g("h3", {
222
224
  className: "text-sm font-semibold text-text-primary",
223
- children: [K ? A("conversations.recipient", "Recipient") : A("conversations.participants", "Participants"), Z ? /* @__PURE__ */ m("span", {
225
+ children: [G ? k("conversations.recipient", "Recipient") : k("conversations.participants", "Participants"), Z ? /* @__PURE__ */ h("span", {
224
226
  className: "ml-1 text-status-error-text",
225
227
  children: "*"
226
- }) : /* @__PURE__ */ h("span", {
228
+ }) : /* @__PURE__ */ g("span", {
227
229
  className: "ml-1.5 text-xs font-normal text-text-secondary",
228
230
  children: [
229
231
  "(",
230
- A("conversations.optional", "optional"),
232
+ k("conversations.optional", "optional"),
231
233
  ")"
232
234
  ]
233
235
  })]
234
- }), /* @__PURE__ */ m(a, {
235
- selected: W,
236
- onAdd: de,
237
- onRemove: X,
238
- single: K,
239
- excludeIds: fe
236
+ }), /* @__PURE__ */ h(ne, {
237
+ selected: U,
238
+ onAdd: ge,
239
+ onRemove: _e,
240
+ single: G,
241
+ excludeIds: ve
240
242
  })]
241
243
  }),
242
- D && !f(D) && /* @__PURE__ */ m("div", {
244
+ q && !m(q) && /* @__PURE__ */ h("div", {
243
245
  className: "text-xs text-status-error-text rounded-lg border border-status-error-border/30 bg-status-error-bg/10 px-3 py-2",
244
- children: ue(D)
246
+ children: y(q)
245
247
  })
246
248
  ]
247
249
  }),
248
- /* @__PURE__ */ h(y, { children: [/* @__PURE__ */ m("button", {
250
+ /* @__PURE__ */ g(_, { children: [/* @__PURE__ */ h("button", {
249
251
  type: "button",
250
252
  onClick: () => Q(!1),
251
253
  className: "px-4 py-2 text-sm font-medium rounded-lg text-text-secondary hover:text-text-primary hover:bg-bg-sunken/50 transition-colors",
252
- children: A("conversations.cancel", "Cancel")
253
- }), /* @__PURE__ */ m("button", {
254
+ children: k("conversations.cancel", "Cancel")
255
+ }), /* @__PURE__ */ h("button", {
254
256
  type: "button",
255
- onClick: () => void pe(),
256
- disabled: !$ || E,
257
- className: n("inline-flex items-center gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-all", $ && !E ? "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90 shadow-sm" : "bg-bg-sunken text-text-secondary cursor-not-allowed"),
258
- children: E ? A("conversations.creating", "Creating...") : A("conversations.createConversation", "Create Conversation")
257
+ onClick: () => void ye(),
258
+ disabled: !$ || J,
259
+ className: n("inline-flex items-center gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-all", $ && !J ? "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90 shadow-sm" : "bg-bg-sunken text-text-secondary cursor-not-allowed"),
260
+ children: J ? k("conversations.creating", "Creating...") : k("conversations.createConversation", "Create Conversation")
259
261
  })] })
260
262
  ]
261
263
  })
262
- }), /* @__PURE__ */ m(ee, {
263
- open: M,
264
- title: A("conversations.quota.conversations.title", "Conversation Quota Reached"),
265
- description: A("conversations.quota.conversations.description", "You've reached the conversation limit for your current plan. View billing to upgrade or add more capacity."),
266
- onClose: me,
264
+ }), /* @__PURE__ */ h(i, {
265
+ open: j,
266
+ title: k("conversations.quota.conversations.title", "Conversation Quota Reached"),
267
+ description: k("conversations.quota.conversations.description", "You've reached the conversation limit for your current plan. View billing to upgrade or add more capacity."),
268
+ onClose: be,
267
269
  onConfirm: () => {
268
- N(!1), j("/billing");
270
+ M(!1), A("/billing");
269
271
  }
270
272
  })] });
271
273
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NewConversationDialog.js","names":[],"sources":["../../../src/conversations/components/NewConversationDialog.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from \"react\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport { isQuotaExhaustedError } from \"@burdenoff/fe-libs/shared/utils\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"@burdenoff/fe-libs/ui\";\nimport {\n Globe,\n Hash,\n Lock,\n Megaphone,\n MessageCircle,\n Shield,\n Users,\n} from \"lucide-react\";\nimport { useNavigate } from \"react-router\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useCreateConversation,\n type WorkspaceDirectoryMember,\n} from \"../hooks/useConversationQueries\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport { MemberPicker } from \"./MemberPicker\";\nimport { QuotaExhaustedDialog } from \"./QuotaExhaustedDialog\";\nimport type { ConversationType, ConversationVisibility } from \"../types\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n/** Extract the first meaningful GraphQL error message from an ApolloError. */\nfunction getErrorMessage(error: Error): string {\n if (\"graphQLErrors\" in error) {\n const gqlErrors = (error as { graphQLErrors?: Array<{ message?: string }> })\n .graphQLErrors;\n if (gqlErrors && gqlErrors.length > 0 && gqlErrors[0]?.message) {\n return gqlErrors[0].message;\n }\n }\n return error.message;\n}\n\ninterface ConversationTypeOption {\n type: ConversationType;\n label: string;\n description: string;\n icon: React.ReactNode;\n}\n\nexport interface NewConversationDialogProps {\n /** Whether the dialog is open. */\n open: boolean;\n /** Open-state change handler. Fires with `false` on close (overlay click,\n * Escape, X button, Cancel). */\n onOpenChange: (open: boolean) => void;\n /**\n * Optional quota-failure hook for route wrappers that need to close the\n * create modal without running their normal close navigation.\n */\n onQuotaExhausted?: () => void;\n /** Called when the quota dialog is dismissed without opening billing. */\n onQuotaDialogClose?: () => void;\n /**\n * Called after a conversation is successfully created. Receives the new\n * conversation id so the parent can navigate to the detail route.\n * The dialog also closes itself (via `onOpenChange(false)`) before this\n * fires, so the parent does not need to close the dialog manually.\n */\n onCreated?: (conversationId: string) => void;\n}\n\n/**\n * NewConversationDialog — modal form for creating a new conversation.\n *\n * Renders inside the canonical `<Dialog>` primitive from\n * `@burdenoff/fe-libs/ui` so it inherits theme tokens, focus management,\n * and overlay behaviour from the shell.\n *\n * Form state is owned locally; on successful submit the dialog clears\n * state, closes itself, and invokes `onCreated` with the new\n * conversation id.\n */\nexport function NewConversationDialog({\n open,\n onOpenChange,\n onQuotaExhausted,\n onQuotaDialogClose,\n onCreated,\n}: NewConversationDialogProps) {\n const { createConversation, loading, error } = useCreateConversation();\n const { currentUser } = useConversations();\n const bus = useEventBus();\n const tr = useTr();\n const navigate = useNavigate();\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n\n const CONVERSATION_TYPES: ConversationTypeOption[] = useMemo(\n () => [\n {\n type: \"DIRECT\" as ConversationType,\n label: tr(\"conversations.directMessage\", \"Direct Message\"),\n description: tr(\n \"conversations.directMessageDescription\",\n \"One-on-one private conversation\",\n ),\n icon: <MessageCircle size={20} />,\n },\n {\n type: \"GROUP\" as ConversationType,\n label: tr(\"conversations.groupChat\", \"Group Chat\"),\n description: tr(\n \"conversations.groupChatDescription\",\n \"Invite multiple people to a group conversation\",\n ),\n icon: <Users size={20} />,\n },\n {\n type: \"CHANNEL\" as ConversationType,\n label: tr(\"conversations.channel\", \"Channel\"),\n description: tr(\n \"conversations.channelDescription\",\n \"A topic-based channel that anyone can join\",\n ),\n icon: <Hash size={20} />,\n },\n {\n type: \"ANNOUNCEMENT\" as ConversationType,\n label: tr(\"conversations.announcement\", \"Announcement\"),\n description: tr(\n \"conversations.announcementDescription\",\n \"Broadcast messages to a large audience\",\n ),\n icon: <Megaphone size={20} />,\n },\n ],\n [tr],\n );\n\n const VISIBILITY_OPTIONS: Array<{\n value: ConversationVisibility;\n label: string;\n description: string;\n icon: React.ReactNode;\n }> = useMemo(\n () => [\n {\n value: \"PUBLIC\" as ConversationVisibility,\n label: tr(\"conversations.public\", \"Public\"),\n description: tr(\n \"conversations.publicDescription\",\n \"Anyone in the workspace can discover and join\",\n ),\n icon: <Globe size={16} />,\n },\n {\n value: \"PRIVATE\" as ConversationVisibility,\n label: tr(\"conversations.private\", \"Private\"),\n description: tr(\n \"conversations.privateDescription\",\n \"Only invited members can access\",\n ),\n icon: <Lock size={16} />,\n },\n {\n value: \"PROTECTED\" as ConversationVisibility,\n label: tr(\"conversations.protected\", \"Protected\"),\n description: tr(\n \"conversations.protectedDescription\",\n \"Discoverable but requires approval to join\",\n ),\n icon: <Shield size={16} />,\n },\n ],\n [tr],\n );\n\n const [selectedType, setSelectedType] = useState<ConversationType>(\"GROUP\");\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [visibility, setVisibility] =\n useState<ConversationVisibility>(\"PRIVATE\");\n const [selectedMembers, setSelectedMembers] = useState<\n WorkspaceDirectoryMember[]\n >([]);\n\n const isDirectMessage = selectedType === \"DIRECT\";\n const needsTitle = !isDirectMessage;\n\n const participantIds = useMemo(\n () => selectedMembers.map((member) => member.id),\n [selectedMembers],\n );\n\n const resetForm = useCallback(() => {\n setSelectedType(\"GROUP\");\n setTitle(\"\");\n setDescription(\"\");\n setVisibility(\"PRIVATE\");\n setSelectedMembers([]);\n }, []);\n\n const addMember = useCallback(\n (member: WorkspaceDirectoryMember) => {\n setSelectedMembers((prev) => {\n if (prev.some((existing) => existing.id === member.id)) return prev;\n // A direct message has exactly one recipient.\n return isDirectMessage ? [member] : [...prev, member];\n });\n },\n [isDirectMessage],\n );\n\n const removeMember = useCallback((userId: string) => {\n setSelectedMembers((prev) => prev.filter((member) => member.id !== userId));\n }, []);\n\n const requiresParticipants =\n selectedType === \"DIRECT\" || selectedType === \"GROUP\";\n\n // Never offer the current user as a participant — they are added implicitly\n // as the conversation creator.\n const excludeIds = useMemo(\n () => (currentUser?.id ? [currentUser.id] : []),\n [currentUser?.id],\n );\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean) => {\n if (!nextOpen) {\n resetForm();\n }\n onOpenChange(nextOpen);\n },\n [onOpenChange, resetForm],\n );\n\n const handleCreate = useCallback(async () => {\n if (requiresParticipants && participantIds.length === 0) return;\n if (needsTitle && !title.trim()) return;\n\n nativeImpact(\"light\");\n try {\n const conversation = await createConversation({\n type: selectedType,\n title: needsTitle ? title.trim() : undefined,\n description: description.trim() || undefined,\n participantIds,\n visibility,\n });\n\n if (!conversation) {\n nativeNotify(\"error\");\n return;\n }\n nativeNotify(\"success\");\n bus.emit(\"conversations.conversation.created\", {\n conversationId: conversation.id,\n conversationType: selectedType,\n source: \"new-conversation-dialog\",\n });\n resetForm();\n onOpenChange(false);\n onCreated?.(conversation.id);\n } catch (error) {\n if (isQuotaExhaustedError(error)) {\n resetForm();\n setShowQuotaExhausted(true);\n if (onQuotaExhausted) {\n onQuotaExhausted();\n } else {\n onOpenChange(false);\n }\n return;\n }\n nativeNotify(\"error\");\n throw error;\n }\n }, [\n bus,\n requiresParticipants,\n participantIds,\n needsTitle,\n title,\n createConversation,\n selectedType,\n description,\n visibility,\n resetForm,\n onOpenChange,\n onQuotaExhausted,\n onCreated,\n ]);\n\n const handleQuotaDialogClose = useCallback(() => {\n setShowQuotaExhausted(false);\n onQuotaDialogClose?.();\n }, [onQuotaDialogClose]);\n\n const canCreate =\n (!requiresParticipants || participantIds.length > 0) &&\n (!needsTitle || title.trim().length > 0);\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleOpenChange}>\n <DialogContent\n className=\"sm:max-w-[640px] max-h-[90vh] overflow-y-auto\"\n data-tour=\"new-conversation-dialog\"\n >\n <DialogHeader>\n <DialogTitle>\n {tr(\"conversations.newConversation\", \"New Conversation\")}\n </DialogTitle>\n <DialogDescription>\n {tr(\n \"conversations.newConversationSubtitle\",\n \"Start a new conversation with your team\",\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-6\">\n <section\n data-tour=\"conversation-type-selector\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr(\"conversations.conversationType\", \"Conversation Type\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n {CONVERSATION_TYPES.map((option) => (\n <button\n key={option.type}\n type=\"button\"\n onClick={() => {\n setSelectedType(option.type);\n if (option.type === \"DIRECT\") {\n setSelectedMembers((prev) => prev.slice(0, 1));\n }\n }}\n className={cn(\n \"flex items-start gap-3 p-4 rounded-xl border text-left transition-all duration-150\",\n selectedType === option.type\n ? \"border-primary bg-action-primary-bg/5 ring-1 ring-primary/20\"\n : \"border-border-subtle hover:border-muted-foreground/30 hover:bg-bg-sunken/30\",\n )}\n >\n <div\n className={cn(\n \"p-2 rounded-lg\",\n selectedType === option.type\n ? \"bg-action-primary-bg/10 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n )}\n >\n {option.icon}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {option.label}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {option.description}\n </p>\n </div>\n </button>\n ))}\n </div>\n </section>\n\n {!isDirectMessage && (\n <section\n data-tour=\"conversation-visibility-selector\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr(\"conversations.visibility\", \"Visibility\")}\n </h3>\n <div className=\"flex gap-2 flex-wrap\">\n {VISIBILITY_OPTIONS.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setVisibility(option.value)}\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm transition-all\",\n visibility === option.value\n ? \"border-primary bg-action-primary-bg/5 text-primary font-medium\"\n : \"border-border-subtle text-text-secondary hover:text-text-primary hover:bg-bg-sunken/30\",\n )}\n >\n {option.icon}\n {option.label}\n </button>\n ))}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {\n VISIBILITY_OPTIONS.find(\n (option) => option.value === visibility,\n )?.description\n }\n </p>\n </section>\n )}\n\n {needsTitle && (\n <section\n data-tour=\"conversation-create-details\"\n className=\"space-y-3\"\n >\n <div>\n <label\n htmlFor=\"conv-title\"\n className=\"text-sm font-semibold text-text-primary\"\n >\n {tr(\"conversations.name\", \"Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"conv-title\"\n type=\"text\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder={\n selectedType === \"CHANNEL\"\n ? tr(\n \"conversations.channelNamePlaceholder\",\n \"e.g., engineering-general\",\n )\n : tr(\n \"conversations.conversationNamePlaceholder\",\n \"e.g., Product Launch Q1\",\n )\n }\n maxLength={200}\n className=\"mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label\n htmlFor=\"conv-desc\"\n className=\"text-sm font-semibold text-text-primary\"\n >\n {tr(\"conversations.description\", \"Description\")}\n </label>\n <textarea\n id=\"conv-desc\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder={tr(\n \"conversations.descriptionPlaceholder\",\n \"What is this conversation about?\",\n )}\n rows={2}\n maxLength={1000}\n className=\"mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n </section>\n )}\n\n <section\n data-tour=\"conversation-participants\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {isDirectMessage\n ? tr(\"conversations.recipient\", \"Recipient\")\n : tr(\"conversations.participants\", \"Participants\")}\n {requiresParticipants ? (\n <span className=\"ml-1 text-status-error-text\">*</span>\n ) : (\n <span className=\"ml-1.5 text-xs font-normal text-text-secondary\">\n ({tr(\"conversations.optional\", \"optional\")})\n </span>\n )}\n </h3>\n\n <MemberPicker\n selected={selectedMembers}\n onAdd={addMember}\n onRemove={removeMember}\n single={isDirectMessage}\n excludeIds={excludeIds}\n />\n </section>\n\n {error && !isQuotaExhaustedError(error) && (\n <div className=\"text-xs text-status-error-text rounded-lg border border-status-error-border/30 bg-status-error-bg/10 px-3 py-2\">\n {getErrorMessage(error)}\n </div>\n )}\n </div>\n\n <DialogFooter>\n <button\n type=\"button\"\n onClick={() => handleOpenChange(false)}\n className=\"px-4 py-2 text-sm font-medium rounded-lg text-text-secondary hover:text-text-primary hover:bg-bg-sunken/50 transition-colors\"\n >\n {tr(\"conversations.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleCreate()}\n disabled={!canCreate || loading}\n className={cn(\n \"inline-flex items-center gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-all\",\n canCreate && !loading\n ? \"bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90 shadow-sm\"\n : \"bg-bg-sunken text-text-secondary cursor-not-allowed\",\n )}\n >\n {loading\n ? tr(\"conversations.creating\", \"Creating...\")\n : tr(\"conversations.createConversation\", \"Create Conversation\")}\n </button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <QuotaExhaustedDialog\n open={showQuotaExhausted}\n title={tr(\n \"conversations.quota.conversations.title\",\n \"Conversation Quota Reached\",\n )}\n description={tr(\n \"conversations.quota.conversations.description\",\n \"You've reached the conversation limit for your current plan. View billing to upgrade or add more capacity.\",\n )}\n onClose={handleQuotaDialogClose}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate(\"/billing\");\n }}\n />\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NewConversationDialog.js","names":[],"sources":["../../../src/conversations/components/NewConversationDialog.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from \"react\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport { isQuotaExhaustedError } from \"@burdenoff/fe-libs/shared/utils\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"@burdenoff/fe-libs/ui\";\nimport {\n Globe,\n Hash,\n Lock,\n Megaphone,\n MessageCircle,\n Shield,\n Users,\n} from \"lucide-react\";\nimport { useNavigate } from \"react-router\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\nimport {\n useCreateConversation,\n useStartDirectConversation,\n type WorkspaceDirectoryMember,\n} from \"../hooks/useConversationQueries\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport { MemberPicker } from \"./MemberPicker\";\nimport { QuotaExhaustedDialog } from \"./QuotaExhaustedDialog\";\nimport type { ConversationType, ConversationVisibility } from \"../types\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\n\n/** Extract the first meaningful GraphQL error message from an ApolloError. */\nfunction getErrorMessage(error: Error): string {\n if (\"graphQLErrors\" in error) {\n const gqlErrors = (error as { graphQLErrors?: Array<{ message?: string }> })\n .graphQLErrors;\n if (gqlErrors && gqlErrors.length > 0 && gqlErrors[0]?.message) {\n return gqlErrors[0].message;\n }\n }\n return error.message;\n}\n\ninterface ConversationTypeOption {\n type: ConversationType;\n label: string;\n description: string;\n icon: React.ReactNode;\n}\n\nexport interface NewConversationDialogProps {\n /** Whether the dialog is open. */\n open: boolean;\n /** Open-state change handler. Fires with `false` on close (overlay click,\n * Escape, X button, Cancel). */\n onOpenChange: (open: boolean) => void;\n /**\n * Optional quota-failure hook for route wrappers that need to close the\n * create modal without running their normal close navigation.\n */\n onQuotaExhausted?: () => void;\n /** Called when the quota dialog is dismissed without opening billing. */\n onQuotaDialogClose?: () => void;\n /**\n * Called after a conversation is successfully created. Receives the new\n * conversation id so the parent can navigate to the detail route.\n * The dialog also closes itself (via `onOpenChange(false)`) before this\n * fires, so the parent does not need to close the dialog manually.\n */\n onCreated?: (conversationId: string) => void;\n}\n\n/**\n * NewConversationDialog — modal form for creating a new conversation.\n *\n * Renders inside the canonical `<Dialog>` primitive from\n * `@burdenoff/fe-libs/ui` so it inherits theme tokens, focus management,\n * and overlay behaviour from the shell.\n *\n * Form state is owned locally; on successful submit the dialog clears\n * state, closes itself, and invokes `onCreated` with the new\n * conversation id.\n */\nexport function NewConversationDialog({\n open,\n onOpenChange,\n onQuotaExhausted,\n onQuotaDialogClose,\n onCreated,\n}: NewConversationDialogProps) {\n const {\n createConversation,\n loading,\n error: createError,\n } = useCreateConversation();\n const {\n startDirectConversation,\n loading: startDirectLoading,\n error: startDirectError,\n } = useStartDirectConversation();\n const { currentUser } = useConversations();\n const bus = useEventBus();\n const tr = useTr();\n const navigate = useNavigate();\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n\n const CONVERSATION_TYPES: ConversationTypeOption[] = useMemo(\n () => [\n {\n type: \"DIRECT\" as ConversationType,\n label: tr(\"conversations.directMessage\", \"Direct Message\"),\n description: tr(\n \"conversations.directMessageDescription\",\n \"One-on-one private conversation\",\n ),\n icon: <MessageCircle size={20} />,\n },\n {\n type: \"GROUP\" as ConversationType,\n label: tr(\"conversations.groupChat\", \"Group Chat\"),\n description: tr(\n \"conversations.groupChatDescription\",\n \"Invite multiple people to a group conversation\",\n ),\n icon: <Users size={20} />,\n },\n {\n type: \"CHANNEL\" as ConversationType,\n label: tr(\"conversations.channel\", \"Channel\"),\n description: tr(\n \"conversations.channelDescription\",\n \"A topic-based channel that anyone can join\",\n ),\n icon: <Hash size={20} />,\n },\n {\n type: \"ANNOUNCEMENT\" as ConversationType,\n label: tr(\"conversations.announcement\", \"Announcement\"),\n description: tr(\n \"conversations.announcementDescription\",\n \"Broadcast messages to a large audience\",\n ),\n icon: <Megaphone size={20} />,\n },\n ],\n [tr],\n );\n\n const VISIBILITY_OPTIONS: Array<{\n value: ConversationVisibility;\n label: string;\n description: string;\n icon: React.ReactNode;\n }> = useMemo(\n () => [\n {\n value: \"PUBLIC\" as ConversationVisibility,\n label: tr(\"conversations.public\", \"Public\"),\n description: tr(\n \"conversations.publicDescription\",\n \"Anyone in the workspace can discover and join\",\n ),\n icon: <Globe size={16} />,\n },\n {\n value: \"PRIVATE\" as ConversationVisibility,\n label: tr(\"conversations.private\", \"Private\"),\n description: tr(\n \"conversations.privateDescription\",\n \"Only invited members can access\",\n ),\n icon: <Lock size={16} />,\n },\n {\n value: \"PROTECTED\" as ConversationVisibility,\n label: tr(\"conversations.protected\", \"Protected\"),\n description: tr(\n \"conversations.protectedDescription\",\n \"Discoverable but requires approval to join\",\n ),\n icon: <Shield size={16} />,\n },\n ],\n [tr],\n );\n\n const [selectedType, setSelectedType] = useState<ConversationType>(\"GROUP\");\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [visibility, setVisibility] =\n useState<ConversationVisibility>(\"PRIVATE\");\n const [selectedMembers, setSelectedMembers] = useState<\n WorkspaceDirectoryMember[]\n >([]);\n\n const isDirectMessage = selectedType === \"DIRECT\";\n const needsTitle = !isDirectMessage;\n\n // The error banner shows whichever hook ran last (createConversation for\n // non-direct types, startDirectConversation for DMs). For DMs\n // createConversation is never called, so its error is always null there.\n const error = isDirectMessage ? startDirectError : createError;\n const isSubmitting = isDirectMessage ? startDirectLoading : loading;\n\n const participantIds = useMemo(\n () => selectedMembers.map((member) => member.id),\n [selectedMembers],\n );\n\n const resetForm = useCallback(() => {\n setSelectedType(\"GROUP\");\n setTitle(\"\");\n setDescription(\"\");\n setVisibility(\"PRIVATE\");\n setSelectedMembers([]);\n }, []);\n\n const addMember = useCallback(\n (member: WorkspaceDirectoryMember) => {\n setSelectedMembers((prev) => {\n if (prev.some((existing) => existing.id === member.id)) return prev;\n // A direct message has exactly one recipient.\n return isDirectMessage ? [member] : [...prev, member];\n });\n },\n [isDirectMessage],\n );\n\n const removeMember = useCallback((userId: string) => {\n setSelectedMembers((prev) => prev.filter((member) => member.id !== userId));\n }, []);\n\n const requiresParticipants =\n selectedType === \"DIRECT\" || selectedType === \"GROUP\";\n\n // Never offer the current user as a participant — they are added implicitly\n // as the conversation creator.\n const excludeIds = useMemo(\n () => (currentUser?.id ? [currentUser.id] : []),\n [currentUser?.id],\n );\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean) => {\n if (!nextOpen) {\n resetForm();\n }\n onOpenChange(nextOpen);\n },\n [onOpenChange, resetForm],\n );\n\n const handleCreate = useCallback(async () => {\n if (requiresParticipants && participantIds.length === 0) return;\n if (needsTitle && !title.trim()) return;\n\n nativeImpact(\"light\");\n try {\n // Direct messages MUST go through getOrCreateDirectConversation so\n // repeated clicks for the same pair reuse the existing thread (the\n // createConversation mutation always mints a new row, which produced\n // duplicate DMs in the inbox — BOFF-8227). For other types the\n // mutation is fine.\n const conversation = isDirectMessage\n ? await startDirectConversation(participantIds[0])\n : await createConversation({\n type: selectedType,\n title: needsTitle ? title.trim() : undefined,\n description: description.trim() || undefined,\n participantIds,\n visibility,\n });\n\n if (!conversation) {\n nativeNotify(\"error\");\n return;\n }\n nativeNotify(\"success\");\n bus.emit(\"conversations.conversation.created\", {\n conversationId: conversation.id,\n conversationType: selectedType,\n source: \"new-conversation-dialog\",\n });\n resetForm();\n onOpenChange(false);\n onCreated?.(conversation.id);\n } catch (error) {\n if (isQuotaExhaustedError(error)) {\n resetForm();\n setShowQuotaExhausted(true);\n if (onQuotaExhausted) {\n onQuotaExhausted();\n } else {\n onOpenChange(false);\n }\n return;\n }\n nativeNotify(\"error\");\n throw error;\n }\n }, [\n bus,\n requiresParticipants,\n participantIds,\n needsTitle,\n title,\n createConversation,\n startDirectConversation,\n selectedType,\n description,\n visibility,\n resetForm,\n onOpenChange,\n onQuotaExhausted,\n onCreated,\n isDirectMessage,\n ]);\n\n const handleQuotaDialogClose = useCallback(() => {\n setShowQuotaExhausted(false);\n onQuotaDialogClose?.();\n }, [onQuotaDialogClose]);\n\n const canCreate =\n (!requiresParticipants || participantIds.length > 0) &&\n (!needsTitle || title.trim().length > 0);\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleOpenChange}>\n <DialogContent\n className=\"sm:max-w-[640px] max-h-[90vh] overflow-y-auto\"\n data-tour=\"new-conversation-dialog\"\n >\n <DialogHeader>\n <DialogTitle>\n {tr(\"conversations.newConversation\", \"New Conversation\")}\n </DialogTitle>\n <DialogDescription>\n {tr(\n \"conversations.newConversationSubtitle\",\n \"Start a new conversation with your team\",\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-6\">\n <section\n data-tour=\"conversation-type-selector\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr(\"conversations.conversationType\", \"Conversation Type\")}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n {CONVERSATION_TYPES.map((option) => (\n <button\n key={option.type}\n type=\"button\"\n onClick={() => {\n setSelectedType(option.type);\n if (option.type === \"DIRECT\") {\n setSelectedMembers((prev) => prev.slice(0, 1));\n }\n }}\n className={cn(\n \"flex items-start gap-3 p-4 rounded-xl border text-left transition-all duration-150\",\n selectedType === option.type\n ? \"border-primary bg-action-primary-bg/5 ring-1 ring-primary/20\"\n : \"border-border-subtle hover:border-muted-foreground/30 hover:bg-bg-sunken/30\",\n )}\n >\n <div\n className={cn(\n \"p-2 rounded-lg\",\n selectedType === option.type\n ? \"bg-action-primary-bg/10 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n )}\n >\n {option.icon}\n </div>\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {option.label}\n </p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {option.description}\n </p>\n </div>\n </button>\n ))}\n </div>\n </section>\n\n {!isDirectMessage && (\n <section\n data-tour=\"conversation-visibility-selector\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr(\"conversations.visibility\", \"Visibility\")}\n </h3>\n <div className=\"flex gap-2 flex-wrap\">\n {VISIBILITY_OPTIONS.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setVisibility(option.value)}\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm transition-all\",\n visibility === option.value\n ? \"border-primary bg-action-primary-bg/5 text-primary font-medium\"\n : \"border-border-subtle text-text-secondary hover:text-text-primary hover:bg-bg-sunken/30\",\n )}\n >\n {option.icon}\n {option.label}\n </button>\n ))}\n </div>\n <p className=\"text-xs text-text-secondary\">\n {\n VISIBILITY_OPTIONS.find(\n (option) => option.value === visibility,\n )?.description\n }\n </p>\n </section>\n )}\n\n {needsTitle && (\n <section\n data-tour=\"conversation-create-details\"\n className=\"space-y-3\"\n >\n <div>\n <label\n htmlFor=\"conv-title\"\n className=\"text-sm font-semibold text-text-primary\"\n >\n {tr(\"conversations.name\", \"Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"conv-title\"\n type=\"text\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder={\n selectedType === \"CHANNEL\"\n ? tr(\n \"conversations.channelNamePlaceholder\",\n \"e.g., engineering-general\",\n )\n : tr(\n \"conversations.conversationNamePlaceholder\",\n \"e.g., Product Launch Q1\",\n )\n }\n maxLength={200}\n className=\"mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <div>\n <label\n htmlFor=\"conv-desc\"\n className=\"text-sm font-semibold text-text-primary\"\n >\n {tr(\"conversations.description\", \"Description\")}\n </label>\n <textarea\n id=\"conv-desc\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder={tr(\n \"conversations.descriptionPlaceholder\",\n \"What is this conversation about?\",\n )}\n rows={2}\n maxLength={1000}\n className=\"mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border-subtle bg-bg-surface placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n </section>\n )}\n\n <section\n data-tour=\"conversation-participants\"\n className=\"space-y-3\"\n >\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {isDirectMessage\n ? tr(\"conversations.recipient\", \"Recipient\")\n : tr(\"conversations.participants\", \"Participants\")}\n {requiresParticipants ? (\n <span className=\"ml-1 text-status-error-text\">*</span>\n ) : (\n <span className=\"ml-1.5 text-xs font-normal text-text-secondary\">\n ({tr(\"conversations.optional\", \"optional\")})\n </span>\n )}\n </h3>\n\n <MemberPicker\n selected={selectedMembers}\n onAdd={addMember}\n onRemove={removeMember}\n single={isDirectMessage}\n excludeIds={excludeIds}\n />\n </section>\n\n {error && !isQuotaExhaustedError(error) && (\n <div className=\"text-xs text-status-error-text rounded-lg border border-status-error-border/30 bg-status-error-bg/10 px-3 py-2\">\n {getErrorMessage(error)}\n </div>\n )}\n </div>\n\n <DialogFooter>\n <button\n type=\"button\"\n onClick={() => handleOpenChange(false)}\n className=\"px-4 py-2 text-sm font-medium rounded-lg text-text-secondary hover:text-text-primary hover:bg-bg-sunken/50 transition-colors\"\n >\n {tr(\"conversations.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleCreate()}\n disabled={!canCreate || isSubmitting}\n className={cn(\n \"inline-flex items-center gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-all\",\n canCreate && !isSubmitting\n ? \"bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90 shadow-sm\"\n : \"bg-bg-sunken text-text-secondary cursor-not-allowed\",\n )}\n >\n {isSubmitting\n ? tr(\"conversations.creating\", \"Creating...\")\n : tr(\"conversations.createConversation\", \"Create Conversation\")}\n </button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <QuotaExhaustedDialog\n open={showQuotaExhausted}\n title={tr(\n \"conversations.quota.conversations.title\",\n \"Conversation Quota Reached\",\n )}\n description={tr(\n \"conversations.quota.conversations.description\",\n \"You've reached the conversation limit for your current plan. View billing to upgrade or add more capacity.\",\n )}\n onClose={handleQuotaDialogClose}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate(\"/billing\");\n }}\n />\n </>\n );\n}\n"],"mappings":"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"}