@burdenoff/microfe-channel 2026.520.1 → 2026.525.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.
Files changed (105) hide show
  1. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +226 -224
  2. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
  3. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +4 -4
  4. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
  5. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +2 -2
  6. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
  7. package/dist/channel/modules/channels/pages/ChannelUsersPage.js +65 -57
  8. package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
  9. package/dist/channel/modules/channels/pages/ChannelsListPage.js +43 -41
  10. package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
  11. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +1 -1
  12. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
  13. package/dist/channel/modules/channels/pages/ConnectionsListPage.js +1 -1
  14. package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
  15. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +183 -179
  16. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
  17. package/dist/channel/modules/channels/pages/EditChannelPage.js +2 -2
  18. package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
  19. package/dist/channel/modules/channels/pages/WebhookEventsPage.js +165 -159
  20. package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
  21. package/package.json +1 -1
  22. package/dist/channel/ChannelRoot.d.ts +0 -32
  23. package/dist/channel/ChannelRoot.d.ts.map +0 -1
  24. package/dist/channel/ChannelRoutes.d.ts +0 -10
  25. package/dist/channel/ChannelRoutes.d.ts.map +0 -1
  26. package/dist/channel/components/AdapterCredentialsForm.d.ts +0 -20
  27. package/dist/channel/components/AdapterCredentialsForm.d.ts.map +0 -1
  28. package/dist/channel/components/FeatureNotEnabled.d.ts +0 -13
  29. package/dist/channel/components/FeatureNotEnabled.d.ts.map +0 -1
  30. package/dist/channel/components/PermissionGuard.d.ts +0 -15
  31. package/dist/channel/components/PermissionGuard.d.ts.map +0 -1
  32. package/dist/channel/config/adapterCredentials.d.ts +0 -44
  33. package/dist/channel/config/adapterCredentials.d.ts.map +0 -1
  34. package/dist/channel/constants/permissions.d.ts +0 -32
  35. package/dist/channel/constants/permissions.d.ts.map +0 -1
  36. package/dist/channel/graphql/global-client.d.ts +0 -11
  37. package/dist/channel/graphql/global-client.d.ts.map +0 -1
  38. package/dist/channel/hooks/useChannelOrgSettings.d.ts +0 -22
  39. package/dist/channel/hooks/useChannelOrgSettings.d.ts.map +0 -1
  40. package/dist/channel/hooks/useChannelSubscription.d.ts +0 -36
  41. package/dist/channel/hooks/useChannelSubscription.d.ts.map +0 -1
  42. package/dist/channel/hooks/useChannels.d.ts +0 -228
  43. package/dist/channel/hooks/useChannels.d.ts.map +0 -1
  44. package/dist/channel/index.d.ts +0 -12
  45. package/dist/channel/index.d.ts.map +0 -1
  46. package/dist/channel/modules/channels/hooks/useExport.d.ts +0 -45
  47. package/dist/channel/modules/channels/hooks/useExport.d.ts.map +0 -1
  48. package/dist/channel/modules/channels/i18n.d.ts +0 -14
  49. package/dist/channel/modules/channels/i18n.d.ts.map +0 -1
  50. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts +0 -14
  51. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts.map +0 -1
  52. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts +0 -7
  53. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts.map +0 -1
  54. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts +0 -7
  55. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts.map +0 -1
  56. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts +0 -7
  57. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts.map +0 -1
  58. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts +0 -7
  59. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts.map +0 -1
  60. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts +0 -7
  61. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts.map +0 -1
  62. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts +0 -7
  63. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts.map +0 -1
  64. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts +0 -12
  65. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts.map +0 -1
  66. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts +0 -11
  67. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts.map +0 -1
  68. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts +0 -7
  69. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts.map +0 -1
  70. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts +0 -8
  71. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts.map +0 -1
  72. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts +0 -10
  73. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts.map +0 -1
  74. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts +0 -8
  75. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts.map +0 -1
  76. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts +0 -7
  77. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts.map +0 -1
  78. package/dist/channel/modules/channels/pages/index.d.ts +0 -18
  79. package/dist/channel/modules/channels/pages/index.d.ts.map +0 -1
  80. package/dist/channel/pages/ChannelLandingPage.d.ts +0 -9
  81. package/dist/channel/pages/ChannelLandingPage.d.ts.map +0 -1
  82. package/dist/channel/providers/ChannelProvider.d.ts +0 -16
  83. package/dist/channel/providers/ChannelProvider.d.ts.map +0 -1
  84. package/dist/channel/types/index.d.ts +0 -89
  85. package/dist/channel/types/index.d.ts.map +0 -1
  86. package/dist/channel/utils/shellBridge.d.ts +0 -59
  87. package/dist/channel/utils/shellBridge.d.ts.map +0 -1
  88. package/dist/dev/App.d.ts +0 -6
  89. package/dist/dev/App.d.ts.map +0 -1
  90. package/dist/dev/main.d.ts +0 -2
  91. package/dist/dev/main.d.ts.map +0 -1
  92. package/dist/generated/global-operations.d.ts +0 -1549
  93. package/dist/generated/global-operations.d.ts.map +0 -1
  94. package/dist/generated/global-types.d.ts +0 -23527
  95. package/dist/generated/global-types.d.ts.map +0 -1
  96. package/dist/generated/wspace-operations.d.ts +0 -2
  97. package/dist/generated/wspace-operations.d.ts.map +0 -1
  98. package/dist/generated/wspace-types.d.ts +0 -57851
  99. package/dist/generated/wspace-types.d.ts.map +0 -1
  100. package/dist/index.d.ts +0 -5
  101. package/dist/index.d.ts.map +0 -1
  102. package/dist/translations/en.d.ts +0 -260
  103. package/dist/translations/en.d.ts.map +0 -1
  104. package/dist/utils/nativeBridge.d.ts +0 -3
  105. package/dist/utils/nativeBridge.d.ts.map +0 -1
