@burdenoff/microfe-conversations 2026.527.2 → 2026.528.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/conversations/ConversationsRoot.js +1 -1
- package/dist/conversations/ConversationsRoot.js.map +1 -1
- package/dist/conversations/ConversationsUserRoot.js +1 -1
- package/dist/conversations/ConversationsUserRoot.js.map +1 -1
- package/dist/conversations/ConversationsUserRoutes.js +6 -6
- package/dist/conversations/ConversationsUserRoutes.js.map +1 -1
- package/dist/conversations/components/ConversationRow.js +176 -0
- package/dist/conversations/components/ConversationRow.js.map +1 -0
- package/dist/conversations/components/EmptyState.js +10 -21
- package/dist/conversations/components/EmptyState.js.map +1 -1
- package/dist/conversations/components/InboxLayout.js +189 -0
- package/dist/conversations/components/InboxLayout.js.map +1 -0
- package/dist/conversations/components/NewConversationDialog.js +285 -0
- package/dist/conversations/components/NewConversationDialog.js.map +1 -0
- package/dist/conversations/components/PageLayout.js +16 -34
- package/dist/conversations/components/PageLayout.js.map +1 -1
- package/dist/conversations/components/PageSection.js +10 -19
- package/dist/conversations/components/PageSection.js.map +1 -1
- package/dist/conversations/hooks/useConversationQueries.js +48 -34
- package/dist/conversations/hooks/useConversationQueries.js.map +1 -1
- package/dist/conversations/pages/ConversationListPage.js +187 -226
- package/dist/conversations/pages/ConversationListPage.js.map +1 -1
- package/dist/conversations/pages/ConversationsLandingPage.js +109 -99
- package/dist/conversations/pages/ConversationsLandingPage.js.map +1 -1
- package/dist/conversations/pages/ConversationsSettingsPage.js +201 -182
- package/dist/conversations/pages/ConversationsSettingsPage.js.map +1 -1
- package/dist/conversations/pages/NewConversationPage.js +19 -280
- package/dist/conversations/pages/NewConversationPage.js.map +1 -1
- package/dist/generated/wspace-operations.js +72 -56
- package/dist/generated/wspace-operations.js.map +1 -1
- package/package.json +2 -2
- package/dist/conversations/components/ConversationCard.js +0 -119
- package/dist/conversations/components/ConversationCard.js.map +0 -1
|
@@ -1,290 +1,29 @@
|
|
|
1
1
|
import { useConversations as e } from "../providers/ConversationsProvider.js";
|
|
2
2
|
import { joinPath as t } from "../utils/navigation.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { nativeImpact as c, nativeNotify as l } from "../../utils/nativeBridge.js";
|
|
10
|
-
import { useCallback as u, useMemo as d, useState as f } from "react";
|
|
11
|
-
import { ArrowLeft as p, Globe as m, Hash as h, Lock as g, Megaphone as _, MessageCircle as v, Plus as ee, Shield as y, Users as b, X as x } from "lucide-react";
|
|
12
|
-
import { useNavigate as S } from "react-router-dom";
|
|
13
|
-
import { useEventBus as C } from "@burdenoff/fe-libs/shared/events";
|
|
14
|
-
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
3
|
+
import { PermissionGuard as n } from "../components/PermissionGuard.js";
|
|
4
|
+
import { CONVERSATIONS_PERMISSIONS as r } from "../constants/permissions.js";
|
|
5
|
+
import { NewConversationDialog as i } from "../components/NewConversationDialog.js";
|
|
6
|
+
import { useCallback as a } from "react";
|
|
7
|
+
import { useNavigate as o } from "react-router-dom";
|
|
8
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
15
9
|
//#region src/conversations/pages/NewConversationPage.tsx
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let D = S(), { basePath: O } = e(), { createConversation: k, loading: A, error: j } = a(), M = C(), N = n(), P = d(() => [
|
|
25
|
-
{
|
|
26
|
-
type: "DIRECT",
|
|
27
|
-
label: N("conversations.directMessage", "Direct Message"),
|
|
28
|
-
description: N("conversations.directMessageDescription", "One-on-one private conversation"),
|
|
29
|
-
icon: /* @__PURE__ */ w(v, { size: 20 })
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
type: "GROUP",
|
|
33
|
-
label: N("conversations.groupChat", "Group Chat"),
|
|
34
|
-
description: N("conversations.groupChatDescription", "Invite multiple people to a group conversation"),
|
|
35
|
-
icon: /* @__PURE__ */ w(b, { size: 20 })
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
type: "CHANNEL",
|
|
39
|
-
label: N("conversations.channel", "Channel"),
|
|
40
|
-
description: N("conversations.channelDescription", "A topic-based channel that anyone can join"),
|
|
41
|
-
icon: /* @__PURE__ */ w(h, { size: 20 })
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
type: "ANNOUNCEMENT",
|
|
45
|
-
label: N("conversations.announcement", "Announcement"),
|
|
46
|
-
description: N("conversations.announcementDescription", "Broadcast messages to a large audience"),
|
|
47
|
-
icon: /* @__PURE__ */ w(_, { size: 20 })
|
|
48
|
-
}
|
|
49
|
-
], [N]), F = d(() => [
|
|
50
|
-
{
|
|
51
|
-
value: "PUBLIC",
|
|
52
|
-
label: N("conversations.public", "Public"),
|
|
53
|
-
description: N("conversations.publicDescription", "Anyone in the workspace can discover and join"),
|
|
54
|
-
icon: /* @__PURE__ */ w(m, { size: 16 })
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
value: "PRIVATE",
|
|
58
|
-
label: N("conversations.private", "Private"),
|
|
59
|
-
description: N("conversations.privateDescription", "Only invited members can access"),
|
|
60
|
-
icon: /* @__PURE__ */ w(g, { size: 16 })
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
value: "PROTECTED",
|
|
64
|
-
label: N("conversations.protected", "Protected"),
|
|
65
|
-
description: N("conversations.protectedDescription", "Discoverable but requires approval to join"),
|
|
66
|
-
icon: /* @__PURE__ */ w(y, { size: 16 })
|
|
67
|
-
}
|
|
68
|
-
], [N]), [I, L] = f("GROUP"), [R, z] = f(""), [B, V] = f(""), [H, U] = f("PRIVATE"), [W, G] = f(""), [K, q] = f([]), J = I === "DIRECT", Y = !J, X = u(() => {
|
|
69
|
-
let e = W.trim();
|
|
70
|
-
!e || K.includes(e) || (q(J ? [e] : (t) => [...t, e]), G(""));
|
|
71
|
-
}, [
|
|
72
|
-
W,
|
|
73
|
-
K,
|
|
74
|
-
J
|
|
75
|
-
]), Z = u((e) => {
|
|
76
|
-
q((t) => t.filter((t) => t !== e));
|
|
77
|
-
}, []), Q = I === "DIRECT" || I === "GROUP", te = u(async () => {
|
|
78
|
-
if (!(Q && K.length === 0) && !(Y && !R.trim())) {
|
|
79
|
-
c("light");
|
|
80
|
-
try {
|
|
81
|
-
let e = await k({
|
|
82
|
-
type: I,
|
|
83
|
-
title: Y ? R.trim() : void 0,
|
|
84
|
-
description: B.trim() || void 0,
|
|
85
|
-
participantIds: K,
|
|
86
|
-
visibility: H
|
|
87
|
-
});
|
|
88
|
-
if (!e) {
|
|
89
|
-
l("error");
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
l("success"), M.emit("conversations.conversation.created", {
|
|
93
|
-
conversationId: e.id,
|
|
94
|
-
conversationType: I,
|
|
95
|
-
source: "new-conversation-page"
|
|
96
|
-
}), D(t(O || "/conversations", e.id));
|
|
97
|
-
} catch (e) {
|
|
98
|
-
throw l("error"), e;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}, [
|
|
102
|
-
O,
|
|
103
|
-
M,
|
|
104
|
-
Q,
|
|
105
|
-
K,
|
|
106
|
-
Y,
|
|
107
|
-
R,
|
|
108
|
-
k,
|
|
109
|
-
I,
|
|
110
|
-
B,
|
|
111
|
-
H,
|
|
112
|
-
D
|
|
113
|
-
]), $ = (!Q || K.length > 0) && (!Y || R.trim().length > 0);
|
|
114
|
-
return /* @__PURE__ */ w(o, {
|
|
115
|
-
permission: s.CONVERSATION_CREATE,
|
|
10
|
+
function c() {
|
|
11
|
+
let c = o(), { basePath: l } = e(), u = l || "/conversations", d = a((e) => {
|
|
12
|
+
e || c(`${u}?new=true`, { replace: !0 });
|
|
13
|
+
}, [c, u]), f = a((e) => {
|
|
14
|
+
c(t(u, e));
|
|
15
|
+
}, [c, u]);
|
|
16
|
+
return /* @__PURE__ */ s(n, {
|
|
17
|
+
permission: r.CONVERSATION_CREATE,
|
|
116
18
|
allowUnavailablePermissions: !0,
|
|
117
|
-
children: /* @__PURE__ */
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
maxWidth: "lg",
|
|
122
|
-
headerActions: /* @__PURE__ */ T("button", {
|
|
123
|
-
type: "button",
|
|
124
|
-
onClick: () => D(O || "/conversations"),
|
|
125
|
-
className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
|
|
126
|
-
children: [/* @__PURE__ */ w(p, { size: 16 }), N("conversations.back", "Back")]
|
|
127
|
-
}),
|
|
128
|
-
children: [
|
|
129
|
-
/* @__PURE__ */ T("section", {
|
|
130
|
-
"data-tour": "conversation-type-selector",
|
|
131
|
-
className: "space-y-3",
|
|
132
|
-
children: [/* @__PURE__ */ w("h3", {
|
|
133
|
-
className: "text-sm font-semibold text-foreground",
|
|
134
|
-
children: N("conversations.conversationType", "Conversation Type")
|
|
135
|
-
}), /* @__PURE__ */ w("div", {
|
|
136
|
-
className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
|
|
137
|
-
children: P.map((e) => /* @__PURE__ */ T("button", {
|
|
138
|
-
type: "button",
|
|
139
|
-
onClick: () => {
|
|
140
|
-
L(e.type), e.type === "DIRECT" && q((e) => e.slice(0, 1));
|
|
141
|
-
},
|
|
142
|
-
className: r("flex items-start gap-3 p-4 rounded-xl border text-left transition-all duration-150", I === e.type ? "border-primary bg-primary/5 ring-1 ring-primary/20" : "border-border hover:border-muted-foreground/30 hover:bg-muted/30"),
|
|
143
|
-
children: [/* @__PURE__ */ w("div", {
|
|
144
|
-
className: r("p-2 rounded-lg", I === e.type ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"),
|
|
145
|
-
children: e.icon
|
|
146
|
-
}), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
147
|
-
className: "text-sm font-medium text-foreground",
|
|
148
|
-
children: e.label
|
|
149
|
-
}), /* @__PURE__ */ w("p", {
|
|
150
|
-
className: "text-xs text-muted-foreground mt-0.5",
|
|
151
|
-
children: e.description
|
|
152
|
-
})] })]
|
|
153
|
-
}, e.type))
|
|
154
|
-
})]
|
|
155
|
-
}),
|
|
156
|
-
!J && /* @__PURE__ */ T("section", {
|
|
157
|
-
"data-tour": "conversation-visibility-selector",
|
|
158
|
-
className: "space-y-3",
|
|
159
|
-
children: [
|
|
160
|
-
/* @__PURE__ */ w("h3", {
|
|
161
|
-
className: "text-sm font-semibold text-foreground",
|
|
162
|
-
children: N("conversations.visibility", "Visibility")
|
|
163
|
-
}),
|
|
164
|
-
/* @__PURE__ */ w("div", {
|
|
165
|
-
className: "flex gap-2",
|
|
166
|
-
children: F.map((e) => /* @__PURE__ */ T("button", {
|
|
167
|
-
type: "button",
|
|
168
|
-
onClick: () => U(e.value),
|
|
169
|
-
className: r("flex items-center gap-2 px-4 py-2.5 rounded-lg border text-sm transition-all", H === e.value ? "border-primary bg-primary/5 text-primary font-medium" : "border-border text-muted-foreground hover:text-foreground hover:bg-muted/30"),
|
|
170
|
-
children: [e.icon, e.label]
|
|
171
|
-
}, e.value))
|
|
172
|
-
}),
|
|
173
|
-
/* @__PURE__ */ w("p", {
|
|
174
|
-
className: "text-xs text-muted-foreground",
|
|
175
|
-
children: F.find((e) => e.value === H)?.description
|
|
176
|
-
})
|
|
177
|
-
]
|
|
178
|
-
}),
|
|
179
|
-
Y && /* @__PURE__ */ T("section", {
|
|
180
|
-
"data-tour": "conversation-create-details",
|
|
181
|
-
className: "space-y-3",
|
|
182
|
-
children: [/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ T("label", {
|
|
183
|
-
htmlFor: "conv-title",
|
|
184
|
-
className: "text-sm font-semibold text-foreground",
|
|
185
|
-
children: [
|
|
186
|
-
N("conversations.name", "Name"),
|
|
187
|
-
" ",
|
|
188
|
-
/* @__PURE__ */ w("span", {
|
|
189
|
-
className: "text-destructive",
|
|
190
|
-
children: "*"
|
|
191
|
-
})
|
|
192
|
-
]
|
|
193
|
-
}), /* @__PURE__ */ w("input", {
|
|
194
|
-
id: "conv-title",
|
|
195
|
-
type: "text",
|
|
196
|
-
value: R,
|
|
197
|
-
onChange: (e) => z(e.target.value),
|
|
198
|
-
placeholder: I === "CHANNEL" ? N("conversations.channelNamePlaceholder", "e.g., engineering-general") : N("conversations.conversationNamePlaceholder", "e.g., Product Launch Q1"),
|
|
199
|
-
maxLength: 200,
|
|
200
|
-
className: "mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
201
|
-
})] }), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
|
|
202
|
-
htmlFor: "conv-desc",
|
|
203
|
-
className: "text-sm font-semibold text-foreground",
|
|
204
|
-
children: N("conversations.description", "Description")
|
|
205
|
-
}), /* @__PURE__ */ w("textarea", {
|
|
206
|
-
id: "conv-desc",
|
|
207
|
-
value: B,
|
|
208
|
-
onChange: (e) => V(e.target.value),
|
|
209
|
-
placeholder: N("conversations.descriptionPlaceholder", "What is this conversation about?"),
|
|
210
|
-
rows: 2,
|
|
211
|
-
maxLength: 1e3,
|
|
212
|
-
className: "mt-1.5 w-full px-3 py-2 text-sm rounded-lg border border-border bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring resize-none"
|
|
213
|
-
})] })]
|
|
214
|
-
}),
|
|
215
|
-
/* @__PURE__ */ T("section", {
|
|
216
|
-
"data-tour": "conversation-participants",
|
|
217
|
-
className: "space-y-3",
|
|
218
|
-
children: [
|
|
219
|
-
/* @__PURE__ */ T("h3", {
|
|
220
|
-
className: "text-sm font-semibold text-foreground",
|
|
221
|
-
children: [J ? N("conversations.participantId", "Participant ID") : N("conversations.participantIds", "Participant IDs"), !Q && /* @__PURE__ */ T("span", {
|
|
222
|
-
className: "ml-1.5 text-xs font-normal text-muted-foreground",
|
|
223
|
-
children: [
|
|
224
|
-
"(",
|
|
225
|
-
N("conversations.optional", "optional"),
|
|
226
|
-
")"
|
|
227
|
-
]
|
|
228
|
-
})]
|
|
229
|
-
}),
|
|
230
|
-
K.length > 0 && /* @__PURE__ */ w("div", {
|
|
231
|
-
className: "flex flex-wrap gap-2",
|
|
232
|
-
children: K.map((e) => /* @__PURE__ */ T("span", {
|
|
233
|
-
className: "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-primary/10 text-primary text-xs font-medium",
|
|
234
|
-
children: [e, /* @__PURE__ */ w("button", {
|
|
235
|
-
type: "button",
|
|
236
|
-
"aria-label": N("conversations.removeParticipant", "Remove participant"),
|
|
237
|
-
onClick: () => Z(e),
|
|
238
|
-
className: "p-0.5 rounded-full hover:bg-primary/20",
|
|
239
|
-
children: /* @__PURE__ */ w(x, { size: 12 })
|
|
240
|
-
})]
|
|
241
|
-
}, e))
|
|
242
|
-
}),
|
|
243
|
-
/* @__PURE__ */ T("div", {
|
|
244
|
-
className: "flex items-center gap-2",
|
|
245
|
-
children: [/* @__PURE__ */ w("input", {
|
|
246
|
-
type: "text",
|
|
247
|
-
"aria-label": N("conversations.participantInputLabel", "Add participant"),
|
|
248
|
-
value: W,
|
|
249
|
-
onChange: (e) => G(e.target.value),
|
|
250
|
-
onKeyDown: (e) => {
|
|
251
|
-
e.key === "Enter" && (e.preventDefault(), X());
|
|
252
|
-
},
|
|
253
|
-
placeholder: N("conversations.participantInputPlaceholder", "Enter user ID and press Enter"),
|
|
254
|
-
className: "w-full px-3 py-2 text-sm rounded-lg border border-border bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
255
|
-
}), /* @__PURE__ */ w("button", {
|
|
256
|
-
type: "button",
|
|
257
|
-
onClick: X,
|
|
258
|
-
className: "px-3 py-2 text-sm rounded-lg border border-border hover:bg-muted/50",
|
|
259
|
-
children: N("conversations.add", "Add")
|
|
260
|
-
})]
|
|
261
|
-
})
|
|
262
|
-
]
|
|
263
|
-
}),
|
|
264
|
-
j && /* @__PURE__ */ w("div", {
|
|
265
|
-
className: "text-xs text-destructive rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2",
|
|
266
|
-
children: E(j)
|
|
267
|
-
}),
|
|
268
|
-
/* @__PURE__ */ T("div", {
|
|
269
|
-
className: "flex justify-end gap-3 pt-4 border-t border-border",
|
|
270
|
-
children: [/* @__PURE__ */ w("button", {
|
|
271
|
-
type: "button",
|
|
272
|
-
onClick: () => D(".."),
|
|
273
|
-
className: "px-4 py-2 text-sm font-medium rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
|
|
274
|
-
children: N("conversations.cancel", "Cancel")
|
|
275
|
-
}), /* @__PURE__ */ w("button", {
|
|
276
|
-
type: "button",
|
|
277
|
-
onClick: () => void te(),
|
|
278
|
-
disabled: !$ || A,
|
|
279
|
-
className: r("inline-flex items-center gap-2 px-5 py-2 text-sm font-medium rounded-lg transition-all", $ && !A ? "bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm" : "bg-muted text-muted-foreground cursor-not-allowed"),
|
|
280
|
-
children: A ? N("conversations.creating", "Creating...") : N("conversations.createConversation", "Create Conversation")
|
|
281
|
-
})]
|
|
282
|
-
})
|
|
283
|
-
]
|
|
19
|
+
children: /* @__PURE__ */ s(i, {
|
|
20
|
+
open: !0,
|
|
21
|
+
onOpenChange: d,
|
|
22
|
+
onCreated: f
|
|
284
23
|
})
|
|
285
24
|
});
|
|
286
25
|
}
|
|
287
26
|
//#endregion
|
|
288
|
-
export {
|
|
27
|
+
export { c as NewConversationPage };
|
|
289
28
|
|
|
290
29
|
//# sourceMappingURL=NewConversationPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NewConversationPage.js","names":[],"sources":["../../../src/conversations/pages/NewConversationPage.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from \"react\";\nimport { useTr } from \"../utils/i18n\";\nimport { useEventBus } from \"@burdenoff/fe-libs/shared/events\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n ArrowLeft,\n Globe,\n Hash,\n Lock,\n Megaphone,\n MessageCircle,\n Plus,\n Shield,\n Users,\n X,\n} from \"lucide-react\";\nimport { cn } from \"../utils/cn\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { useCreateConversation } from \"../hooks/useConversationQueries\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport type { ConversationType, ConversationVisibility } from \"../types\";\nimport { PermissionGuard } from \"../components/PermissionGuard\";\nimport { CONVERSATIONS_PERMISSIONS } from \"../constants/permissions\";\nimport { joinPath } from \"../utils/navigation\";\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 function NewConversationPage() {\n const navigate = useNavigate();\n const { basePath } = useConversations();\n const { createConversation, loading, error } = useCreateConversation();\n const bus = useEventBus();\n const tr = useTr();\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 [participantInput, setParticipantInput] = useState(\"\");\n const [participantIds, setParticipantIds] = useState<string[]>([]);\n\n const isDirectMessage = selectedType === \"DIRECT\";\n const needsTitle = !isDirectMessage;\n\n const addParticipant = useCallback(() => {\n const value = participantInput.trim();\n if (!value || participantIds.includes(value)) return;\n if (isDirectMessage) {\n setParticipantIds([value]);\n } else {\n setParticipantIds((prev) => [...prev, value]);\n }\n setParticipantInput(\"\");\n }, [participantInput, participantIds, isDirectMessage]);\n\n const removeParticipant = useCallback((participantId: string) => {\n setParticipantIds((prev) => prev.filter((id) => id !== participantId));\n }, []);\n\n const requiresParticipants =\n selectedType === \"DIRECT\" || selectedType === \"GROUP\";\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-page\",\n });\n navigate(joinPath(basePath || \"/conversations\", conversation.id));\n } catch (error) {\n nativeNotify(\"error\");\n throw error;\n }\n }, [\n basePath,\n bus,\n requiresParticipants,\n participantIds,\n needsTitle,\n title,\n createConversation,\n selectedType,\n description,\n visibility,\n navigate,\n ]);\n\n const canCreate =\n (!requiresParticipants || participantIds.length > 0) &&\n (!needsTitle || title.trim().length > 0);\n\n return (\n <PermissionGuard\n permission={CONVERSATIONS_PERMISSIONS.CONVERSATION_CREATE}\n allowUnavailablePermissions\n >\n <PageLayout\n title={tr(\"conversations.newConversation\", \"New Conversation\")}\n subtitle={tr(\n \"conversations.newConversationSubtitle\",\n \"Start a new conversation with your team\",\n )}\n icon={<Plus size={24} />}\n maxWidth=\"lg\"\n headerActions={\n <button\n type=\"button\"\n onClick={() => navigate(basePath || \"/conversations\")}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors\"\n >\n <ArrowLeft size={16} />\n {tr(\"conversations.back\", \"Back\")}\n </button>\n }\n >\n <section data-tour=\"conversation-type-selector\" className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-foreground\">\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 setParticipantIds((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-primary/5 ring-1 ring-primary/20\"\n : \"border-border hover:border-muted-foreground/30 hover:bg-muted/30\",\n )}\n >\n <div\n className={cn(\n \"p-2 rounded-lg\",\n selectedType === option.type\n ? \"bg-primary/10 text-primary\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {option.icon}\n </div>\n <div>\n <p className=\"text-sm font-medium text-foreground\">\n {option.label}\n </p>\n <p className=\"text-xs text-muted-foreground 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-foreground\">\n {tr(\"conversations.visibility\", \"Visibility\")}\n </h3>\n <div className=\"flex gap-2\">\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-primary/5 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:text-foreground hover:bg-muted/30\",\n )}\n >\n {option.icon}\n {option.label}\n </button>\n ))}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {\n VISIBILITY_OPTIONS.find((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-foreground\"\n >\n {tr(\"conversations.name\", \"Name\")}{\" \"}\n <span className=\"text-destructive\">*</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 bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div>\n <label\n htmlFor=\"conv-desc\"\n className=\"text-sm font-semibold text-foreground\"\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 bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring resize-none\"\n />\n </div>\n </section>\n )}\n\n <section data-tour=\"conversation-participants\" className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-foreground\">\n {isDirectMessage\n ? tr(\"conversations.participantId\", \"Participant ID\")\n : tr(\"conversations.participantIds\", \"Participant IDs\")}\n {!requiresParticipants && (\n <span className=\"ml-1.5 text-xs font-normal text-muted-foreground\">\n ({tr(\"conversations.optional\", \"optional\")})\n </span>\n )}\n </h3>\n\n {participantIds.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {participantIds.map((participantId) => (\n <span\n key={participantId}\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-primary/10 text-primary text-xs font-medium\"\n >\n {participantId}\n <button\n type=\"button\"\n aria-label={tr(\n \"conversations.removeParticipant\",\n \"Remove participant\",\n )}\n onClick={() => removeParticipant(participantId)}\n className=\"p-0.5 rounded-full hover:bg-primary/20\"\n >\n <X size={12} />\n </button>\n </span>\n ))}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n aria-label={tr(\n \"conversations.participantInputLabel\",\n \"Add participant\",\n )}\n value={participantInput}\n onChange={(event) => setParticipantInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Enter\") return;\n event.preventDefault();\n addParticipant();\n }}\n placeholder={tr(\n \"conversations.participantInputPlaceholder\",\n \"Enter user ID and press Enter\",\n )}\n className=\"w-full px-3 py-2 text-sm rounded-lg border border-border bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n <button\n type=\"button\"\n onClick={addParticipant}\n className=\"px-3 py-2 text-sm rounded-lg border border-border hover:bg-muted/50\"\n >\n {tr(\"conversations.add\", \"Add\")}\n </button>\n </div>\n </section>\n\n {error && (\n <div className=\"text-xs text-destructive rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2\">\n {getErrorMessage(error)}\n </div>\n )}\n\n <div className=\"flex justify-end gap-3 pt-4 border-t border-border\">\n <button\n type=\"button\"\n onClick={() => navigate(\"..\")}\n className=\"px-4 py-2 text-sm font-medium rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/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-primary text-primary-foreground hover:bg-primary/90 shadow-sm\"\n : \"bg-muted text-muted-foreground cursor-not-allowed\",\n )}\n >\n {loading\n ? tr(\"conversations.creating\", \"Creating...\")\n : tr(\"conversations.createConversation\", \"Create Conversation\")}\n </button>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NewConversationPage.js","names":[],"sources":["../../../src/conversations/pages/NewConversationPage.tsx"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { PermissionGuard } from \"../components/PermissionGuard\";\nimport { CONVERSATIONS_PERMISSIONS } from \"../constants/permissions\";\nimport { NewConversationDialog } from \"../components/NewConversationDialog\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport { joinPath } from \"../utils/navigation\";\n\n/**\n * Legacy `/conversations/new` route.\n *\n * The canonical UX is now the in-place `<NewConversationDialog>` opened via\n * the `?new=true` URL param on the landing page — no full-page navigation.\n * This wrapper preserves the old route for any deep links that still exist\n * in the wild: it mounts the dialog as already-open and routes the user\n * back to the inbox (with `?new=true`) on close, so the dialog stays open\n * and they end up in the canonical surface.\n *\n * On successful create the dialog itself navigates to the new conversation\n * detail page via the `onCreated` callback.\n */\nexport function NewConversationPage() {\n const navigate = useNavigate();\n const { basePath } = useConversations();\n const root = basePath || \"/conversations\";\n\n const handleOpenChange = useCallback(\n (open: boolean) => {\n if (open) return;\n // Closing the dialog from the legacy route lands the user on the\n // inbox; we keep `?new=true` so the dialog re-opens in-place there\n // — this mirrors what would have happened had they clicked the\n // primary CTA on the inbox itself.\n navigate(`${root}?new=true`, { replace: true });\n },\n [navigate, root],\n );\n\n const handleCreated = useCallback(\n (conversationId: string) => {\n navigate(joinPath(root, conversationId));\n },\n [navigate, root],\n );\n\n return (\n <PermissionGuard\n permission={CONVERSATIONS_PERMISSIONS.CONVERSATION_CREATE}\n allowUnavailablePermissions\n >\n <NewConversationDialog\n open\n onOpenChange={handleOpenChange}\n onCreated={handleCreated}\n />\n </PermissionGuard>\n );\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,IAAsB;CACpC,IAAM,IAAW,GAAa,EACxB,EAAE,gBAAa,GAAkB,EACjC,IAAO,KAAY,kBAEnB,IAAmB,GACtB,MAAkB;AACb,OAKJ,EAAS,GAAG,EAAK,YAAY,EAAE,SAAS,IAAM,CAAC;IAEjD,CAAC,GAAU,EAAK,CACjB,EAEK,IAAgB,GACnB,MAA2B;AAC1B,IAAS,EAAS,GAAM,EAAe,CAAC;IAE1C,CAAC,GAAU,EAAK,CACjB;AAED,QACE,kBAAC,GAAD;EACE,YAAY,EAA0B;EACtC,6BAAA;YAEA,kBAAC,GAAD;GACE,MAAA;GACA,cAAc;GACd,WAAW;GACX,CAAA;EACc,CAAA"}
|