@arbidocs/blocks 0.4.110 → 0.4.111
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/{NativeDocxEditor-WODZAURG.cjs → NativeDocxEditor-AQKRZBIU.cjs} +7 -7
- package/dist/{NativeDocxEditor-WODZAURG.cjs.map → NativeDocxEditor-AQKRZBIU.cjs.map} +1 -1
- package/dist/{NativeDocxEditor-4PY4YZYC.js → NativeDocxEditor-IN2HEO5I.js} +3 -3
- package/dist/{NativeDocxEditor-4PY4YZYC.js.map → NativeDocxEditor-IN2HEO5I.js.map} +1 -1
- package/dist/agents/index.cjs +207 -207
- package/dist/agents/index.js +2 -2
- package/dist/calendar/EventEditor.d.ts +1 -1
- package/dist/calendar/draft.d.ts +7 -1
- package/dist/calendar/index.cjs +58 -10
- package/dist/calendar/index.cjs.map +1 -1
- package/dist/calendar/index.d.ts +1 -1
- package/dist/calendar/index.js +56 -11
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/types.d.ts +20 -0
- package/dist/calls/CallSidePanel.d.ts +16 -1
- package/dist/calls/ControlBar.d.ts +25 -3
- package/dist/calls/PreJoin.d.ts +6 -2
- package/dist/calls/cards.d.ts +6 -2
- package/dist/calls/index.cjs +1078 -47
- package/dist/calls/index.cjs.map +1 -1
- package/dist/calls/index.d.ts +4 -3
- package/dist/calls/index.js +1067 -51
- package/dist/calls/index.js.map +1 -1
- package/dist/calls/panels.d.ts +11 -0
- package/dist/calls/webinar/ChatPermissionSetting.d.ts +18 -0
- package/dist/calls/webinar/OnStageCheck.d.ts +23 -0
- package/dist/calls/webinar/QAPanel.d.ts +56 -0
- package/dist/calls/webinar/RaiseHandButton.d.ts +14 -0
- package/dist/calls/webinar/WebinarAudiencePanel.d.ts +23 -0
- package/dist/calls/webinar/WebinarViewer.d.ts +39 -0
- package/dist/calls/webinar/WebinarWaiting.d.ts +19 -0
- package/dist/calls/webinar/hooks.d.ts +13 -0
- package/dist/calls/webinar/index.d.ts +14 -0
- package/dist/calls/webinar/live.d.ts +43 -0
- package/dist/calls/webinar/types.d.ts +49 -0
- package/dist/{chunk-GKDWQLVU.js → chunk-2C7TCVQZ.js} +172 -121
- package/dist/chunk-2C7TCVQZ.js.map +1 -0
- package/dist/{chunk-54WBIVHV.cjs → chunk-2WO5L7YT.cjs} +5 -5
- package/dist/{chunk-54WBIVHV.cjs.map → chunk-2WO5L7YT.cjs.map} +1 -1
- package/dist/{chunk-A35KT2II.js → chunk-6Z7DLJU2.js} +3 -3
- package/dist/{chunk-A35KT2II.js.map → chunk-6Z7DLJU2.js.map} +1 -1
- package/dist/{chunk-VZKBI2KJ.cjs → chunk-FXUQZFAN.cjs} +3 -3
- package/dist/{chunk-VZKBI2KJ.cjs.map → chunk-FXUQZFAN.cjs.map} +1 -1
- package/dist/{chunk-SQNAJPNR.js → chunk-GFYGYME3.js} +3 -3
- package/dist/{chunk-SQNAJPNR.js.map → chunk-GFYGYME3.js.map} +1 -1
- package/dist/chunk-GICUGQNN.cjs +76 -0
- package/dist/chunk-GICUGQNN.cjs.map +1 -0
- package/dist/chunk-JJLMCV3T.js +73 -0
- package/dist/chunk-JJLMCV3T.js.map +1 -0
- package/dist/{chunk-W7ZDBPJ3.cjs → chunk-OR4CO743.cjs} +3 -3
- package/dist/{chunk-W7ZDBPJ3.cjs.map → chunk-OR4CO743.cjs.map} +1 -1
- package/dist/{chunk-PEHLUB52.js → chunk-Q6B77ZWZ.js} +3 -3
- package/dist/{chunk-PEHLUB52.js.map → chunk-Q6B77ZWZ.js.map} +1 -1
- package/dist/{chunk-ELDUWTRR.cjs → chunk-TF47ATYS.cjs} +4 -4
- package/dist/{chunk-ELDUWTRR.cjs.map → chunk-TF47ATYS.cjs.map} +1 -1
- package/dist/{chunk-JB32KYAH.js → chunk-WTM65ZNG.js} +3 -3
- package/dist/{chunk-JB32KYAH.js.map → chunk-WTM65ZNG.js.map} +1 -1
- package/dist/{chunk-2NIL2ASF.cjs → chunk-XIGWUDOD.cjs} +170 -119
- package/dist/chunk-XIGWUDOD.cjs.map +1 -0
- package/dist/collaboration/index.cjs +1 -1
- package/dist/collaboration/index.js +1 -1
- package/dist/connect/docx.cjs +6 -6
- package/dist/connect/docx.js +4 -4
- package/dist/connect/index.cjs +31 -31
- package/dist/connect/index.js +7 -7
- package/dist/docx/AgentUndo.d.ts +4 -0
- package/dist/docx/index.cjs +46 -46
- package/dist/docx/index.js +3 -3
- package/dist/files/index.cjs +1 -1
- package/dist/files/index.js +1 -1
- package/dist/index.cjs +332 -332
- package/dist/index.js +6 -6
- package/dist/settings/index.cjs +48 -102
- package/dist/settings/index.cjs.map +1 -1
- package/dist/settings/index.js +10 -70
- package/dist/settings/index.js.map +1 -1
- package/dist/workflow-canvas/index.cjs +9 -9
- package/dist/workflow-canvas/index.js +2 -2
- package/node_modules/@arbidocs/coedit/dist/commands.cjs +179 -9
- package/node_modules/@arbidocs/coedit/dist/commands.cjs.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/commands.d.cts +81 -1
- package/node_modules/@arbidocs/coedit/dist/commands.d.ts +81 -1
- package/node_modules/@arbidocs/coedit/dist/commands.js +173 -11
- package/node_modules/@arbidocs/coedit/dist/commands.js.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/server.cjs +58 -2
- package/node_modules/@arbidocs/coedit/dist/server.cjs.map +1 -1
- package/node_modules/@arbidocs/coedit/dist/server.d.cts +29 -1
- package/node_modules/@arbidocs/coedit/dist/server.d.ts +29 -1
- package/node_modules/@arbidocs/coedit/dist/server.js +58 -3
- package/node_modules/@arbidocs/coedit/dist/server.js.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +4 -4
- package/dist/chunk-2NIL2ASF.cjs.map +0 -1
- package/dist/chunk-GKDWQLVU.js.map +0 -1
package/dist/calls/index.cjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkGICUGQNN_cjs = require('../chunk-GICUGQNN.cjs');
|
|
4
5
|
var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
|
|
6
|
+
require('../chunk-ULWRNGGE.cjs');
|
|
5
7
|
var chunkMWDW5UBW_cjs = require('../chunk-MWDW5UBW.cjs');
|
|
6
8
|
require('../chunk-PPCATBOY.cjs');
|
|
7
9
|
require('../chunk-MHVNT4J3.cjs');
|
|
10
|
+
var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
|
|
8
11
|
require('../chunk-DES3K4SD.cjs');
|
|
9
12
|
var react = require('react');
|
|
10
13
|
var ui = require('@arbidocs/react/ui');
|
|
@@ -681,9 +684,11 @@ function LeaveButton({
|
|
|
681
684
|
onLeave,
|
|
682
685
|
compact = false,
|
|
683
686
|
label = "Leave",
|
|
684
|
-
title = "Leave call"
|
|
687
|
+
title = "Leave call",
|
|
688
|
+
options
|
|
685
689
|
}) {
|
|
686
|
-
|
|
690
|
+
const menu = !!options?.length;
|
|
691
|
+
const button = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
687
692
|
ui.Button,
|
|
688
693
|
{
|
|
689
694
|
type: "button",
|
|
@@ -692,7 +697,7 @@ function LeaveButton({
|
|
|
692
697
|
className: ui.cn("shrink-0", !compact && "px-4"),
|
|
693
698
|
"aria-label": title,
|
|
694
699
|
title,
|
|
695
|
-
onClick: onLeave,
|
|
700
|
+
onClick: menu ? void 0 : onLeave,
|
|
696
701
|
"data-testid": "call-leave",
|
|
697
702
|
children: [
|
|
698
703
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { className: "size-4", "aria-hidden": true }),
|
|
@@ -700,13 +705,34 @@ function LeaveButton({
|
|
|
700
705
|
]
|
|
701
706
|
}
|
|
702
707
|
);
|
|
708
|
+
if (!menu) return button;
|
|
709
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
710
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: button }),
|
|
711
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", className: "w-56", children: [
|
|
712
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onLeave, "data-testid": "call-leave-only", children: [
|
|
713
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { "aria-hidden": true }),
|
|
714
|
+
label
|
|
715
|
+
] }),
|
|
716
|
+
options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
717
|
+
ui.DropdownMenuItem,
|
|
718
|
+
{
|
|
719
|
+
onSelect: o.onSelect,
|
|
720
|
+
className: "text-red-text focus:text-red-text",
|
|
721
|
+
"data-testid": o.testId,
|
|
722
|
+
children: o.label
|
|
723
|
+
},
|
|
724
|
+
o.key
|
|
725
|
+
))
|
|
726
|
+
] })
|
|
727
|
+
] });
|
|
703
728
|
}
|
|
729
|
+
var isSection = (g) => !Array.isArray(g);
|
|
704
730
|
function MoreMenu({
|
|
705
731
|
details,
|
|
706
732
|
groups,
|
|
707
733
|
label = "More options"
|
|
708
734
|
}) {
|
|
709
|
-
const shown = groups.filter((g) => g.length > 0);
|
|
735
|
+
const shown = groups.filter((g) => isSection(g) || g.length > 0);
|
|
710
736
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
711
737
|
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(CallControlButton, { label, tooltip: false, "data-testid": "call-more", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { "aria-hidden": true }) }) }),
|
|
712
738
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { side: "top", align: "end", className: "w-72", "data-testid": "call-more-menu", children: [
|
|
@@ -716,7 +742,7 @@ function MoreMenu({
|
|
|
716
742
|
] }),
|
|
717
743
|
shown.map((group, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", children: [
|
|
718
744
|
i > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
|
|
719
|
-
group.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
745
|
+
isSection(group) ? group.content : group.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
720
746
|
ui.DropdownMenuItem,
|
|
721
747
|
{
|
|
722
748
|
onSelect: item.onSelect,
|
|
@@ -730,7 +756,7 @@ function MoreMenu({
|
|
|
730
756
|
},
|
|
731
757
|
item.key
|
|
732
758
|
))
|
|
733
|
-
] }, group[0].key))
|
|
759
|
+
] }, isSection(group) ? group.key : group[0].key))
|
|
734
760
|
] })
|
|
735
761
|
] });
|
|
736
762
|
}
|
|
@@ -908,40 +934,69 @@ function CallSidePanel({
|
|
|
908
934
|
onClose,
|
|
909
935
|
closeLabel,
|
|
910
936
|
closeTestId,
|
|
937
|
+
tabs,
|
|
938
|
+
activeTab,
|
|
939
|
+
onTabChange,
|
|
911
940
|
children,
|
|
912
941
|
className,
|
|
913
942
|
...rest
|
|
914
943
|
}) {
|
|
915
|
-
|
|
944
|
+
const tabbed = !!tabs?.length;
|
|
945
|
+
const current = activeTab ?? tabs?.[0]?.id;
|
|
946
|
+
const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border pl-3 pr-1.5", children: [
|
|
947
|
+
tabbed ? /* @__PURE__ */ jsxRuntime.jsx(ui.TabsList, { className: "h-8 min-w-0 flex-1 justify-start overflow-x-auto bg-transparent p-0", children: tabs.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
948
|
+
ui.TabsTrigger,
|
|
949
|
+
{
|
|
950
|
+
value: t.id,
|
|
951
|
+
className: "h-8 gap-1.5 px-2.5 data-[state=active]:bg-muted data-[state=active]:text-primary data-[state=active]:shadow-none",
|
|
952
|
+
"data-testid": t.testId,
|
|
953
|
+
children: [
|
|
954
|
+
t.label,
|
|
955
|
+
t.count !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs tabular-nums text-muted-foreground", children: t.count })
|
|
956
|
+
]
|
|
957
|
+
},
|
|
958
|
+
t.id
|
|
959
|
+
)) }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-base font-semibold text-primary", children: [
|
|
960
|
+
icon,
|
|
961
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: title })
|
|
962
|
+
] }),
|
|
963
|
+
actions,
|
|
964
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
965
|
+
ui.Button,
|
|
966
|
+
{
|
|
967
|
+
type: "button",
|
|
968
|
+
variant: "ghost",
|
|
969
|
+
size: "icon",
|
|
970
|
+
className: "size-8 text-muted-foreground hover:text-foreground",
|
|
971
|
+
"aria-label": closeLabel,
|
|
972
|
+
title: closeLabel,
|
|
973
|
+
onClick: onClose,
|
|
974
|
+
"data-testid": closeTestId,
|
|
975
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
976
|
+
}
|
|
977
|
+
)
|
|
978
|
+
] });
|
|
979
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
916
980
|
"aside",
|
|
917
981
|
{
|
|
918
982
|
className: ui.cn("flex min-h-0 flex-col bg-background text-foreground", className),
|
|
919
983
|
"aria-label": title,
|
|
920
984
|
...rest,
|
|
921
|
-
children:
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
ui.
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
className: "size-8 text-muted-foreground hover:text-foreground",
|
|
935
|
-
"aria-label": closeLabel,
|
|
936
|
-
title: closeLabel,
|
|
937
|
-
onClick: onClose,
|
|
938
|
-
"data-testid": closeTestId,
|
|
939
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
940
|
-
}
|
|
941
|
-
)
|
|
942
|
-
] }),
|
|
985
|
+
children: tabbed ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
986
|
+
ui.Tabs,
|
|
987
|
+
{
|
|
988
|
+
value: current,
|
|
989
|
+
onValueChange: (id) => onTabChange?.(id),
|
|
990
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
991
|
+
children: [
|
|
992
|
+
header,
|
|
993
|
+
current && /* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: current, className: "mt-0 flex min-h-0 flex-1 flex-col", children })
|
|
994
|
+
]
|
|
995
|
+
}
|
|
996
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
997
|
+
header,
|
|
943
998
|
children
|
|
944
|
-
]
|
|
999
|
+
] })
|
|
945
1000
|
}
|
|
946
1001
|
);
|
|
947
1002
|
}
|
|
@@ -974,6 +1029,31 @@ function VoiceMeter({
|
|
|
974
1029
|
}
|
|
975
1030
|
);
|
|
976
1031
|
}
|
|
1032
|
+
function CallPersonLabel({
|
|
1033
|
+
name,
|
|
1034
|
+
entity,
|
|
1035
|
+
isLocal = false,
|
|
1036
|
+
youLabel = "(me)"
|
|
1037
|
+
}) {
|
|
1038
|
+
if (entity) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: entity });
|
|
1039
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1040
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1041
|
+
"span",
|
|
1042
|
+
{
|
|
1043
|
+
className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary",
|
|
1044
|
+
"aria-hidden": true,
|
|
1045
|
+
children: chunkMWDW5UBW_cjs.initialsOf(name)
|
|
1046
|
+
}
|
|
1047
|
+
),
|
|
1048
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate", children: [
|
|
1049
|
+
name,
|
|
1050
|
+
isLocal && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
|
|
1051
|
+
" ",
|
|
1052
|
+
youLabel
|
|
1053
|
+
] })
|
|
1054
|
+
] })
|
|
1055
|
+
] });
|
|
1056
|
+
}
|
|
977
1057
|
function PersonRow({
|
|
978
1058
|
p,
|
|
979
1059
|
canRemove,
|
|
@@ -1003,20 +1083,7 @@ function PersonRow({
|
|
|
1003
1083
|
children: p.entity
|
|
1004
1084
|
}
|
|
1005
1085
|
)
|
|
1006
|
-
) : /* @__PURE__ */ jsxRuntime.
|
|
1007
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1008
|
-
"span",
|
|
1009
|
-
{
|
|
1010
|
-
className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary",
|
|
1011
|
-
"aria-hidden": true,
|
|
1012
|
-
children: chunkMWDW5UBW_cjs.initialsOf(p.name)
|
|
1013
|
-
}
|
|
1014
|
-
),
|
|
1015
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate", children: [
|
|
1016
|
-
p.name,
|
|
1017
|
-
p.isLocal && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: " (me)" })
|
|
1018
|
-
] })
|
|
1019
|
-
] }),
|
|
1086
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: p.name, isLocal: p.isLocal }),
|
|
1020
1087
|
p.speaking && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " \u2014 speaking" }),
|
|
1021
1088
|
p.note && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: p.note })
|
|
1022
1089
|
] }),
|
|
@@ -1428,18 +1495,22 @@ function CallStateMessage({
|
|
|
1428
1495
|
title,
|
|
1429
1496
|
description,
|
|
1430
1497
|
spinner = true,
|
|
1498
|
+
icon,
|
|
1431
1499
|
action,
|
|
1500
|
+
children,
|
|
1432
1501
|
testId
|
|
1433
1502
|
}) {
|
|
1434
1503
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1435
1504
|
"div",
|
|
1436
1505
|
{
|
|
1437
1506
|
className: "flex size-full flex-col items-center justify-center gap-3 p-6 text-center",
|
|
1507
|
+
role: "status",
|
|
1438
1508
|
"data-testid": testId,
|
|
1439
1509
|
children: [
|
|
1440
|
-
spinner && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-6 animate-spin text-muted-foreground", "aria-hidden": true }),
|
|
1510
|
+
icon ?? (spinner && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-6 animate-spin text-muted-foreground", "aria-hidden": true })),
|
|
1441
1511
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold", children: title }),
|
|
1442
1512
|
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }),
|
|
1513
|
+
children,
|
|
1443
1514
|
action
|
|
1444
1515
|
]
|
|
1445
1516
|
}
|
|
@@ -1581,8 +1652,10 @@ function DeviceSelect({
|
|
|
1581
1652
|
function PreJoin({
|
|
1582
1653
|
title,
|
|
1583
1654
|
heading = "Ready to join?",
|
|
1655
|
+
headingAs: Heading = "h2",
|
|
1584
1656
|
children,
|
|
1585
1657
|
joinLabel = "Join",
|
|
1658
|
+
cancelLabel = "Cancel",
|
|
1586
1659
|
busy = false,
|
|
1587
1660
|
error,
|
|
1588
1661
|
onJoin,
|
|
@@ -1653,7 +1726,7 @@ function PreJoin({
|
|
|
1653
1726
|
] }),
|
|
1654
1727
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [
|
|
1655
1728
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1656
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1729
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "text-xl font-semibold", children: heading }),
|
|
1657
1730
|
title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm text-muted-foreground", children: title })
|
|
1658
1731
|
] }),
|
|
1659
1732
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
@@ -1724,14 +1797,957 @@ function PreJoin({
|
|
|
1724
1797
|
type: "button",
|
|
1725
1798
|
variant: "outline",
|
|
1726
1799
|
onClick: onCancel,
|
|
1800
|
+
disabled: busy,
|
|
1727
1801
|
"data-testid": "call-prejoin-cancel",
|
|
1728
|
-
children:
|
|
1802
|
+
children: cancelLabel
|
|
1729
1803
|
}
|
|
1730
1804
|
)
|
|
1731
1805
|
] })
|
|
1732
1806
|
] })
|
|
1733
1807
|
] }) });
|
|
1734
1808
|
}
|
|
1809
|
+
function WebinarWaiting({
|
|
1810
|
+
variant,
|
|
1811
|
+
title,
|
|
1812
|
+
when,
|
|
1813
|
+
host,
|
|
1814
|
+
onLeave,
|
|
1815
|
+
leaveLabel = "Leave"
|
|
1816
|
+
}) {
|
|
1817
|
+
const waiting = variant === "waiting";
|
|
1818
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1819
|
+
CallStateMessage,
|
|
1820
|
+
{
|
|
1821
|
+
title: waiting ? "Starting soon" : "This webinar has ended",
|
|
1822
|
+
description: waiting ? "The host hasn't gone live yet. You'll join automatically when the webinar starts." : "Thanks for attending.",
|
|
1823
|
+
spinner: waiting,
|
|
1824
|
+
icon: waiting ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarCheck, { className: "size-6 text-muted-foreground", "aria-hidden": true }),
|
|
1825
|
+
testId: waiting ? "webinar-waiting" : "webinar-ended",
|
|
1826
|
+
action: onLeave && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1827
|
+
ui.Button,
|
|
1828
|
+
{
|
|
1829
|
+
type: "button",
|
|
1830
|
+
variant: "outline",
|
|
1831
|
+
onClick: onLeave,
|
|
1832
|
+
"data-testid": "webinar-waiting-leave",
|
|
1833
|
+
children: leaveLabel
|
|
1834
|
+
}
|
|
1835
|
+
),
|
|
1836
|
+
children: (title || when || host) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-w-sm flex-col items-center gap-1 text-sm", children: [
|
|
1837
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", "data-testid": "webinar-waiting-title", children: title }),
|
|
1838
|
+
when && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", "data-testid": "webinar-waiting-when", children: when }),
|
|
1839
|
+
host && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1840
|
+
"p",
|
|
1841
|
+
{
|
|
1842
|
+
className: "flex flex-wrap items-center justify-center gap-1 text-muted-foreground",
|
|
1843
|
+
"data-testid": "webinar-waiting-host",
|
|
1844
|
+
children: [
|
|
1845
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Hosted by" }),
|
|
1846
|
+
host
|
|
1847
|
+
]
|
|
1848
|
+
}
|
|
1849
|
+
)
|
|
1850
|
+
] })
|
|
1851
|
+
}
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
function usePending() {
|
|
1855
|
+
const [keys, setKeys] = react.useState(() => /* @__PURE__ */ new Set());
|
|
1856
|
+
const mounted = react.useRef(true);
|
|
1857
|
+
react.useEffect(() => {
|
|
1858
|
+
mounted.current = true;
|
|
1859
|
+
return () => {
|
|
1860
|
+
mounted.current = false;
|
|
1861
|
+
};
|
|
1862
|
+
}, []);
|
|
1863
|
+
const set = react.useCallback((key, on) => {
|
|
1864
|
+
if (!mounted.current) return;
|
|
1865
|
+
setKeys((prev) => {
|
|
1866
|
+
if (prev.has(key) === on) return prev;
|
|
1867
|
+
const next = new Set(prev);
|
|
1868
|
+
if (on) next.add(key);
|
|
1869
|
+
else next.delete(key);
|
|
1870
|
+
return next;
|
|
1871
|
+
});
|
|
1872
|
+
}, []);
|
|
1873
|
+
const run = react.useCallback(
|
|
1874
|
+
async (key, fn) => {
|
|
1875
|
+
let result;
|
|
1876
|
+
try {
|
|
1877
|
+
result = fn();
|
|
1878
|
+
} catch {
|
|
1879
|
+
return false;
|
|
1880
|
+
}
|
|
1881
|
+
if (!result || typeof result.then !== "function") return true;
|
|
1882
|
+
set(key, true);
|
|
1883
|
+
try {
|
|
1884
|
+
await result;
|
|
1885
|
+
return true;
|
|
1886
|
+
} catch {
|
|
1887
|
+
return false;
|
|
1888
|
+
} finally {
|
|
1889
|
+
set(key, false);
|
|
1890
|
+
}
|
|
1891
|
+
},
|
|
1892
|
+
[set]
|
|
1893
|
+
);
|
|
1894
|
+
const isPending = react.useCallback((key) => keys.has(key), [keys]);
|
|
1895
|
+
return { isPending, run };
|
|
1896
|
+
}
|
|
1897
|
+
function useNow(ms = 3e4, fixed) {
|
|
1898
|
+
const [now, setNow] = react.useState(() => /* @__PURE__ */ new Date());
|
|
1899
|
+
const ticking = !fixed;
|
|
1900
|
+
react.useEffect(() => {
|
|
1901
|
+
if (!ticking) return;
|
|
1902
|
+
const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), ms);
|
|
1903
|
+
return () => clearInterval(id);
|
|
1904
|
+
}, [ms, ticking]);
|
|
1905
|
+
return fixed ?? now;
|
|
1906
|
+
}
|
|
1907
|
+
function WebinarLiveChip({
|
|
1908
|
+
compact = false,
|
|
1909
|
+
className
|
|
1910
|
+
}) {
|
|
1911
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1912
|
+
CallStatusChip,
|
|
1913
|
+
{
|
|
1914
|
+
tone: "red",
|
|
1915
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
1916
|
+
label: "Live",
|
|
1917
|
+
compact,
|
|
1918
|
+
title: "Live: attendees see and hear the stage",
|
|
1919
|
+
role: "status",
|
|
1920
|
+
className,
|
|
1921
|
+
testId: "webinar-live-chip"
|
|
1922
|
+
}
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
function WebinarLiveControl({
|
|
1926
|
+
live,
|
|
1927
|
+
onGoLive,
|
|
1928
|
+
onEnd,
|
|
1929
|
+
compact = false,
|
|
1930
|
+
className
|
|
1931
|
+
}) {
|
|
1932
|
+
const { isPending, run } = usePending();
|
|
1933
|
+
const [confirming, setConfirming] = react.useState(false);
|
|
1934
|
+
if (!live) {
|
|
1935
|
+
if (!onGoLive) return null;
|
|
1936
|
+
const busy = isPending("live");
|
|
1937
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1938
|
+
ui.Button,
|
|
1939
|
+
{
|
|
1940
|
+
type: "button",
|
|
1941
|
+
size: compact ? "icon" : "sm",
|
|
1942
|
+
className: ui.cn("h-8 shrink-0", !compact && "px-3", className),
|
|
1943
|
+
disabled: busy,
|
|
1944
|
+
"aria-label": "Go live",
|
|
1945
|
+
title: "Go live: let attendees see and hear the stage",
|
|
1946
|
+
onClick: () => void run("live", onGoLive),
|
|
1947
|
+
"data-testid": "webinar-go-live",
|
|
1948
|
+
children: [
|
|
1949
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-4", "aria-hidden": true }),
|
|
1950
|
+
!compact && "Go live"
|
|
1951
|
+
]
|
|
1952
|
+
}
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
if (!onEnd) return null;
|
|
1956
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1957
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1958
|
+
ui.Button,
|
|
1959
|
+
{
|
|
1960
|
+
type: "button",
|
|
1961
|
+
variant: "outline",
|
|
1962
|
+
size: compact ? "icon" : "default",
|
|
1963
|
+
className: ui.cn(
|
|
1964
|
+
"shrink-0 border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
|
|
1965
|
+
!compact && "px-4",
|
|
1966
|
+
className
|
|
1967
|
+
),
|
|
1968
|
+
"aria-label": "End webinar",
|
|
1969
|
+
title: "End webinar for everyone",
|
|
1970
|
+
onClick: () => setConfirming(true),
|
|
1971
|
+
"data-testid": "webinar-end",
|
|
1972
|
+
children: [
|
|
1973
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquareX, { className: "size-4", "aria-hidden": true }),
|
|
1974
|
+
!compact && "End webinar"
|
|
1975
|
+
]
|
|
1976
|
+
}
|
|
1977
|
+
),
|
|
1978
|
+
/* @__PURE__ */ jsxRuntime.jsx(WebinarEndConfirm, { open: confirming, onOpenChange: setConfirming, onEnd })
|
|
1979
|
+
] });
|
|
1980
|
+
}
|
|
1981
|
+
function WebinarEndConfirm({
|
|
1982
|
+
open,
|
|
1983
|
+
onOpenChange,
|
|
1984
|
+
onEnd
|
|
1985
|
+
}) {
|
|
1986
|
+
const { isPending, run } = usePending();
|
|
1987
|
+
const ending = isPending("end");
|
|
1988
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1989
|
+
chunkGICUGQNN_cjs.ConfirmDialog,
|
|
1990
|
+
{
|
|
1991
|
+
isOpen: open,
|
|
1992
|
+
onClose: () => onOpenChange(false),
|
|
1993
|
+
onConfirm: () => void run("end", onEnd).then((ok) => {
|
|
1994
|
+
if (ok) onOpenChange(false);
|
|
1995
|
+
}),
|
|
1996
|
+
title: "End the webinar?",
|
|
1997
|
+
description: "Everyone leaves, attendees and panelists alike. The stage closes and cannot be reopened in this session.",
|
|
1998
|
+
confirmText: "End webinar",
|
|
1999
|
+
isLoading: ending,
|
|
2000
|
+
testId: "webinar-end-confirm",
|
|
2001
|
+
testIds: { cancel: "webinar-end-cancel", confirm: "webinar-end-confirm-button" }
|
|
2002
|
+
}
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
function BackstageBanner({
|
|
2006
|
+
onGoLive,
|
|
2007
|
+
className
|
|
2008
|
+
}) {
|
|
2009
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2010
|
+
"div",
|
|
2011
|
+
{
|
|
2012
|
+
className: ui.cn(
|
|
2013
|
+
"flex min-h-10 min-w-0 items-center gap-2 rounded-md border border-yellow-border bg-yellow-bg py-1 pl-3 pr-1 text-sm text-yellow-text",
|
|
2014
|
+
className
|
|
2015
|
+
),
|
|
2016
|
+
role: "status",
|
|
2017
|
+
"data-testid": "webinar-backstage",
|
|
2018
|
+
children: [
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
2020
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
2021
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Backstage" }),
|
|
2022
|
+
" \u2014 attendees can't see or hear you yet",
|
|
2023
|
+
!onGoLive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-yellow-text/80", children: ". The host goes live when ready." })
|
|
2024
|
+
] }),
|
|
2025
|
+
onGoLive && /* @__PURE__ */ jsxRuntime.jsx(WebinarLiveControl, { live: false, onGoLive })
|
|
2026
|
+
]
|
|
2027
|
+
}
|
|
2028
|
+
);
|
|
2029
|
+
}
|
|
2030
|
+
function RaiseHandButton({
|
|
2031
|
+
raised,
|
|
2032
|
+
onToggle,
|
|
2033
|
+
pending = false,
|
|
2034
|
+
shortcut = "H",
|
|
2035
|
+
className
|
|
2036
|
+
}) {
|
|
2037
|
+
const { isPending, run } = usePending();
|
|
2038
|
+
const busy = pending || isPending("hand");
|
|
2039
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2040
|
+
CallControlButton,
|
|
2041
|
+
{
|
|
2042
|
+
label: raised ? "Lower hand" : "Raise hand",
|
|
2043
|
+
shortcut,
|
|
2044
|
+
tone: raised ? "active" : "neutral",
|
|
2045
|
+
"aria-pressed": raised,
|
|
2046
|
+
disabled: busy,
|
|
2047
|
+
"aria-busy": busy || void 0,
|
|
2048
|
+
onClick: () => void run("hand", () => onToggle(!raised)),
|
|
2049
|
+
className,
|
|
2050
|
+
"data-testid": "webinar-raise-hand",
|
|
2051
|
+
"data-raised": raised,
|
|
2052
|
+
"data-call-shortcut": shortcut.toLowerCase(),
|
|
2053
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { "aria-hidden": true })
|
|
2054
|
+
}
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
var ROLE_NOTE = {
|
|
2058
|
+
host: "Host",
|
|
2059
|
+
cohost: "Co-host",
|
|
2060
|
+
panelist: "Panelist",
|
|
2061
|
+
attendee: null
|
|
2062
|
+
};
|
|
2063
|
+
function SectionTitle({ children }) {
|
|
2064
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "flex items-center gap-1.5 px-2 pb-1 pt-3 text-xs font-medium text-muted-foreground", children });
|
|
2065
|
+
}
|
|
2066
|
+
function Row({ testId, children }) {
|
|
2067
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2068
|
+
"li",
|
|
2069
|
+
{
|
|
2070
|
+
className: "flex min-h-11 items-center gap-3 rounded-md px-2 py-1 hover:bg-muted",
|
|
2071
|
+
"data-testid": testId,
|
|
2072
|
+
children
|
|
2073
|
+
}
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
function WebinarAudiencePanel({
|
|
2077
|
+
hands,
|
|
2078
|
+
attendees,
|
|
2079
|
+
onPromote,
|
|
2080
|
+
onDemote,
|
|
2081
|
+
searchThreshold = 8,
|
|
2082
|
+
now: fixedNow,
|
|
2083
|
+
className
|
|
2084
|
+
}) {
|
|
2085
|
+
const now = useNow(3e4, fixedNow);
|
|
2086
|
+
const { isPending, run } = usePending();
|
|
2087
|
+
const [query, setQuery] = react.useState("");
|
|
2088
|
+
const queue = react.useMemo(
|
|
2089
|
+
() => [...hands].sort((a, b) => Date.parse(a.raisedAt) - Date.parse(b.raisedAt)),
|
|
2090
|
+
[hands]
|
|
2091
|
+
);
|
|
2092
|
+
const searchable = attendees.length > searchThreshold;
|
|
2093
|
+
const q = searchable ? query.trim().toLowerCase() : "";
|
|
2094
|
+
const shown = q ? attendees.filter((a) => a.name.toLowerCase().includes(q)) : attendees;
|
|
2095
|
+
const action = (id, name, promote, where) => {
|
|
2096
|
+
const key = `${promote ? "promote" : "demote"}:${id}`;
|
|
2097
|
+
const busy = isPending(key);
|
|
2098
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2099
|
+
ui.Button,
|
|
2100
|
+
{
|
|
2101
|
+
type: "button",
|
|
2102
|
+
variant: "outline",
|
|
2103
|
+
size: "sm",
|
|
2104
|
+
className: "h-8 shrink-0",
|
|
2105
|
+
disabled: busy,
|
|
2106
|
+
"aria-label": promote ? `Promote ${name} to the stage` : `Move ${name} to the audience`,
|
|
2107
|
+
onClick: () => void run(key, () => promote ? onPromote(id) : onDemote(id)),
|
|
2108
|
+
"data-testid": `webinar-${where === "hand" ? "hand-" : ""}${promote ? "promote" : "demote"}-${id}`,
|
|
2109
|
+
children: [
|
|
2110
|
+
busy && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
2111
|
+
promote ? "Promote" : "Move to audience"
|
|
2112
|
+
]
|
|
2113
|
+
}
|
|
2114
|
+
);
|
|
2115
|
+
};
|
|
2116
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2117
|
+
"div",
|
|
2118
|
+
{
|
|
2119
|
+
className: ui.cn("min-h-0 flex-1 overflow-y-auto px-2 pb-2", className),
|
|
2120
|
+
"data-testid": "webinar-audience",
|
|
2121
|
+
children: [
|
|
2122
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Raised hands", children: [
|
|
2123
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
|
|
2124
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hand, { className: "size-3.5", "aria-hidden": true }),
|
|
2125
|
+
"Raised hands (",
|
|
2126
|
+
queue.length,
|
|
2127
|
+
")"
|
|
2128
|
+
] }),
|
|
2129
|
+
queue.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-2 py-2 text-sm text-muted-foreground", "data-testid": "webinar-hands-empty", children: "No hands raised." }) : /* @__PURE__ */ jsxRuntime.jsx("ol", { children: queue.map((h) => /* @__PURE__ */ jsxRuntime.jsxs(Row, { testId: `webinar-hand-${h.id}`, children: [
|
|
2130
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
2131
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex min-w-0 items-center gap-1.5 text-sm", children: /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: h.name, entity: h.entity }) }),
|
|
2132
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
2133
|
+
"Raised ",
|
|
2134
|
+
chunkKDG6FER6_cjs.fromNow(h.raisedAt, now)
|
|
2135
|
+
] })
|
|
2136
|
+
] }),
|
|
2137
|
+
action(h.id, h.name, true, "hand")
|
|
2138
|
+
] }, h.id)) })
|
|
2139
|
+
] }),
|
|
2140
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Attendees", children: [
|
|
2141
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SectionTitle, { children: [
|
|
2142
|
+
"Attendees (",
|
|
2143
|
+
attendees.length,
|
|
2144
|
+
")"
|
|
2145
|
+
] }),
|
|
2146
|
+
searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative px-2 pb-1", children: [
|
|
2147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2148
|
+
lucideReact.Search,
|
|
2149
|
+
{
|
|
2150
|
+
className: "pointer-events-none absolute left-4.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground",
|
|
2151
|
+
"aria-hidden": true
|
|
2152
|
+
}
|
|
2153
|
+
),
|
|
2154
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2155
|
+
ui.Input,
|
|
2156
|
+
{
|
|
2157
|
+
type: "search",
|
|
2158
|
+
value: query,
|
|
2159
|
+
onChange: (e) => setQuery(e.target.value),
|
|
2160
|
+
placeholder: "Find someone",
|
|
2161
|
+
"aria-label": "Find an attendee",
|
|
2162
|
+
className: "h-8 pl-8 text-sm",
|
|
2163
|
+
"data-testid": "webinar-attendee-search"
|
|
2164
|
+
}
|
|
2165
|
+
)
|
|
2166
|
+
] }),
|
|
2167
|
+
shown.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2168
|
+
"p",
|
|
2169
|
+
{
|
|
2170
|
+
className: "px-2 py-2 text-sm text-muted-foreground",
|
|
2171
|
+
"data-testid": "webinar-attendees-empty",
|
|
2172
|
+
children: q ? `No one matches \u201C${query.trim()}\u201D.` : "No attendees yet."
|
|
2173
|
+
}
|
|
2174
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("ul", { children: shown.map((a) => {
|
|
2175
|
+
const note = ROLE_NOTE[a.role];
|
|
2176
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Row, { testId: `webinar-attendee-${a.id}`, children: [
|
|
2177
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-sm", children: [
|
|
2178
|
+
/* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: a.name, entity: a.entity }),
|
|
2179
|
+
(note || a.onStage) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: [note, a.onStage ? "On stage" : null].filter(Boolean).join(" \xB7 ") })
|
|
2180
|
+
] }),
|
|
2181
|
+
a.handRaised && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2182
|
+
lucideReact.Hand,
|
|
2183
|
+
{
|
|
2184
|
+
className: "size-4 shrink-0 text-primary",
|
|
2185
|
+
"aria-label": "Hand raised",
|
|
2186
|
+
"data-testid": `webinar-attendee-hand-${a.id}`
|
|
2187
|
+
}
|
|
2188
|
+
),
|
|
2189
|
+
a.onStage ? a.role !== "host" && action(a.id, a.name, false, "list") : !a.handRaised && action(a.id, a.name, true, "list")
|
|
2190
|
+
] }, a.id);
|
|
2191
|
+
}) })
|
|
2192
|
+
] })
|
|
2193
|
+
]
|
|
2194
|
+
}
|
|
2195
|
+
);
|
|
2196
|
+
}
|
|
2197
|
+
var DEFAULT_MAX = 500;
|
|
2198
|
+
function sortQuestions(questions, filter) {
|
|
2199
|
+
const match = (s) => filter === "open" ? s === "open" || s === "answering" : s === filter;
|
|
2200
|
+
return questions.filter((q) => match(q.status)).sort(
|
|
2201
|
+
(a, b) => Number(b.status === "answering") - Number(a.status === "answering") || b.voteCount - a.voteCount || Date.parse(a.createdAt) - Date.parse(b.createdAt)
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
function PanelComposer({
|
|
2205
|
+
placeholder,
|
|
2206
|
+
ariaLabel,
|
|
2207
|
+
sendLabel,
|
|
2208
|
+
maxLength,
|
|
2209
|
+
busy,
|
|
2210
|
+
onSend,
|
|
2211
|
+
onCancel,
|
|
2212
|
+
autoFocus,
|
|
2213
|
+
testId
|
|
2214
|
+
}) {
|
|
2215
|
+
const [text, setText] = react.useState("");
|
|
2216
|
+
const body = text.trim();
|
|
2217
|
+
const canSend = !!body && body.length <= maxLength && !busy;
|
|
2218
|
+
const send = () => {
|
|
2219
|
+
if (!canSend) return;
|
|
2220
|
+
void onSend(body).then((ok) => {
|
|
2221
|
+
if (ok) setText("");
|
|
2222
|
+
});
|
|
2223
|
+
};
|
|
2224
|
+
const onKeyDown = (e) => {
|
|
2225
|
+
if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
2226
|
+
e.preventDefault();
|
|
2227
|
+
send();
|
|
2228
|
+
} else if (e.key === "Escape" && onCancel) {
|
|
2229
|
+
e.preventDefault();
|
|
2230
|
+
onCancel();
|
|
2231
|
+
}
|
|
2232
|
+
};
|
|
2233
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": testId, children: [
|
|
2234
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2235
|
+
ui.Textarea,
|
|
2236
|
+
{
|
|
2237
|
+
value: text,
|
|
2238
|
+
onChange: (e) => setText(e.target.value),
|
|
2239
|
+
onKeyDown,
|
|
2240
|
+
placeholder,
|
|
2241
|
+
"aria-label": ariaLabel,
|
|
2242
|
+
maxLength,
|
|
2243
|
+
rows: 2,
|
|
2244
|
+
disabled: busy,
|
|
2245
|
+
autoFocus,
|
|
2246
|
+
className: "min-h-[60px] resize-none",
|
|
2247
|
+
"data-testid": `${testId}-input`
|
|
2248
|
+
}
|
|
2249
|
+
),
|
|
2250
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2252
|
+
"span",
|
|
2253
|
+
{
|
|
2254
|
+
className: ui.cn(
|
|
2255
|
+
"flex-1 text-xs tabular-nums text-muted-foreground",
|
|
2256
|
+
text.length >= maxLength && "text-red-text"
|
|
2257
|
+
),
|
|
2258
|
+
"aria-live": "polite",
|
|
2259
|
+
"data-testid": `${testId}-count`,
|
|
2260
|
+
children: [
|
|
2261
|
+
text.length,
|
|
2262
|
+
"/",
|
|
2263
|
+
maxLength
|
|
2264
|
+
]
|
|
2265
|
+
}
|
|
2266
|
+
),
|
|
2267
|
+
onCancel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2268
|
+
ui.Button,
|
|
2269
|
+
{
|
|
2270
|
+
type: "button",
|
|
2271
|
+
variant: "ghost",
|
|
2272
|
+
size: "sm",
|
|
2273
|
+
className: "h-8",
|
|
2274
|
+
onClick: onCancel,
|
|
2275
|
+
disabled: busy,
|
|
2276
|
+
"data-testid": `${testId}-cancel`,
|
|
2277
|
+
children: "Cancel"
|
|
2278
|
+
}
|
|
2279
|
+
),
|
|
2280
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2281
|
+
ui.Button,
|
|
2282
|
+
{
|
|
2283
|
+
type: "button",
|
|
2284
|
+
size: "sm",
|
|
2285
|
+
className: "h-8",
|
|
2286
|
+
onClick: send,
|
|
2287
|
+
disabled: !canSend,
|
|
2288
|
+
"data-testid": `${testId}-send`,
|
|
2289
|
+
children: [
|
|
2290
|
+
busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "size-4", "aria-hidden": true }),
|
|
2291
|
+
sendLabel
|
|
2292
|
+
]
|
|
2293
|
+
}
|
|
2294
|
+
)
|
|
2295
|
+
] })
|
|
2296
|
+
] });
|
|
2297
|
+
}
|
|
2298
|
+
function QuestionItem({
|
|
2299
|
+
q,
|
|
2300
|
+
team,
|
|
2301
|
+
now,
|
|
2302
|
+
maxLength,
|
|
2303
|
+
pending,
|
|
2304
|
+
run,
|
|
2305
|
+
onVote,
|
|
2306
|
+
onStatusChange,
|
|
2307
|
+
onAnswer,
|
|
2308
|
+
onDelete
|
|
2309
|
+
}) {
|
|
2310
|
+
const [answering, setAnswering] = react.useState(false);
|
|
2311
|
+
const voteKey = `vote:${q.id}`;
|
|
2312
|
+
const statusKey = `status:${q.id}`;
|
|
2313
|
+
const answerKey = `answer:${q.id}`;
|
|
2314
|
+
const busy = pending(statusKey) || pending(answerKey) || pending(`delete:${q.id}`);
|
|
2315
|
+
const setStatus = (status) => () => onStatusChange ? onStatusChange(q, status) : void 0;
|
|
2316
|
+
const can = team && !!onStatusChange;
|
|
2317
|
+
const primary = !can ? null : q.status === "open" ? { key: "live", label: "Answer live", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, {}), run: setStatus("answering") } : q.status === "answering" ? {
|
|
2318
|
+
key: "answered",
|
|
2319
|
+
label: "Mark answered",
|
|
2320
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, {}),
|
|
2321
|
+
run: setStatus("answered")
|
|
2322
|
+
} : { key: "reopen", label: "Reopen", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, {}), run: setStatus("open") };
|
|
2323
|
+
const more = [
|
|
2324
|
+
...can && q.status === "open" ? [
|
|
2325
|
+
{
|
|
2326
|
+
key: "answered",
|
|
2327
|
+
label: "Mark answered",
|
|
2328
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, {}),
|
|
2329
|
+
run: setStatus("answered")
|
|
2330
|
+
}
|
|
2331
|
+
] : [],
|
|
2332
|
+
...can && q.status === "answering" ? [{ key: "reopen", label: "Reopen", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, {}), run: setStatus("open") }] : [],
|
|
2333
|
+
...can && q.status !== "dismissed" ? [{ key: "dismiss", label: "Dismiss", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, {}), run: setStatus("dismissed") }] : [],
|
|
2334
|
+
...q.mine && q.status === "open" && onDelete ? [
|
|
2335
|
+
{
|
|
2336
|
+
key: "delete",
|
|
2337
|
+
label: "Delete question",
|
|
2338
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, {}),
|
|
2339
|
+
run: () => onDelete(q),
|
|
2340
|
+
destructive: true
|
|
2341
|
+
}
|
|
2342
|
+
] : []
|
|
2343
|
+
];
|
|
2344
|
+
const canAnswerInText = team && !!onAnswer && !q.answer && q.status !== "dismissed";
|
|
2345
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2346
|
+
"li",
|
|
2347
|
+
{
|
|
2348
|
+
className: "flex gap-2 rounded-md border border-border p-2",
|
|
2349
|
+
"data-testid": `webinar-question-${q.id}`,
|
|
2350
|
+
"data-status": q.status,
|
|
2351
|
+
children: [
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2353
|
+
ui.Button,
|
|
2354
|
+
{
|
|
2355
|
+
type: "button",
|
|
2356
|
+
variant: "ghost",
|
|
2357
|
+
className: ui.cn(
|
|
2358
|
+
"h-auto w-10 shrink-0 flex-col gap-0 self-start px-0 py-1 text-xs tabular-nums",
|
|
2359
|
+
q.voted ? "bg-primary/10 text-primary hover:bg-primary/15" : "text-muted-foreground"
|
|
2360
|
+
),
|
|
2361
|
+
"aria-pressed": q.voted,
|
|
2362
|
+
"aria-label": q.mine ? `${q.voteCount} upvotes (your question)` : q.voted ? `Remove upvote (${q.voteCount})` : `Upvote (${q.voteCount})`,
|
|
2363
|
+
title: q.mine ? "You can't upvote your own question" : void 0,
|
|
2364
|
+
disabled: q.mine || pending(voteKey),
|
|
2365
|
+
onClick: () => void run(voteKey, () => onVote(q, !q.voted)),
|
|
2366
|
+
"data-testid": `webinar-question-vote-${q.id}`,
|
|
2367
|
+
children: [
|
|
2368
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4", "aria-hidden": true }),
|
|
2369
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": `webinar-question-votes-${q.id}`, children: q.voteCount })
|
|
2370
|
+
]
|
|
2371
|
+
}
|
|
2372
|
+
),
|
|
2373
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
|
|
2374
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [
|
|
2375
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2376
|
+
"span",
|
|
2377
|
+
{
|
|
2378
|
+
className: "flex min-w-0 items-center gap-1.5 text-sm text-foreground",
|
|
2379
|
+
"data-testid": `webinar-question-asker-${q.id}`,
|
|
2380
|
+
children: q.askerName === null && !q.asker ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Attendee" }) : /* @__PURE__ */ jsxRuntime.jsx(CallPersonLabel, { name: q.askerName ?? "", entity: q.asker, isLocal: q.mine })
|
|
2381
|
+
}
|
|
2382
|
+
),
|
|
2383
|
+
/* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: q.createdAt, children: chunkKDG6FER6_cjs.fromNow(q.createdAt, now) }),
|
|
2384
|
+
q.status === "answering" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2385
|
+
CallStatusChip,
|
|
2386
|
+
{
|
|
2387
|
+
tone: "red",
|
|
2388
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Radio, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
2389
|
+
label: "Answering live",
|
|
2390
|
+
testId: `webinar-question-live-${q.id}`
|
|
2391
|
+
}
|
|
2392
|
+
),
|
|
2393
|
+
q.status === "answered" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2394
|
+
CallStatusChip,
|
|
2395
|
+
{
|
|
2396
|
+
tone: "green",
|
|
2397
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
2398
|
+
label: "Answered",
|
|
2399
|
+
testId: `webinar-question-answered-${q.id}`
|
|
2400
|
+
}
|
|
2401
|
+
),
|
|
2402
|
+
q.status === "dismissed" && /* @__PURE__ */ jsxRuntime.jsx(CallStatusChip, { tone: "neutral", label: "Dismissed" })
|
|
2403
|
+
] }),
|
|
2404
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2405
|
+
"p",
|
|
2406
|
+
{
|
|
2407
|
+
className: "whitespace-pre-wrap break-words text-sm",
|
|
2408
|
+
"data-testid": `webinar-question-body-${q.id}`,
|
|
2409
|
+
children: q.body
|
|
2410
|
+
}
|
|
2411
|
+
),
|
|
2412
|
+
q.answer && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2413
|
+
"div",
|
|
2414
|
+
{
|
|
2415
|
+
className: "flex flex-col gap-1 rounded-md bg-muted px-2.5 py-2 text-sm",
|
|
2416
|
+
"data-testid": `webinar-question-answer-${q.id}`,
|
|
2417
|
+
children: [
|
|
2418
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
2419
|
+
"Answer",
|
|
2420
|
+
q.answeredBy
|
|
2421
|
+
] }),
|
|
2422
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap break-words", children: q.answer })
|
|
2423
|
+
]
|
|
2424
|
+
}
|
|
2425
|
+
),
|
|
2426
|
+
answering && onAnswer && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2427
|
+
PanelComposer,
|
|
2428
|
+
{
|
|
2429
|
+
placeholder: "Write an answer",
|
|
2430
|
+
ariaLabel: "Answer in text",
|
|
2431
|
+
sendLabel: "Send answer",
|
|
2432
|
+
maxLength,
|
|
2433
|
+
busy: pending(answerKey),
|
|
2434
|
+
autoFocus: true,
|
|
2435
|
+
onSend: (text) => run(answerKey, () => onAnswer(q, text)).then((ok) => {
|
|
2436
|
+
if (ok) setAnswering(false);
|
|
2437
|
+
return ok;
|
|
2438
|
+
}),
|
|
2439
|
+
onCancel: () => setAnswering(false),
|
|
2440
|
+
testId: `webinar-answer-${q.id}`
|
|
2441
|
+
}
|
|
2442
|
+
),
|
|
2443
|
+
(primary || canAnswerInText || more.length > 0) && !answering && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2444
|
+
primary && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2445
|
+
ui.Button,
|
|
2446
|
+
{
|
|
2447
|
+
type: "button",
|
|
2448
|
+
variant: "outline",
|
|
2449
|
+
size: "sm",
|
|
2450
|
+
className: "h-7 gap-1.5 px-2 text-xs [&_svg]:size-3.5",
|
|
2451
|
+
disabled: busy,
|
|
2452
|
+
onClick: () => void run(statusKey, primary.run),
|
|
2453
|
+
"data-testid": `webinar-question-${primary.key}-${q.id}`,
|
|
2454
|
+
children: [
|
|
2455
|
+
pending(statusKey) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "animate-spin", "aria-hidden": true }) : primary.icon,
|
|
2456
|
+
primary.label
|
|
2457
|
+
]
|
|
2458
|
+
}
|
|
2459
|
+
),
|
|
2460
|
+
canAnswerInText && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2461
|
+
ui.Button,
|
|
2462
|
+
{
|
|
2463
|
+
type: "button",
|
|
2464
|
+
variant: "ghost",
|
|
2465
|
+
size: "sm",
|
|
2466
|
+
className: "h-7 gap-1.5 px-2 text-xs [&_svg]:size-3.5",
|
|
2467
|
+
disabled: busy,
|
|
2468
|
+
onClick: () => setAnswering(true),
|
|
2469
|
+
"data-testid": `webinar-question-answer-text-${q.id}`,
|
|
2470
|
+
children: [
|
|
2471
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquareText, { "aria-hidden": true }),
|
|
2472
|
+
"Answer in text"
|
|
2473
|
+
]
|
|
2474
|
+
}
|
|
2475
|
+
),
|
|
2476
|
+
more.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
2477
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2478
|
+
ui.Button,
|
|
2479
|
+
{
|
|
2480
|
+
type: "button",
|
|
2481
|
+
variant: "ghost",
|
|
2482
|
+
size: "icon",
|
|
2483
|
+
className: "ml-auto size-7 text-muted-foreground hover:text-foreground",
|
|
2484
|
+
"aria-label": "More question actions",
|
|
2485
|
+
disabled: busy,
|
|
2486
|
+
"data-testid": `webinar-question-menu-${q.id}`,
|
|
2487
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
|
|
2488
|
+
}
|
|
2489
|
+
) }),
|
|
2490
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "end", className: "w-48", children: more.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2491
|
+
ui.DropdownMenuItem,
|
|
2492
|
+
{
|
|
2493
|
+
onSelect: () => void run(a.key === "delete" ? `delete:${q.id}` : statusKey, a.run),
|
|
2494
|
+
className: ui.cn(a.destructive && "text-destructive focus:text-destructive"),
|
|
2495
|
+
"data-testid": `webinar-question-${a.key}-${q.id}`,
|
|
2496
|
+
children: [
|
|
2497
|
+
a.icon,
|
|
2498
|
+
a.label
|
|
2499
|
+
]
|
|
2500
|
+
},
|
|
2501
|
+
a.key
|
|
2502
|
+
)) })
|
|
2503
|
+
] })
|
|
2504
|
+
] })
|
|
2505
|
+
] })
|
|
2506
|
+
]
|
|
2507
|
+
}
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
var EMPTY = {
|
|
2511
|
+
open: {
|
|
2512
|
+
team: "Questions from the audience appear here.",
|
|
2513
|
+
audience: "No questions yet. Ask the first one."
|
|
2514
|
+
},
|
|
2515
|
+
answered: { team: "No answered questions yet.", audience: "No answered questions yet." },
|
|
2516
|
+
dismissed: { team: "Nothing dismissed.", audience: "Nothing dismissed." }
|
|
2517
|
+
};
|
|
2518
|
+
function QAPanel({
|
|
2519
|
+
questions,
|
|
2520
|
+
team = false,
|
|
2521
|
+
maxLength = DEFAULT_MAX,
|
|
2522
|
+
canAsk = true,
|
|
2523
|
+
onAsk,
|
|
2524
|
+
onVote,
|
|
2525
|
+
onStatusChange,
|
|
2526
|
+
onAnswer,
|
|
2527
|
+
onDelete,
|
|
2528
|
+
defaultFilter = "open",
|
|
2529
|
+
now: fixedNow,
|
|
2530
|
+
className
|
|
2531
|
+
}) {
|
|
2532
|
+
const now = useNow(3e4, fixedNow);
|
|
2533
|
+
const { isPending, run } = usePending();
|
|
2534
|
+
const [filter, setFilter] = react.useState(
|
|
2535
|
+
defaultFilter === "dismissed" && !team ? "open" : defaultFilter
|
|
2536
|
+
);
|
|
2537
|
+
const filters = [
|
|
2538
|
+
{ id: "open", label: "Open" },
|
|
2539
|
+
{ id: "answered", label: "Answered" },
|
|
2540
|
+
...team ? [{ id: "dismissed", label: "Dismissed" }] : []
|
|
2541
|
+
];
|
|
2542
|
+
const lists = react.useMemo(
|
|
2543
|
+
() => ({
|
|
2544
|
+
open: sortQuestions(questions, "open"),
|
|
2545
|
+
answered: sortQuestions(questions, "answered"),
|
|
2546
|
+
// Dismissed questions are the team's business only.
|
|
2547
|
+
dismissed: team ? sortQuestions(questions, "dismissed") : []
|
|
2548
|
+
}),
|
|
2549
|
+
[questions, team]
|
|
2550
|
+
);
|
|
2551
|
+
const shown = lists[filter];
|
|
2552
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex min-h-0 flex-1 flex-col", className), "data-testid": "webinar-qa", children: [
|
|
2553
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2554
|
+
ui.Tabs,
|
|
2555
|
+
{
|
|
2556
|
+
value: filter,
|
|
2557
|
+
onValueChange: (v) => setFilter(v),
|
|
2558
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
2559
|
+
children: [
|
|
2560
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-3 pt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.TabsList, { className: "h-8 w-full", children: filters.map((f) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2561
|
+
ui.TabsTrigger,
|
|
2562
|
+
{
|
|
2563
|
+
value: f.id,
|
|
2564
|
+
className: "h-6 flex-1 gap-1.5 px-2 text-xs",
|
|
2565
|
+
"data-testid": `webinar-qa-filter-${f.id}`,
|
|
2566
|
+
children: [
|
|
2567
|
+
f.label,
|
|
2568
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums text-muted-foreground", children: lists[f.id].length })
|
|
2569
|
+
]
|
|
2570
|
+
},
|
|
2571
|
+
f.id
|
|
2572
|
+
)) }) }),
|
|
2573
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TabsContent, { value: filter, className: "mt-0 min-h-0 flex-1 overflow-y-auto p-3", children: shown.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2574
|
+
"p",
|
|
2575
|
+
{
|
|
2576
|
+
className: "py-6 text-center text-sm text-muted-foreground",
|
|
2577
|
+
"data-testid": "webinar-qa-empty",
|
|
2578
|
+
children: filter === "open" && questions.length > 0 ? "No open questions right now." : EMPTY[filter][team ? "team" : "audience"]
|
|
2579
|
+
}
|
|
2580
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex flex-col gap-2", children: shown.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2581
|
+
QuestionItem,
|
|
2582
|
+
{
|
|
2583
|
+
q,
|
|
2584
|
+
team,
|
|
2585
|
+
now,
|
|
2586
|
+
maxLength,
|
|
2587
|
+
pending: isPending,
|
|
2588
|
+
run,
|
|
2589
|
+
onVote,
|
|
2590
|
+
onStatusChange,
|
|
2591
|
+
onAnswer,
|
|
2592
|
+
onDelete
|
|
2593
|
+
},
|
|
2594
|
+
q.id
|
|
2595
|
+
)) }) })
|
|
2596
|
+
]
|
|
2597
|
+
}
|
|
2598
|
+
),
|
|
2599
|
+
canAsk && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t border-border p-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2600
|
+
PanelComposer,
|
|
2601
|
+
{
|
|
2602
|
+
placeholder: "Ask a question",
|
|
2603
|
+
ariaLabel: "Ask a question",
|
|
2604
|
+
sendLabel: "Ask",
|
|
2605
|
+
maxLength,
|
|
2606
|
+
busy: isPending("ask"),
|
|
2607
|
+
onSend: (text) => run("ask", () => onAsk(text)),
|
|
2608
|
+
testId: "webinar-ask"
|
|
2609
|
+
}
|
|
2610
|
+
) })
|
|
2611
|
+
] });
|
|
2612
|
+
}
|
|
2613
|
+
var OPTIONS = [
|
|
2614
|
+
{ value: "panelists", label: "Panelists only" },
|
|
2615
|
+
{ value: "everyone", label: "Everyone" }
|
|
2616
|
+
];
|
|
2617
|
+
function ChatPermissionSetting({
|
|
2618
|
+
value,
|
|
2619
|
+
onChange,
|
|
2620
|
+
pending = false
|
|
2621
|
+
}) {
|
|
2622
|
+
const [choosing, setChoosing] = react.useState(null);
|
|
2623
|
+
const busy = pending || choosing !== null;
|
|
2624
|
+
const select = (next) => {
|
|
2625
|
+
const v = next;
|
|
2626
|
+
if (v === value || busy) return;
|
|
2627
|
+
const result = onChange(v);
|
|
2628
|
+
if (result && typeof result.then === "function") {
|
|
2629
|
+
setChoosing(v);
|
|
2630
|
+
void result.then(
|
|
2631
|
+
() => setChoosing(null),
|
|
2632
|
+
() => setChoosing(null)
|
|
2633
|
+
);
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Who can chat", "data-testid": "webinar-chat-permission", children: [
|
|
2637
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuLabel, { className: "flex items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
2638
|
+
"Who can chat",
|
|
2639
|
+
busy && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin", "aria-label": "Saving" })
|
|
2640
|
+
] }),
|
|
2641
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuRadioGroup, { value: choosing ?? value, onValueChange: select, children: OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2642
|
+
ui.DropdownMenuRadioItem,
|
|
2643
|
+
{
|
|
2644
|
+
value: o.value,
|
|
2645
|
+
disabled: busy,
|
|
2646
|
+
"data-testid": `webinar-chat-${o.value}`,
|
|
2647
|
+
children: o.label
|
|
2648
|
+
},
|
|
2649
|
+
o.value
|
|
2650
|
+
)) })
|
|
2651
|
+
] });
|
|
2652
|
+
}
|
|
2653
|
+
function chatPermissionSection(props) {
|
|
2654
|
+
return { key: "webinar-chat", content: /* @__PURE__ */ jsxRuntime.jsx(ChatPermissionSetting, { ...props }) };
|
|
2655
|
+
}
|
|
2656
|
+
function OnStageCheck({
|
|
2657
|
+
open,
|
|
2658
|
+
onJoinStage,
|
|
2659
|
+
onStayInAudience,
|
|
2660
|
+
busy = false,
|
|
2661
|
+
error,
|
|
2662
|
+
mirror = true,
|
|
2663
|
+
describeError = describeMediaError
|
|
2664
|
+
}) {
|
|
2665
|
+
const { isPending, run } = usePending();
|
|
2666
|
+
const working = busy || isPending("join") || isPending("stay");
|
|
2667
|
+
const stay = () => {
|
|
2668
|
+
if (!working) void run("stay", onStayInAudience);
|
|
2669
|
+
};
|
|
2670
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open, onOpenChange: (next) => !next && stay(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.DialogContent, { presentation: "sheet", className: "max-w-3xl", "data-testid": "webinar-on-stage", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2671
|
+
PreJoin,
|
|
2672
|
+
{
|
|
2673
|
+
heading: "You're on stage",
|
|
2674
|
+
headingAs: ui.DialogTitle,
|
|
2675
|
+
joinLabel: "Join stage",
|
|
2676
|
+
cancelLabel: "Stay in audience",
|
|
2677
|
+
busy: working,
|
|
2678
|
+
error,
|
|
2679
|
+
mirror,
|
|
2680
|
+
describeError,
|
|
2681
|
+
onJoin: (choices) => void run("join", () => onJoinStage(choices)),
|
|
2682
|
+
onCancel: stay,
|
|
2683
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: "A host invited you to speak. Check your microphone and camera: once you join, everyone sees and hears you." })
|
|
2684
|
+
}
|
|
2685
|
+
) }) });
|
|
2686
|
+
}
|
|
2687
|
+
function WebinarViewer({
|
|
2688
|
+
header,
|
|
2689
|
+
stage,
|
|
2690
|
+
stageRef,
|
|
2691
|
+
stageOverlay,
|
|
2692
|
+
captions,
|
|
2693
|
+
side,
|
|
2694
|
+
sideToggle,
|
|
2695
|
+
hand,
|
|
2696
|
+
onLeave,
|
|
2697
|
+
left,
|
|
2698
|
+
controls,
|
|
2699
|
+
shortcuts = true,
|
|
2700
|
+
className
|
|
2701
|
+
}) {
|
|
2702
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2703
|
+
"div",
|
|
2704
|
+
{
|
|
2705
|
+
className: ui.cn(
|
|
2706
|
+
"@container flex size-full min-h-0 flex-col bg-background text-foreground",
|
|
2707
|
+
className
|
|
2708
|
+
),
|
|
2709
|
+
"data-testid": "webinar-viewer",
|
|
2710
|
+
children: [
|
|
2711
|
+
header,
|
|
2712
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex min-h-0 flex-1", children: [
|
|
2713
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col gap-2 px-3 pb-3 pt-1", children: [
|
|
2714
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { ref: stageRef, className: "relative min-h-0 flex-1", "data-testid": "call-stage", children: [
|
|
2715
|
+
stage,
|
|
2716
|
+
stageOverlay
|
|
2717
|
+
] }),
|
|
2718
|
+
captions
|
|
2719
|
+
] }),
|
|
2720
|
+
side && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2721
|
+
"div",
|
|
2722
|
+
{
|
|
2723
|
+
className: "absolute inset-0 z-20 flex min-h-0 flex-col border-t border-border motion-safe:animate-in motion-safe:fade-in-0 @3xl:static @3xl:z-auto @3xl:w-80 @3xl:shrink-0 @3xl:border-l @3xl:border-t-0",
|
|
2724
|
+
"data-testid": "webinar-viewer-side",
|
|
2725
|
+
children: side
|
|
2726
|
+
}
|
|
2727
|
+
)
|
|
2728
|
+
] }),
|
|
2729
|
+
/* @__PURE__ */ jsxRuntime.jsx(CallControlBar, { shortcuts, left, right: /* @__PURE__ */ jsxRuntime.jsx(LeaveButton, { onLeave }), children: /* @__PURE__ */ jsxRuntime.jsxs(ControlGroup, { children: [
|
|
2730
|
+
/* @__PURE__ */ jsxRuntime.jsx(RaiseHandButton, { ...hand }),
|
|
2731
|
+
sideToggle && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2732
|
+
CallControlButton,
|
|
2733
|
+
{
|
|
2734
|
+
label: sideToggle.open ? `Close ${sideToggle.label}` : sideToggle.label,
|
|
2735
|
+
tone: sideToggle.open ? "active" : "neutral",
|
|
2736
|
+
"aria-pressed": sideToggle.open,
|
|
2737
|
+
onClick: sideToggle.onToggle,
|
|
2738
|
+
"data-testid": "webinar-side-toggle",
|
|
2739
|
+
children: [
|
|
2740
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleQuestion, { "aria-hidden": true }),
|
|
2741
|
+
!!sideToggle.count && /* @__PURE__ */ jsxRuntime.jsx(ControlBadge, { count: sideToggle.count, tone: "quiet" })
|
|
2742
|
+
]
|
|
2743
|
+
}
|
|
2744
|
+
),
|
|
2745
|
+
controls
|
|
2746
|
+
] }) })
|
|
2747
|
+
]
|
|
2748
|
+
}
|
|
2749
|
+
);
|
|
2750
|
+
}
|
|
1735
2751
|
|
|
1736
2752
|
Object.defineProperty(exports, "CAPTION_LINES", {
|
|
1737
2753
|
enumerable: true,
|
|
@@ -1813,6 +2829,7 @@ Object.defineProperty(exports, "stageContentHeight", {
|
|
|
1813
2829
|
enumerable: true,
|
|
1814
2830
|
get: function () { return chunkMWDW5UBW_cjs.stageContentHeight; }
|
|
1815
2831
|
});
|
|
2832
|
+
exports.BackstageBanner = BackstageBanner;
|
|
1816
2833
|
exports.CallControlBar = CallControlBar;
|
|
1817
2834
|
exports.CallControlButton = CallControlButton;
|
|
1818
2835
|
exports.CallFocus = CallFocus;
|
|
@@ -1820,12 +2837,14 @@ exports.CallGrid = CallGrid;
|
|
|
1820
2837
|
exports.CallHeader = CallHeader;
|
|
1821
2838
|
exports.CallNotice = CallNotice;
|
|
1822
2839
|
exports.CallParticipants = CallParticipants;
|
|
2840
|
+
exports.CallPersonLabel = CallPersonLabel;
|
|
1823
2841
|
exports.CallSidePanel = CallSidePanel;
|
|
1824
2842
|
exports.CallStageFrame = CallStageFrame;
|
|
1825
2843
|
exports.CallStateMessage = CallStateMessage;
|
|
1826
2844
|
exports.CallStatusChip = CallStatusChip;
|
|
1827
2845
|
exports.CallTile = CallTile;
|
|
1828
2846
|
exports.CaptionsStrip = CaptionsStrip;
|
|
2847
|
+
exports.ChatPermissionSetting = ChatPermissionSetting;
|
|
1829
2848
|
exports.ConnectionOverlay = ConnectionOverlay;
|
|
1830
2849
|
exports.ControlBadge = ControlBadge;
|
|
1831
2850
|
exports.ControlDivider = ControlDivider;
|
|
@@ -1839,13 +2858,25 @@ exports.LobbyRequests = LobbyRequests;
|
|
|
1839
2858
|
exports.MediaControl = MediaControl;
|
|
1840
2859
|
exports.MinimisedCall = MinimisedCall;
|
|
1841
2860
|
exports.MoreMenu = MoreMenu;
|
|
2861
|
+
exports.OnStageCheck = OnStageCheck;
|
|
2862
|
+
exports.PanelComposer = PanelComposer;
|
|
1842
2863
|
exports.PreJoin = PreJoin;
|
|
2864
|
+
exports.QAPanel = QAPanel;
|
|
2865
|
+
exports.RaiseHandButton = RaiseHandButton;
|
|
1843
2866
|
exports.RecordControl = RecordControl;
|
|
1844
2867
|
exports.RecordingStatusChip = RecordingStatusChip;
|
|
1845
2868
|
exports.SpeakingNow = SpeakingNow;
|
|
1846
2869
|
exports.TranscriptionStatusChip = TranscriptionStatusChip;
|
|
1847
2870
|
exports.VoiceMeter = VoiceMeter;
|
|
2871
|
+
exports.WebinarAudiencePanel = WebinarAudiencePanel;
|
|
2872
|
+
exports.WebinarEndConfirm = WebinarEndConfirm;
|
|
2873
|
+
exports.WebinarLiveChip = WebinarLiveChip;
|
|
2874
|
+
exports.WebinarLiveControl = WebinarLiveControl;
|
|
2875
|
+
exports.WebinarViewer = WebinarViewer;
|
|
2876
|
+
exports.WebinarWaiting = WebinarWaiting;
|
|
2877
|
+
exports.chatPermissionSection = chatPermissionSection;
|
|
1848
2878
|
exports.describeMediaError = describeMediaError;
|
|
2879
|
+
exports.sortQuestions = sortQuestions;
|
|
1849
2880
|
exports.useBriefNotice = useBriefNotice;
|
|
1850
2881
|
exports.useElementSize = useElementSize;
|
|
1851
2882
|
exports.useShortcutKeys = useShortcutKeys;
|