@@ -3,9 +3,9 @@ import { useChannel as t } from "../../../hooks/useChannels.js";
3
3
  import { PermissionGuard as n } from "../../../components/PermissionGuard.js";
4
4
  import { CHANNEL_PERMISSIONS as r } from "../../../constants/permissions.js";
5
5
  import { useExportChannelUsers as i } from "../hooks/useExport.js";
6
- import { useCallback as a, useEffect as o, useState as s } from "react";
7
- import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
- import { AlertCircle as l, ArrowLeft as u, Bell as d, BellOff as f, CheckCircle2 as p, ChevronLeft as m, ChevronRight as h, Clock as g, Download as _, Loader2 as v, RefreshCw as y, User as b, UserCheck as x, XCircle as S } from "lucide-react";
6
+ import { useCallback as a, useEffect as o, useRef as s, useState as c } from "react";
7
+ import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
+ import { AlertCircle as u, ArrowLeft as d, Bell as f, BellOff as p, CheckCircle2 as m, ChevronLeft as ee, ChevronRight as h, Clock as g, Download as _, Loader2 as v, RefreshCw as y, User as b, UserCheck as x, XCircle as S } from "lucide-react";
9
9
  import { useNavigate as C, useParams as w } from "react-router-dom";
10
10
  import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
11
11
  //#region src/channel/modules/channels/pages/ChannelUsersPage.tsx
