@burdenoff/microfe-conversations 2026.527.1 → 2026.528.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +185 -0
- package/dist/conversations/components/InboxLayout.js.map +1 -0
- package/dist/conversations/components/LazyPageBoundary.js.map +1 -1
- 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/components/lazyRetry.js.map +1 -1
- package/dist/conversations/hooks/useConversationQueries.js +48 -34
- package/dist/conversations/hooks/useConversationQueries.js.map +1 -1
- package/dist/conversations/hooks/useMessageQueries.js.map +1 -1
- package/dist/conversations/pages/ConversationAdminPages.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 +93 -103
- 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/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,119 +1,109 @@
|
|
|
1
1
|
import { useTr as e } from "../utils/i18n.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { useConversationsStore as t } from "../store/conversationsStore.js";
|
|
3
|
+
import { PermissionGuard as n } from "../components/PermissionGuard.js";
|
|
4
|
+
import { CONVERSATIONS_PERMISSIONS as r } from "../constants/permissions.js";
|
|
5
|
+
import { ConversationListPage as i } from "./ConversationListPage.js";
|
|
6
|
+
import { InboxLayout as a } from "../components/InboxLayout.js";
|
|
7
7
|
import { useUserFeatureFlags as o } from "../hooks/useUserFeatureFlags.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
8
|
+
import { Suspense as s, lazy as c, useCallback as l, useEffect as u, useMemo as d } from "react";
|
|
9
|
+
import { Filter as f, Loader2 as p, Pin as m } from "lucide-react";
|
|
10
|
+
import { useParams as h, useSearchParams as g } from "react-router-dom";
|
|
11
|
+
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
12
|
+
import { PageContainer as y } from "@burdenoff/fe-libs/ui";
|
|
12
13
|
//#region src/conversations/pages/ConversationsLandingPage.tsx
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
className: "text-sm text-muted-foreground",
|
|
25
|
-
children: n("conversations.comingSoon", "Coming soon.")
|
|
26
|
-
})]
|
|
27
|
-
})
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function h() {
|
|
31
|
-
let [h, g] = l(), _ = e(), { archivedEnabled: v } = o(), y = c(() => [
|
|
32
|
-
{
|
|
33
|
-
id: p,
|
|
34
|
-
label: _("conversations.allConversations", "All Conversations")
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: "channels",
|
|
38
|
-
label: _("conversations.channels", "Channels")
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: "direct",
|
|
42
|
-
label: _("conversations.directMessages", "Direct Messages")
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: "groups",
|
|
46
|
-
label: _("conversations.groups", "Groups")
|
|
47
|
-
},
|
|
48
|
-
...v ? [{
|
|
49
|
-
id: "archived",
|
|
50
|
-
label: _("conversations.archived", "Archived")
|
|
51
|
-
}] : [],
|
|
52
|
-
{
|
|
53
|
-
id: "new",
|
|
54
|
-
label: _("conversations.new", "New")
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
id: "settings",
|
|
58
|
-
label: _("conversations.settings", "Settings")
|
|
59
|
-
}
|
|
60
|
-
], [_, v]), b = h.get("tab"), x = b === "archived" && !v ? p : b ?? p;
|
|
61
|
-
return s(() => {
|
|
62
|
-
!v && b === "archived" && g((e) => {
|
|
14
|
+
var b = c(() => import("./ConversationDetailPage.js").then((e) => ({ default: e.ConversationDetailPage }))), x = "all", S = {
|
|
15
|
+
all: void 0,
|
|
16
|
+
direct: "direct",
|
|
17
|
+
groups: "group",
|
|
18
|
+
channels: "channel",
|
|
19
|
+
archived: "archived"
|
|
20
|
+
};
|
|
21
|
+
function C() {
|
|
22
|
+
let [c, C] = g(), { conversationId: w } = h(), T = e(), { archivedEnabled: E } = o(), { searchQuery: D, setSearchQuery: O, conversationFilter: k, updateConversationFilter: A } = t(), j = c.get("tab") ?? x, M = j === "archived" && !E ? x : j;
|
|
23
|
+
u(() => {
|
|
24
|
+
!E && j === "archived" && C((e) => {
|
|
63
25
|
let t = new URLSearchParams(e);
|
|
64
26
|
return t.delete("tab"), t;
|
|
65
27
|
}, { replace: !0 });
|
|
66
28
|
}, [
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
])
|
|
71
|
-
|
|
29
|
+
E,
|
|
30
|
+
j,
|
|
31
|
+
C
|
|
32
|
+
]);
|
|
33
|
+
let N = l((e) => {
|
|
34
|
+
C((t) => {
|
|
35
|
+
let n = new URLSearchParams(t);
|
|
36
|
+
return e === x ? n.delete("tab") : n.set("tab", e), n;
|
|
37
|
+
}, { replace: !0 });
|
|
38
|
+
}, [C]), P = d(() => {
|
|
39
|
+
if (M === "archived") return [];
|
|
40
|
+
let e = k.hasUnread === !0, t = k.isPinned === !0;
|
|
41
|
+
return [{
|
|
42
|
+
id: "unread",
|
|
43
|
+
label: T("conversations.unread", "Unread"),
|
|
44
|
+
active: e,
|
|
45
|
+
onToggle: () => A({ hasUnread: e ? void 0 : !0 }),
|
|
46
|
+
icon: /* @__PURE__ */ _(f, {
|
|
47
|
+
size: 11,
|
|
48
|
+
"aria-hidden": "true"
|
|
49
|
+
})
|
|
50
|
+
}, {
|
|
51
|
+
id: "pinned",
|
|
52
|
+
label: T("conversations.pinned", "Pinned"),
|
|
53
|
+
active: t,
|
|
54
|
+
onToggle: () => A({ isPinned: t ? void 0 : !0 }),
|
|
55
|
+
icon: /* @__PURE__ */ _(m, {
|
|
56
|
+
size: 11,
|
|
57
|
+
"aria-hidden": "true"
|
|
58
|
+
})
|
|
59
|
+
}];
|
|
60
|
+
}, [
|
|
61
|
+
M,
|
|
62
|
+
k.hasUnread,
|
|
63
|
+
k.isPinned,
|
|
64
|
+
T,
|
|
65
|
+
A
|
|
66
|
+
]), F = S[M];
|
|
67
|
+
return /* @__PURE__ */ _(n, {
|
|
68
|
+
permission: r.CONVERSATION_READ,
|
|
72
69
|
allowUnavailablePermissions: !0,
|
|
73
|
-
children: /* @__PURE__ */
|
|
70
|
+
children: /* @__PURE__ */ v(y, {
|
|
74
71
|
"data-tour": "conversations-landing",
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
children: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
padded: !1,
|
|
73
|
+
className: "h-full min-h-0",
|
|
74
|
+
children: [/* @__PURE__ */ _("h1", {
|
|
75
|
+
id: "conversations-page-heading",
|
|
76
|
+
className: "sr-only",
|
|
77
|
+
children: T("conversations.title", "Conversations")
|
|
78
|
+
}), /* @__PURE__ */ _(a, {
|
|
79
|
+
activeTab: M,
|
|
80
|
+
onTabChange: N,
|
|
81
|
+
archivedEnabled: E,
|
|
82
|
+
searchQuery: D,
|
|
83
|
+
onSearchChange: O,
|
|
84
|
+
filterChips: P,
|
|
85
|
+
listSlot: /* @__PURE__ */ _(i, {
|
|
86
|
+
embedded: !0,
|
|
87
|
+
forcedFilterParam: F
|
|
82
88
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}),
|
|
98
|
-
/* @__PURE__ */ d("section", {
|
|
99
|
-
className: "flex-1 min-h-0 overflow-auto",
|
|
100
|
-
"aria-live": "polite",
|
|
101
|
-
"aria-label": _("conversations.activePanel", "Active conversations panel"),
|
|
102
|
-
children: [
|
|
103
|
-
x === "all" && /* @__PURE__ */ u(r, {}),
|
|
104
|
-
x === "channels" && /* @__PURE__ */ u(r, { forcedFilterParam: "channel" }),
|
|
105
|
-
x === "direct" && /* @__PURE__ */ u(r, { forcedFilterParam: "direct" }),
|
|
106
|
-
x === "groups" && /* @__PURE__ */ u(r, { forcedFilterParam: "group" }),
|
|
107
|
-
x === "archived" && /* @__PURE__ */ u(m, { title: _("conversations.archivedTitle", "Archived Conversations") }),
|
|
108
|
-
x === "new" && /* @__PURE__ */ u(i, {}),
|
|
109
|
-
x === "settings" && /* @__PURE__ */ u(a, {})
|
|
110
|
-
]
|
|
111
|
-
})
|
|
112
|
-
]
|
|
89
|
+
detailSlot: w ? /* @__PURE__ */ _(s, {
|
|
90
|
+
fallback: /* @__PURE__ */ v("div", {
|
|
91
|
+
role: "status",
|
|
92
|
+
"aria-live": "polite",
|
|
93
|
+
className: "flex h-full items-center justify-center gap-2 text-sm text-text-secondary",
|
|
94
|
+
children: [/* @__PURE__ */ _(p, {
|
|
95
|
+
size: 16,
|
|
96
|
+
className: "animate-spin",
|
|
97
|
+
"aria-hidden": "true"
|
|
98
|
+
}), T("conversations.detailLoading", "Loading conversation…")]
|
|
99
|
+
}),
|
|
100
|
+
children: /* @__PURE__ */ _(b, {})
|
|
101
|
+
}) : void 0
|
|
102
|
+
})]
|
|
113
103
|
})
|
|
114
104
|
});
|
|
115
105
|
}
|
|
116
106
|
//#endregion
|
|
117
|
-
export {
|
|
107
|
+
export { C as ConversationsLandingPage };
|
|
118
108
|
|
|
119
109
|
//# sourceMappingURL=ConversationsLandingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationsLandingPage.js","names":[],"sources":["../../../src/conversations/pages/ConversationsLandingPage.tsx"],"sourcesContent":["import { useEffect, useMemo } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {
|
|
1
|
+
{"version":3,"file":"ConversationsLandingPage.js","names":[],"sources":["../../../src/conversations/pages/ConversationsLandingPage.tsx"],"sourcesContent":["import { Suspense, useCallback, useEffect, useMemo, lazy } from \"react\";\nimport { useParams, useSearchParams } from \"react-router-dom\";\nimport { PageContainer } from \"@burdenoff/fe-libs/ui\";\nimport { Pin, Filter, Loader2 } from \"lucide-react\";\nimport { ConversationListPage } from \"./ConversationListPage\";\nimport { PermissionGuard } from \"../components/PermissionGuard\";\nimport {\n InboxLayout,\n type FilterChipDescriptor,\n type InboxTabId,\n} from \"../components/InboxLayout\";\nimport { CONVERSATIONS_PERMISSIONS } from \"../constants/permissions\";\nimport { useUserFeatureFlags } from \"../hooks/useUserFeatureFlags\";\nimport { useConversationsStore } from \"../store/conversationsStore\";\nimport { useTr } from \"../utils/i18n\";\n\n// Lazy-load the detail page so the inbox bundle stays small for users who\n// never open a conversation in this session. The detail subtree is the\n// heaviest by far (~19kB gz including MessageBubble).\nconst ConversationDetailPage = lazy(() =>\n import(\"./ConversationDetailPage\").then((m) => ({\n default: m.ConversationDetailPage,\n })),\n);\n\nconst DEFAULT_TAB_ID: InboxTabId = \"all\";\n\n// Maps the inbox tab id to the `forcedFilterParam` prop accepted by\n// ConversationListPage. The \"all\" tab passes undefined so the list shows\n// every conversation type. The archived tab triggers the BE state filter\n// (states: [ARCHIVED]) handled inside ConversationListPage.\nconst TAB_TO_LIST_FILTER: Record<\n InboxTabId,\n \"channel\" | \"direct\" | \"group\" | \"archived\" | undefined\n> = {\n all: undefined,\n direct: \"direct\",\n groups: \"group\",\n channels: \"channel\",\n archived: \"archived\",\n};\n\n/**\n * Landing page for `/conversations`.\n *\n * Renders the canonical inbox: two-pane shell with the conversation list on\n * the left and an empty detail panel on the right. The detail panel is\n * filled in by the router on `/conversations/:conversationId`; this page\n * itself only renders the chrome and the list.\n *\n * Tabs (All / Direct / Groups / Channels / Archived) are stored in the\n * `?tab=` URL search param so refreshing the page keeps the user on the\n * same view.\n */\nexport function ConversationsLandingPage() {\n const [params, setParams] = useSearchParams();\n const { conversationId } = useParams<{ conversationId?: string }>();\n const tr = useTr();\n const { archivedEnabled } = useUserFeatureFlags();\n const {\n searchQuery,\n setSearchQuery,\n conversationFilter,\n updateConversationFilter,\n } = useConversationsStore();\n\n const requestedTab = (params.get(\"tab\") ?? DEFAULT_TAB_ID) as InboxTabId;\n // Strip the archived tab when the feature flag is off — the side effect\n // below also lazily cleans the URL so a deep link doesn't leave the user\n // staring at an unknown tab.\n const activeTab: InboxTabId =\n requestedTab === \"archived\" && !archivedEnabled\n ? DEFAULT_TAB_ID\n : requestedTab;\n\n useEffect(() => {\n if (!archivedEnabled && requestedTab === \"archived\") {\n // Updater form reads the freshest params at flush time to preserve\n // concurrent query-param changes elsewhere in the tree.\n setParams(\n (prev) => {\n const next = new URLSearchParams(prev);\n next.delete(\"tab\");\n return next;\n },\n { replace: true },\n );\n }\n }, [archivedEnabled, requestedTab, setParams]);\n\n const handleTabChange = useCallback(\n (id: InboxTabId) => {\n setParams(\n (prev) => {\n const next = new URLSearchParams(prev);\n if (id === DEFAULT_TAB_ID) {\n next.delete(\"tab\");\n } else {\n next.set(\"tab\", id);\n }\n return next;\n },\n { replace: true },\n );\n },\n [setParams],\n );\n\n // Filter chips are only meaningful on tabs where they can hide items. On\n // the Archived tab the only sane secondary toggle is \"Pinned\" (unread\n // doesn't make sense for archived conversations); on the inbox tabs we\n // expose both unread + pinned.\n const filterChips = useMemo<FilterChipDescriptor[]>(() => {\n if (activeTab === \"archived\") return [];\n const unreadActive = conversationFilter.hasUnread === true;\n const pinnedActive = conversationFilter.isPinned === true;\n return [\n {\n id: \"unread\",\n label: tr(\"conversations.unread\", \"Unread\"),\n active: unreadActive,\n onToggle: () =>\n updateConversationFilter({\n hasUnread: unreadActive ? undefined : true,\n }),\n icon: <Filter size={11} aria-hidden=\"true\" />,\n },\n {\n id: \"pinned\",\n label: tr(\"conversations.pinned\", \"Pinned\"),\n active: pinnedActive,\n onToggle: () =>\n updateConversationFilter({\n isPinned: pinnedActive ? undefined : true,\n }),\n icon: <Pin size={11} aria-hidden=\"true\" />,\n },\n ];\n }, [\n activeTab,\n conversationFilter.hasUnread,\n conversationFilter.isPinned,\n tr,\n updateConversationFilter,\n ]);\n\n const forcedFilter = TAB_TO_LIST_FILTER[activeTab];\n\n return (\n <PermissionGuard\n permission={CONVERSATIONS_PERMISSIONS.CONVERSATION_READ}\n allowUnavailablePermissions\n >\n <PageContainer\n data-tour=\"conversations-landing\"\n padded={false}\n className=\"h-full min-h-0\"\n >\n <h1 id=\"conversations-page-heading\" className=\"sr-only\">\n {tr(\"conversations.title\", \"Conversations\")}\n </h1>\n <InboxLayout\n activeTab={activeTab}\n onTabChange={handleTabChange}\n archivedEnabled={archivedEnabled}\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n filterChips={filterChips}\n listSlot={\n <ConversationListPage embedded forcedFilterParam={forcedFilter} />\n }\n detailSlot={\n conversationId ? (\n <Suspense\n fallback={\n <div\n role=\"status\"\n aria-live=\"polite\"\n className=\"flex h-full items-center justify-center gap-2 text-sm text-text-secondary\"\n >\n <Loader2\n size={16}\n className=\"animate-spin\"\n aria-hidden=\"true\"\n />\n {tr(\"conversations.detailLoading\", \"Loading conversation…\")}\n </div>\n }\n >\n <ConversationDetailPage />\n </Suspense>\n ) : undefined\n }\n />\n </PageContainer>\n </PermissionGuard>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,IAAM,IAAyB,QAC7B,OAAO,+BAA4B,MAAM,OAAO,EAC9C,SAAS,EAAE,wBACZ,EAAE,CACJ,EAEK,IAA6B,OAM7B,IAGF;CACF,KAAK,KAAA;CACL,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACX;AAcD,SAAgB,IAA2B;CACzC,IAAM,CAAC,GAAQ,KAAa,GAAiB,EACvC,EAAE,sBAAmB,GAAwC,EAC7D,IAAK,GAAO,EACZ,EAAE,uBAAoB,GAAqB,EAC3C,EACJ,gBACA,mBACA,uBACA,gCACE,GAAuB,EAErB,IAAgB,EAAO,IAAI,MAAM,IAAI,GAIrC,IACJ,MAAiB,cAAc,CAAC,IAC5B,IACA;AAEN,SAAgB;AACd,EAAI,CAAC,KAAmB,MAAiB,cAGvC,GACG,MAAS;GACR,IAAM,IAAO,IAAI,gBAAgB,EAAK;AAEtC,UADA,EAAK,OAAO,MAAM,EACX;KAET,EAAE,SAAS,IAAM,CAClB;IAEF;EAAC;EAAiB;EAAc;EAAU,CAAC;CAE9C,IAAM,IAAkB,GACrB,MAAmB;AAClB,KACG,MAAS;GACR,IAAM,IAAO,IAAI,gBAAgB,EAAK;AAMtC,UALI,MAAO,IACT,EAAK,OAAO,MAAM,GAElB,EAAK,IAAI,OAAO,EAAG,EAEd;KAET,EAAE,SAAS,IAAM,CAClB;IAEH,CAAC,EAAU,CACZ,EAMK,IAAc,QAAsC;AACxD,MAAI,MAAc,WAAY,QAAO,EAAE;EACvC,IAAM,IAAe,EAAmB,cAAc,IAChD,IAAe,EAAmB,aAAa;AACrD,SAAO,CACL;GACE,IAAI;GACJ,OAAO,EAAG,wBAAwB,SAAS;GAC3C,QAAQ;GACR,gBACE,EAAyB,EACvB,WAAW,IAAe,KAAA,IAAY,IACvC,CAAC;GACJ,MAAM,kBAAC,GAAD;IAAQ,MAAM;IAAI,eAAY;IAAS,CAAA;GAC9C,EACD;GACE,IAAI;GACJ,OAAO,EAAG,wBAAwB,SAAS;GAC3C,QAAQ;GACR,gBACE,EAAyB,EACvB,UAAU,IAAe,KAAA,IAAY,IACtC,CAAC;GACJ,MAAM,kBAAC,GAAD;IAAK,MAAM;IAAI,eAAY;IAAS,CAAA;GAC3C,CACF;IACA;EACD;EACA,EAAmB;EACnB,EAAmB;EACnB;EACA;EACD,CAAC,EAEI,IAAe,EAAmB;AAExC,QACE,kBAAC,GAAD;EACE,YAAY,EAA0B;EACtC,6BAAA;YAEA,kBAAC,GAAD;GACE,aAAU;GACV,QAAQ;GACR,WAAU;aAHZ,CAKE,kBAAC,MAAD;IAAI,IAAG;IAA6B,WAAU;cAC3C,EAAG,uBAAuB,gBAAgB;IACxC,CAAA,EACL,kBAAC,GAAD;IACa;IACX,aAAa;IACI;IACJ;IACb,gBAAgB;IACH;IACb,UACE,kBAAC,GAAD;KAAsB,UAAA;KAAS,mBAAmB;KAAgB,CAAA;IAEpE,YACE,IACE,kBAAC,GAAD;KACE,UACE,kBAAC,OAAD;MACE,MAAK;MACL,aAAU;MACV,WAAU;gBAHZ,CAKE,kBAAC,GAAD;OACE,MAAM;OACN,WAAU;OACV,eAAY;OACZ,CAAA,EACD,EAAG,+BAA+B,wBAAwB,CACvD;;eAGR,kBAAC,GAAD,EAA0B,CAAA;KACjB,CAAA,GACT,KAAA;IAEN,CAAA,CACY;;EACA,CAAA"}
|