@@ -35,7 +35,7 @@ var O = {
35
35
  APPROVED: {
36
36
  label: "Approved",
37
37
  color: "text-status-success-text bg-status-success-bg-subtle",
38
- icon: p
38
+ icon: m
39
39
  },
40
40
  EXPIRED: {
41
41
  label: "Expired",
@@ -44,55 +44,63 @@ var O = {
44
44
  }
45
45
  };
46
46
  function A() {
47
- let { channelId: p } = w(), g = C(), { t: A } = c(), j = (e, t) => {
47
+ let { channelId: m } = w(), g = C(), { t: A } = l(), j = (e, t) => {
48
48
  let n = A(e);
49
49
  return n === e ? t : n;
50
- }, { organizationId: M } = e(), { triggerExport: N, isExporting: P, exportError: F } = i(M ?? void 0, p), [I, L] = s(!0), [R, z] = s([]), [B, V] = s(25), [H, U] = s(0), [W, G] = s(0), { channel: K, isLoading: q, error: J, fetchUserPlatformConnections: Y } = t(p), X = a(async (e = 0) => {
51
- if (p) {
52
- L(!0);
50
+ }, { organizationId: M } = e(), { triggerExport: te, isExporting: N, exportError: P } = i(M ?? void 0, m), [F, I] = c(!0), [L, R] = c([]), [z, B] = c(25), [V, H] = c(0), [U, W] = c(0), { channel: G, isLoading: K, error: q, fetchUserPlatformConnections: J } = t(m), Y = a(async (e = 0) => {
51
+ if (m) {
52
+ I(!0);
53
53
  try {
54
- let t = await Y(B, e * B);
55
- z(t.items), U(t.total);
54
+ let t = await J(z, e * z);
55
+ R(t.items), H(t.total);
56
56
  } finally {
57
- L(!1);
57
+ I(!1);
58
58
  }
59
59
  }
60
60
  }, [
61
- p,
62
- Y,
63
- B
64
- ]);
61
+ m,
62
+ J,
63
+ z
64
+ ]), X = s(Y);
65
+ o(() => {
66
+ X.current = Y;
67
+ });
68
+ let Z = s(!0), Q = s(!1);
65
69
  o(() => {
66
70
  Promise.resolve().then(() => {
67
- G(0), X(0);
71
+ Q.current = !0, W(0), X.current(0).finally(() => {
72
+ Q.current = !1;
73
+ });
68
74
  });
69
- }, [B]), o(() => {
70
- Promise.resolve().then(() => X(W));
71
- }, [W]), o(() => {
72
- Promise.resolve().then(() => X(0));
73
- }, []);
74
- let Z = Math.max(1, Math.ceil(H / B)), Q = W > 0, $ = W < Z - 1, ee = (e) => O[e] || O.OFFLINE, te = (e) => k[e] || k.EXPIRED;
75
- return q ? /* @__PURE__ */ E("div", {
75
+ }, [z]), o(() => {
76
+ if (Z.current) {
77
+ Z.current = !1;
78
+ return;
79
+ }
80
+ Q.current || Promise.resolve().then(() => X.current(U));
81
+ }, [U]);
82
+ let $ = Math.max(1, Math.ceil(V / z)), ne = U > 0, re = U < $ - 1, ie = (e) => O[e] || O.OFFLINE, ae = (e) => k[e] || k.EXPIRED;
83
+ return K ? /* @__PURE__ */ E("div", {
76
84
  className: "flex items-center justify-center min-h-screen",
77
85
  children: /* @__PURE__ */ E(v, {
78
86
  size: 32,
79
87
  className: "animate-spin text-accent-primary"
80
88
  })
81
- }) : J || !K ? /* @__PURE__ */ E("div", {
89
+ }) : q || !G ? /* @__PURE__ */ E("div", {
82
90
  className: "p-6",
83
91
  children: /* @__PURE__ */ D("div", {
84
92
  className: "flex items-center gap-3 p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg",
85
93
  children: [
86
- /* @__PURE__ */ E(l, {
94
+ /* @__PURE__ */ E(u, {
87
95
  size: 20,
88
96
  className: "text-status-error-text"
89
97
  }),
90
98
  /* @__PURE__ */ E("div", { children: /* @__PURE__ */ E("p", {
91
99
  className: "text-sm font-medium text-status-error-text",
92
- children: J || "Channel not found"
100
+ children: q || "Channel not found"
93
101
  }) }),
94
102
  /* @__PURE__ */ E("button", {
95
- onClick: () => g(`/channels/${p}`),
103
+ onClick: () => g(`/channels/${m}`),
96
104
  className: "ml-auto px-3 py-1 text-sm text-status-error-text hover:bg-status-error-bg-subtle rounded transition-colors",
97
105
  children: "Go Back"
98
106
  })
@@ -108,10 +116,10 @@ function A() {
108
116
  children: [/* @__PURE__ */ D("div", {
109
117
  className: "flex items-center gap-3",
110
118
  children: [/* @__PURE__ */ E("button", {
111
- onClick: () => g(`/channels/${p}`),
119
+ onClick: () => g(`/channels/${m}`),
112
120
  "aria-label": j("channel.backToChannel", "Back to channel"),
113
121
  className: "p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors",
114
- children: /* @__PURE__ */ E(u, {
122
+ children: /* @__PURE__ */ E(d, {
115
123
  size: 20,
116
124
  "aria-hidden": "true"
117
125
  })
@@ -120,14 +128,14 @@ function A() {
120
128
  children: j("channel.channelUsers", "Channel Users")
121
129
  }), /* @__PURE__ */ D("p", {
122
130
  className: "text-sm text-muted-foreground mt-1",
123
- children: [K.name, " - User connections"]
131
+ children: [G.name, " - User connections"]
124
132
  })] })]
125
133
  }), /* @__PURE__ */ D("div", {
126
134
  className: "flex items-center gap-3",
127
135
  children: [
128
136
  /* @__PURE__ */ D("select", {
129
- value: B,
130
- onChange: (e) => V(Number(e.target.value)),
137
+ value: z,
138
+ onChange: (e) => B(Number(e.target.value)),
131
139
  className: "px-3 py-2 text-sm bg-surface border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary/50 text-foreground",
132
140
  children: [
133
141
  /* @__PURE__ */ E("option", {
@@ -149,22 +157,22 @@ function A() {
149
157
  ]
150
158
  }),
151
159
  /* @__PURE__ */ D("button", {
152
- onClick: () => void X(W),
153
- disabled: I,
160
+ onClick: () => void Y(U),
161
+ disabled: F,
154
162
  className: "flex items-center gap-2 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50",
155
163
  children: [/* @__PURE__ */ E(y, {
156
164
  size: 16,
157
- className: I ? "animate-spin" : ""
165
+ className: F ? "animate-spin" : ""
158
166
  }), j("channel.refresh", "Refresh")]
159
167
  }),
160
168
  /* @__PURE__ */ E(n, {
161
169
  permission: r.CHANNEL_ADMIN,
162
170
  children: /* @__PURE__ */ D("button", {
163
- onClick: () => void N(),
164
- disabled: P,
171
+ onClick: () => void te(),
172
+ disabled: N,
165
173
  className: "flex items-center gap-2 px-4 py-2 text-sm font-medium text-fg border border-border hover:bg-bg-elevated rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
166
174
  title: j("channel.exportCSV", "Export to CSV"),
167
- children: [P ? /* @__PURE__ */ E(v, {
175
+ children: [N ? /* @__PURE__ */ E(v, {
168
176
  size: 16,
169
177
  className: "animate-spin"
170
178
  }) : /* @__PURE__ */ E(_, { size: 16 }), j("channel.export", "Export")]
@@ -173,14 +181,14 @@ function A() {
173
181
  ]
174
182
  })]
175
183
  }),
176
- F && /* @__PURE__ */ D("div", {
184
+ P && /* @__PURE__ */ D("div", {
177
185
  className: "p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg flex items-center gap-3",
178
- children: [/* @__PURE__ */ E(l, {
186
+ children: [/* @__PURE__ */ E(u, {
179
187
  size: 20,
180
188
  className: "text-status-error-text"
181
189
  }), /* @__PURE__ */ E("p", {
182
190
  className: "text-sm text-status-error-text flex-1",
183
- children: F
191
+ children: P
184
192
  })]
185
193
  }),
186
194
  /* @__PURE__ */ E("div", {
@@ -230,12 +238,12 @@ function A() {
230
238
  ] })
231
239
  }), /* @__PURE__ */ E("tbody", {
232
240
  className: "divide-y divide-border",
233
- children: R.length === 0 ? /* @__PURE__ */ E("tr", { children: /* @__PURE__ */ E("td", {
241
+ children: L.length === 0 ? /* @__PURE__ */ E("tr", { children: /* @__PURE__ */ E("td", {
234
242
  colSpan: 7,
235
243
  className: "px-4 py-8 text-center text-muted-foreground",
236
244
  children: j("channel.noUsersConnected", "No users connected to this channel")
237
- }) }) : R.map((e) => {
238
- let t = ee(e.presenceStatus), n = e.pairingStatus ? te(e.pairingStatus) : null, r = n?.icon ?? S;
245
+ }) }) : L.map((e) => {
246
+ let t = ie(e.presenceStatus), n = e.pairingStatus ? ae(e.pairingStatus) : null, r = n?.icon ?? S;
239
247
  return /* @__PURE__ */ D("tr", {
240
248
  className: "hover:bg-muted/30 transition-colors",
241
249
  children: [
@@ -293,7 +301,7 @@ function A() {
293
301
  className: "px-4 py-3",
294
302
  children: e.notificationsEnabled ? /* @__PURE__ */ D("span", {
295
303
  className: "inline-flex items-center gap-1",
296
- children: [/* @__PURE__ */ E(d, {
304
+ children: [/* @__PURE__ */ E(f, {
297
305
  size: 16,
298
306
  className: "text-status-success-text",
299
307
  "aria-hidden": "true"
@@ -303,7 +311,7 @@ function A() {
303
311
  })]
304
312
  }) : /* @__PURE__ */ D("span", {
305
313
  className: "inline-flex items-center gap-1",
306
- children: [/* @__PURE__ */ E(f, {
314
+ children: [/* @__PURE__ */ E(p, {
307
315
  size: 16,
308
316
  className: "text-muted-foreground",
309
317
  "aria-hidden": "true"
@@ -334,15 +342,15 @@ function A() {
334
342
  className: "flex items-center justify-between",
335
343
  children: [/* @__PURE__ */ E("p", {
336
344
  className: "text-sm text-muted-foreground",
337
- children: H > 0 && /* @__PURE__ */ D(T, { children: [
345
+ children: V > 0 && /* @__PURE__ */ D(T, { children: [
338
346
  j("channel.showing", "Showing"),
339
347
  " ",
340
348
  /* @__PURE__ */ D("span", {
341
349
  className: "font-medium",
342
350
  children: [
343
- W * B + 1,
351
+ U * z + 1,
344
352
  "–",
345
- Math.min((W + 1) * B, H)
353
+ Math.min((U + 1) * z, V)
346
354
  ]
347
355
  }),
348
356
  " ",
@@ -350,29 +358,29 @@ function A() {
350
358
  " ",
351
359
  /* @__PURE__ */ E("span", {
352
360
  className: "font-medium",
353
- children: H
361
+ children: V
354
362
  })
355
363
  ] })
356
364
  }), /* @__PURE__ */ D("div", {
357
365
  className: "flex items-center gap-2",
358
366
  children: [
359
367
  /* @__PURE__ */ D("button", {
360
- onClick: () => G((e) => Math.max(0, e - 1)),
361
- disabled: !Q || I,
368
+ onClick: () => W((e) => Math.max(0, e - 1)),
369
+ disabled: !ne || F,
362
370
  className: "flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
363
- children: [/* @__PURE__ */ E(m, { size: 16 }), j("channel.previous", "Previous")]
371
+ children: [/* @__PURE__ */ E(ee, { size: 16 }), j("channel.previous", "Previous")]
364
372
  }),
365
373
  /* @__PURE__ */ D("span", {
366
374
  className: "text-sm text-muted-foreground",
367
375
  children: [
368
- W + 1,
376
+ U + 1,
369
377
  " / ",
370
- Z
378
+ $
371
379
  ]
372
380
  }),
373
381
  /* @__PURE__ */ D("button", {
374
- onClick: () => G((e) => Math.min(Z - 1, e + 1)),
375
- disabled: !$ || I,
382
+ onClick: () => W((e) => Math.min($ - 1, e + 1)),
383
+ disabled: !re || F,
376
384
  className: "flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
377
385
  children: [j("channel.next", "Next"), /* @__PURE__ */ E(h, { size: 16 })]
378
386
  })
@@ -1 +1 @@
1
- {"version":3,"file":"ChannelUsersPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ChannelUsersPage.tsx"],"sourcesContent":["/**\n * Channel Users Page\n *\n * Displays user platform connections for a specific channel\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ArrowLeft,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n Clock,\n User,\n UserCheck,\n Bell,\n BellOff,\n RefreshCw,\n Download,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport {\n useChannel,\n type UserPlatformConnection,\n type UserPresenceStatus,\n type PairingStatus,\n} from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\nimport { useExportChannelUsers } from '../hooks/useExport';\n\nconst PRESENCE_CONFIG: Record<UserPresenceStatus, { label: string; color: string }> = {\n ONLINE: { label: 'Online', color: 'text-status-success-text' },\n OFFLINE: { label: 'Offline', color: 'text-muted-foreground' },\n AWAY: { label: 'Away', color: 'text-status-warning-text' },\n DND: { label: 'Do Not Disturb', color: 'text-status-error-text' },\n};\n\nconst PAIRING_CONFIG: Record<\n PairingStatus,\n { label: string; color: string; icon: typeof CheckCircle2 }\n> = {\n PENDING: {\n label: 'Pending',\n color: 'text-status-warning-text bg-status-warning-bg-subtle',\n icon: Clock,\n },\n APPROVED: {\n label: 'Approved',\n color: 'text-status-success-text bg-status-success-bg-subtle',\n icon: CheckCircle2,\n },\n EXPIRED: { label: 'Expired', color: 'text-muted-foreground bg-muted', icon: XCircle },\n};\n\nexport function ChannelUsersPage() {\n const { channelId } = useParams<{ channelId: string }>();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { organizationId } = useChannelContext();\n const {\n triggerExport: exportUsers,\n isExporting: isExportingUsers,\n exportError: exportUsersError,\n } = useExportChannelUsers(organizationId ?? undefined, channelId);\n const [isLoadingUsers, setIsLoadingUsers] = useState(true);\n const [users, setUsers] = useState<UserPlatformConnection[]>([]);\n const [limit, setLimit] = useState(25);\n const [total, setTotal] = useState(0);\n const [currentPage, setCurrentPage] = useState(0);\n\n const { channel, isLoading, error, fetchUserPlatformConnections } = useChannel(channelId);\n\n const loadUsers = useCallback(\n async (page: number = 0) => {\n if (!channelId) return;\n setIsLoadingUsers(true);\n try {\n const result = await fetchUserPlatformConnections(limit, page * limit);\n setUsers(result.items);\n setTotal(result.total);\n } finally {\n setIsLoadingUsers(false);\n }\n },\n [channelId, fetchUserPlatformConnections, limit]\n );\n\n useEffect(() => {\n void Promise.resolve().then(() => {\n setCurrentPage(0);\n void loadUsers(0);\n });\n }, [limit]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n void Promise.resolve().then(() => loadUsers(currentPage));\n }, [currentPage]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n void Promise.resolve().then(() => loadUsers(0));\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const totalPages = Math.max(1, Math.ceil(total / limit));\n const hasPrevPage = currentPage > 0;\n const hasNextPage = currentPage < totalPages - 1;\n\n const getPresenceConfig = (status: UserPresenceStatus) => {\n return PRESENCE_CONFIG[status] || PRESENCE_CONFIG.OFFLINE;\n };\n\n const getPairingConfig = (status: PairingStatus) => {\n return PAIRING_CONFIG[status] || PAIRING_CONFIG.EXPIRED;\n };\n\n // Loading state (only full-screen for initial channel load)\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 size={32} className=\"animate-spin text-accent-primary\" />\n </div>\n );\n }\n\n // Error state\n if (error || !channel) {\n return (\n <div className=\"p-6\">\n <div className=\"flex items-center gap-3 p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg\">\n <AlertCircle size={20} className=\"text-status-error-text\" />\n <div>\n <p className=\"text-sm font-medium text-status-error-text\">\n {error || 'Channel not found'}\n </p>\n </div>\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"ml-auto px-3 py-1 text-sm text-status-error-text hover:bg-status-error-bg-subtle rounded transition-colors\"\n >\n Go Back\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.USER_PLATFORM_CONNECTION_READ}>\n <div className=\"space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n aria-label={tr('channel.backToChannel', 'Back to channel')}\n className=\"p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft size={20} aria-hidden=\"true\" />\n </button>\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tr('channel.channelUsers', 'Channel Users')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {channel.name} - User connections\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <select\n value={limit}\n onChange={(e) => setLimit(Number(e.target.value))}\n className=\"px-3 py-2 text-sm bg-surface border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary/50 text-foreground\"\n >\n <option value={10}>10 results</option>\n <option value={25}>25 results</option>\n <option value={50}>50 results</option>\n <option value={100}>100 results</option>\n </select>\n <button\n onClick={() => void loadUsers(currentPage)}\n disabled={isLoadingUsers}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50\"\n >\n <RefreshCw size={16} className={isLoadingUsers ? 'animate-spin' : ''} />\n {tr('channel.refresh', 'Refresh')}\n </button>\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_ADMIN}>\n <button\n onClick={() => void exportUsers()}\n disabled={isExportingUsers}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-fg border border-border hover:bg-bg-elevated rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr('channel.exportCSV', 'Export to CSV')}\n >\n {isExportingUsers ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Download size={16} />\n )}\n {tr('channel.export', 'Export')}\n </button>\n </PermissionGuard>\n </div>\n </div>\n\n {/* Export Error Banner */}\n {exportUsersError && (\n <div className=\"p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg flex items-center gap-3\">\n <AlertCircle size={20} className=\"text-status-error-text\" />\n <p className=\"text-sm text-status-error-text flex-1\">{exportUsersError}</p>\n </div>\n )}\n\n {/* Info Banner */}\n <div className=\"p-4 bg-surface border border-border rounded-lg\">\n <p className=\"text-sm text-muted-foreground\">\n Users connected to this channel through OAuth or pairing. Manage notification\n preferences and DM authorization here.\n </p>\n </div>\n\n {/* Users List */}\n <div className=\"bg-surface border border-border rounded-lg overflow-hidden\">\n <div className=\"overflow-x-auto min-w-full\">\n <table className=\"w-full min-w-[800px]\">\n <thead className=\"bg-muted/50 border-b border-border\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.user', 'User')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.platformId', 'Platform ID')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.source', 'Source')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.status', 'Status')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.pairing', 'Pairing')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.notifications', 'Notifications')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.dmAllowed', 'DM Allowed')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {users.length === 0 ? (\n <tr>\n <td colSpan={7} className=\"px-4 py-8 text-center text-muted-foreground\">\n {tr('channel.noUsersConnected', 'No users connected to this channel')}\n </td>\n </tr>\n ) : (\n users.map((user) => {\n const presenceConfig = getPresenceConfig(\n user.presenceStatus as UserPresenceStatus\n );\n const pairingConfig = user.pairingStatus\n ? getPairingConfig(user.pairingStatus as PairingStatus)\n : null;\n const PairingIcon = pairingConfig?.icon ?? XCircle;\n return (\n <tr key={user.id} className=\"hover:bg-muted/30 transition-colors\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 bg-accent-primary/10 rounded-full flex items-center justify-center\">\n <User size={16} className=\"text-accent-primary\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-foreground\">\n {user.externalDisplayName || 'Unknown'}\n </p>\n {user.externalUsername && (\n <p className=\"text-xs text-muted-foreground\">\n {user.externalUsername}\n </p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm font-mono text-muted-foreground\">\n {user.externalUserId}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-muted-foreground bg-muted px-2 py-1 rounded\">\n {user.source}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <span\n className={`w-2 h-2 rounded-full ${presenceConfig.color.replace('text-', 'bg-')}`}\n />\n <span className={`text-sm ${presenceConfig.color}`}>\n {presenceConfig.label}\n </span>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n {user.pairingStatus && pairingConfig ? (\n <span\n className={`inline-flex items-center gap-1 text-xs px-2 py-1 rounded ${pairingConfig.color}`}\n >\n <PairingIcon size={12} />\n {pairingConfig.label}\n </span>\n ) : (\n <span className=\"text-xs text-muted-foreground\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {user.notificationsEnabled ? (\n <span className=\"inline-flex items-center gap-1\">\n <Bell\n size={16}\n className=\"text-status-success-text\"\n aria-hidden=\"true\"\n />\n <span className=\"sr-only\">{tr('channel.enabled', 'Enabled')}</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1\">\n <BellOff\n size={16}\n className=\"text-muted-foreground\"\n aria-hidden=\"true\"\n />\n <span className=\"sr-only\">{tr('channel.disabled', 'Disabled')}</span>\n </span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {user.dmAllowed ? (\n <span className=\"inline-flex items-center gap-1 text-sm text-status-success-text\">\n <UserCheck size={16} />\n {tr('channel.allowed', 'Allowed')}\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-sm text-muted-foreground\">\n <XCircle size={16} />\n {tr('channel.blocked', 'Blocked')}\n </span>\n )}\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n {/* Pagination footer */}\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {total > 0 && (\n <>\n {tr('channel.showing', 'Showing')}{' '}\n <span className=\"font-medium\">\n {currentPage * limit + 1}–{Math.min((currentPage + 1) * limit, total)}\n </span>{' '}\n {tr('channel.of', 'of')} <span className=\"font-medium\">{total}</span>\n </>\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}\n disabled={!hasPrevPage || isLoadingUsers}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <ChevronLeft size={16} />\n {tr('channel.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {currentPage + 1} / {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}\n disabled={!hasNextPage || isLoadingUsers}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.next', 'Next')}\n <ChevronRight size={16} />\n </button>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChannelUsersPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ChannelUsersPage.tsx"],"sourcesContent":["/**\n * Channel Users Page\n *\n * Displays user platform connections for a specific channel\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ArrowLeft,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n Clock,\n User,\n UserCheck,\n Bell,\n BellOff,\n RefreshCw,\n Download,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport {\n useChannel,\n type UserPlatformConnection,\n type UserPresenceStatus,\n type PairingStatus,\n} from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\nimport { useExportChannelUsers } from '../hooks/useExport';\n\nconst PRESENCE_CONFIG: Record<UserPresenceStatus, { label: string; color: string }> = {\n ONLINE: { label: 'Online', color: 'text-status-success-text' },\n OFFLINE: { label: 'Offline', color: 'text-muted-foreground' },\n AWAY: { label: 'Away', color: 'text-status-warning-text' },\n DND: { label: 'Do Not Disturb', color: 'text-status-error-text' },\n};\n\nconst PAIRING_CONFIG: Record<\n PairingStatus,\n { label: string; color: string; icon: typeof CheckCircle2 }\n> = {\n PENDING: {\n label: 'Pending',\n color: 'text-status-warning-text bg-status-warning-bg-subtle',\n icon: Clock,\n },\n APPROVED: {\n label: 'Approved',\n color: 'text-status-success-text bg-status-success-bg-subtle',\n icon: CheckCircle2,\n },\n EXPIRED: { label: 'Expired', color: 'text-muted-foreground bg-muted', icon: XCircle },\n};\n\nexport function ChannelUsersPage() {\n const { channelId } = useParams<{ channelId: string }>();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const { organizationId } = useChannelContext();\n const {\n triggerExport: exportUsers,\n isExporting: isExportingUsers,\n exportError: exportUsersError,\n } = useExportChannelUsers(organizationId ?? undefined, channelId);\n const [isLoadingUsers, setIsLoadingUsers] = useState(true);\n const [users, setUsers] = useState<UserPlatformConnection[]>([]);\n const [limit, setLimit] = useState(25);\n const [total, setTotal] = useState(0);\n const [currentPage, setCurrentPage] = useState(0);\n\n const { channel, isLoading, error, fetchUserPlatformConnections } = useChannel(channelId);\n\n const loadUsers = useCallback(\n async (page: number = 0) => {\n if (!channelId) return;\n setIsLoadingUsers(true);\n try {\n const result = await fetchUserPlatformConnections(limit, page * limit);\n setUsers(result.items);\n setTotal(result.total);\n } finally {\n setIsLoadingUsers(false);\n }\n },\n [channelId, fetchUserPlatformConnections, limit]\n );\n\n const loadUsersRef = useRef(loadUsers);\n useEffect(() => {\n loadUsersRef.current = loadUsers;\n });\n const isFirstPageRender = useRef(true);\n // Prevents the [currentPage] effect from double-loading when limit changes\n // reset the page back to 0 (the [limit] effect already handles that load).\n const limitChangingRef = useRef(false);\n\n useEffect(() => {\n void Promise.resolve().then(() => {\n // Set the guard before resetting page so the [currentPage] effect skips\n // the redundant load that would otherwise fire when page resets to 0.\n limitChangingRef.current = true;\n setCurrentPage(0);\n void loadUsersRef.current(0).finally(() => {\n limitChangingRef.current = false;\n });\n });\n }, [limit]);\n\n useEffect(() => {\n if (isFirstPageRender.current) {\n isFirstPageRender.current = false;\n return;\n }\n if (limitChangingRef.current) return;\n void Promise.resolve().then(() => loadUsersRef.current(currentPage));\n }, [currentPage]);\n\n const totalPages = Math.max(1, Math.ceil(total / limit));\n const hasPrevPage = currentPage > 0;\n const hasNextPage = currentPage < totalPages - 1;\n\n const getPresenceConfig = (status: UserPresenceStatus) => {\n return PRESENCE_CONFIG[status] || PRESENCE_CONFIG.OFFLINE;\n };\n\n const getPairingConfig = (status: PairingStatus) => {\n return PAIRING_CONFIG[status] || PAIRING_CONFIG.EXPIRED;\n };\n\n // Loading state (only full-screen for initial channel load)\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 size={32} className=\"animate-spin text-accent-primary\" />\n </div>\n );\n }\n\n // Error state\n if (error || !channel) {\n return (\n <div className=\"p-6\">\n <div className=\"flex items-center gap-3 p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg\">\n <AlertCircle size={20} className=\"text-status-error-text\" />\n <div>\n <p className=\"text-sm font-medium text-status-error-text\">\n {error || 'Channel not found'}\n </p>\n </div>\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"ml-auto px-3 py-1 text-sm text-status-error-text hover:bg-status-error-bg-subtle rounded transition-colors\"\n >\n Go Back\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.USER_PLATFORM_CONNECTION_READ}>\n <div className=\"space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => navigate(`/channels/${channelId}`)}\n aria-label={tr('channel.backToChannel', 'Back to channel')}\n className=\"p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft size={20} aria-hidden=\"true\" />\n </button>\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold text-foreground\">\n {tr('channel.channelUsers', 'Channel Users')}\n </h1>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {channel.name} - User connections\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <select\n value={limit}\n onChange={(e) => setLimit(Number(e.target.value))}\n className=\"px-3 py-2 text-sm bg-surface border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-primary/50 text-foreground\"\n >\n <option value={10}>10 results</option>\n <option value={25}>25 results</option>\n <option value={50}>50 results</option>\n <option value={100}>100 results</option>\n </select>\n <button\n onClick={() => void loadUsers(currentPage)}\n disabled={isLoadingUsers}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50\"\n >\n <RefreshCw size={16} className={isLoadingUsers ? 'animate-spin' : ''} />\n {tr('channel.refresh', 'Refresh')}\n </button>\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_ADMIN}>\n <button\n onClick={() => void exportUsers()}\n disabled={isExportingUsers}\n className=\"flex items-center gap-2 px-4 py-2 text-sm font-medium text-fg border border-border hover:bg-bg-elevated rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr('channel.exportCSV', 'Export to CSV')}\n >\n {isExportingUsers ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Download size={16} />\n )}\n {tr('channel.export', 'Export')}\n </button>\n </PermissionGuard>\n </div>\n </div>\n\n {/* Export Error Banner */}\n {exportUsersError && (\n <div className=\"p-4 bg-status-error-bg-subtle border border-status-error-border rounded-lg flex items-center gap-3\">\n <AlertCircle size={20} className=\"text-status-error-text\" />\n <p className=\"text-sm text-status-error-text flex-1\">{exportUsersError}</p>\n </div>\n )}\n\n {/* Info Banner */}\n <div className=\"p-4 bg-surface border border-border rounded-lg\">\n <p className=\"text-sm text-muted-foreground\">\n Users connected to this channel through OAuth or pairing. Manage notification\n preferences and DM authorization here.\n </p>\n </div>\n\n {/* Users List */}\n <div className=\"bg-surface border border-border rounded-lg overflow-hidden\">\n <div className=\"overflow-x-auto min-w-full\">\n <table className=\"w-full min-w-[800px]\">\n <thead className=\"bg-muted/50 border-b border-border\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.user', 'User')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.platformId', 'Platform ID')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.source', 'Source')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.status', 'Status')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.pairing', 'Pairing')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.notifications', 'Notifications')}\n </th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {tr('channel.dmAllowed', 'DM Allowed')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {users.length === 0 ? (\n <tr>\n <td colSpan={7} className=\"px-4 py-8 text-center text-muted-foreground\">\n {tr('channel.noUsersConnected', 'No users connected to this channel')}\n </td>\n </tr>\n ) : (\n users.map((user) => {\n const presenceConfig = getPresenceConfig(\n user.presenceStatus as UserPresenceStatus\n );\n const pairingConfig = user.pairingStatus\n ? getPairingConfig(user.pairingStatus as PairingStatus)\n : null;\n const PairingIcon = pairingConfig?.icon ?? XCircle;\n return (\n <tr key={user.id} className=\"hover:bg-muted/30 transition-colors\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 bg-accent-primary/10 rounded-full flex items-center justify-center\">\n <User size={16} className=\"text-accent-primary\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-foreground\">\n {user.externalDisplayName || 'Unknown'}\n </p>\n {user.externalUsername && (\n <p className=\"text-xs text-muted-foreground\">\n {user.externalUsername}\n </p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm font-mono text-muted-foreground\">\n {user.externalUserId}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-muted-foreground bg-muted px-2 py-1 rounded\">\n {user.source}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <span\n className={`w-2 h-2 rounded-full ${presenceConfig.color.replace('text-', 'bg-')}`}\n />\n <span className={`text-sm ${presenceConfig.color}`}>\n {presenceConfig.label}\n </span>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n {user.pairingStatus && pairingConfig ? (\n <span\n className={`inline-flex items-center gap-1 text-xs px-2 py-1 rounded ${pairingConfig.color}`}\n >\n <PairingIcon size={12} />\n {pairingConfig.label}\n </span>\n ) : (\n <span className=\"text-xs text-muted-foreground\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {user.notificationsEnabled ? (\n <span className=\"inline-flex items-center gap-1\">\n <Bell\n size={16}\n className=\"text-status-success-text\"\n aria-hidden=\"true\"\n />\n <span className=\"sr-only\">{tr('channel.enabled', 'Enabled')}</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1\">\n <BellOff\n size={16}\n className=\"text-muted-foreground\"\n aria-hidden=\"true\"\n />\n <span className=\"sr-only\">{tr('channel.disabled', 'Disabled')}</span>\n </span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {user.dmAllowed ? (\n <span className=\"inline-flex items-center gap-1 text-sm text-status-success-text\">\n <UserCheck size={16} />\n {tr('channel.allowed', 'Allowed')}\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-sm text-muted-foreground\">\n <XCircle size={16} />\n {tr('channel.blocked', 'Blocked')}\n </span>\n )}\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n {/* Pagination footer */}\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {total > 0 && (\n <>\n {tr('channel.showing', 'Showing')}{' '}\n <span className=\"font-medium\">\n {currentPage * limit + 1}–{Math.min((currentPage + 1) * limit, total)}\n </span>{' '}\n {tr('channel.of', 'of')} <span className=\"font-medium\">{total}</span>\n </>\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}\n disabled={!hasPrevPage || isLoadingUsers}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <ChevronLeft size={16} />\n {tr('channel.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {currentPage + 1} / {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}\n disabled={!hasNextPage || isLoadingUsers}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.next', 'Next')}\n <ChevronRight size={16} />\n </button>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}