@livo-tv/sdk 1.2.4 → 1.3.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.
@@ -2704,11 +2704,15 @@ function StudioSidePanel({
2704
2704
  onGrantStage,
2705
2705
  onDenyStage,
2706
2706
  onTakeOffAir,
2707
+ onKick,
2707
2708
  guestUrl,
2708
2709
  onShareGuestLink
2709
2710
  }) {
2710
2711
  const panelists = participants.filter((row) => isOnStage(row.stageStatus));
2711
2712
  const audience = participants.filter((row) => !isOnStage(row.stageStatus));
2713
+ const [pendingKick, setPendingKick] = react.useState(
2714
+ null
2715
+ );
2712
2716
  return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "bg-background flex min-h-0 w-full flex-1 flex-col border-t md:w-80 md:flex-none md:border-l md:border-t-0", children: [
2713
2717
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
2714
2718
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2825,23 +2829,37 @@ function StudioSidePanel({
2825
2829
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: labels.panelists }),
2826
2830
  panelists.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm", children: labels.noPanelists }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", children: panelists.map((row) => {
2827
2831
  const userId = row.userId;
2832
+ const showKick = isModerator2 && !row.isSelf && Boolean(row.id);
2828
2833
  return /* @__PURE__ */ jsxRuntime.jsxs(
2829
2834
  "li",
2830
2835
  {
2831
2836
  className: "space-y-2 rounded-md border p-2",
2832
2837
  children: [
2833
2838
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm", children: row.name }),
2834
- !row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
2835
- Button,
2836
- {
2837
- type: "button",
2838
- size: "xs",
2839
- variant: "outline",
2840
- className: "w-full",
2841
- onClick: () => onTakeOffAir(userId),
2842
- children: labels.offAir
2843
- }
2844
- ) : null
2839
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
2840
+ !row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
2841
+ Button,
2842
+ {
2843
+ type: "button",
2844
+ size: "xs",
2845
+ variant: "outline",
2846
+ className: "w-full",
2847
+ onClick: () => onTakeOffAir(userId),
2848
+ children: labels.offAir
2849
+ }
2850
+ ) : null,
2851
+ showKick ? /* @__PURE__ */ jsxRuntime.jsx(
2852
+ Button,
2853
+ {
2854
+ type: "button",
2855
+ size: "xs",
2856
+ variant: "ghost",
2857
+ className: "w-full",
2858
+ onClick: () => setPendingKick(row),
2859
+ children: labels.kick
2860
+ }
2861
+ ) : null
2862
+ ] })
2845
2863
  ]
2846
2864
  },
2847
2865
  row.id
@@ -2852,29 +2870,61 @@ function StudioSidePanel({
2852
2870
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: labels.audience }),
2853
2871
  audience.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm", children: labels.noAudience }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", children: audience.map((row) => {
2854
2872
  const userId = row.userId;
2873
+ const showKick = isModerator2 && !row.isSelf && Boolean(row.id);
2855
2874
  return /* @__PURE__ */ jsxRuntime.jsxs(
2856
2875
  "li",
2857
2876
  {
2858
2877
  className: "space-y-2 rounded-md border p-2",
2859
2878
  children: [
2860
2879
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm", children: row.name }),
2861
- !row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
2862
- Button,
2863
- {
2864
- type: "button",
2865
- size: "xs",
2866
- variant: "outline",
2867
- className: "w-full",
2868
- onClick: () => onGrantStage(userId),
2869
- children: labels.bringOnAir
2870
- }
2871
- ) : null
2880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
2881
+ !row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
2882
+ Button,
2883
+ {
2884
+ type: "button",
2885
+ size: "xs",
2886
+ variant: "outline",
2887
+ className: "w-full",
2888
+ onClick: () => onGrantStage(userId),
2889
+ children: labels.bringOnAir
2890
+ }
2891
+ ) : null,
2892
+ showKick ? /* @__PURE__ */ jsxRuntime.jsx(
2893
+ Button,
2894
+ {
2895
+ type: "button",
2896
+ size: "xs",
2897
+ variant: "ghost",
2898
+ className: "w-full",
2899
+ onClick: () => setPendingKick(row),
2900
+ children: labels.kick
2901
+ }
2902
+ ) : null
2903
+ ] })
2872
2904
  ]
2873
2905
  },
2874
2906
  row.id
2875
2907
  );
2876
2908
  }) })
2877
- ] })
2909
+ ] }),
2910
+ /* @__PURE__ */ jsxRuntime.jsx(
2911
+ ConfirmAction,
2912
+ {
2913
+ open: pendingKick !== null,
2914
+ onOpenChange: (open) => {
2915
+ if (!open) setPendingKick(null);
2916
+ },
2917
+ triggerLabel: labels.kick,
2918
+ title: pendingKick ? labels.kickTitleNamed.replace("{name}", pendingKick.name) : labels.kickTitle,
2919
+ description: labels.kickDescription,
2920
+ confirmLabel: labels.kickConfirm,
2921
+ onConfirm: () => {
2922
+ const target = pendingKick;
2923
+ setPendingKick(null);
2924
+ if (target) onKick(target.id);
2925
+ }
2926
+ }
2927
+ )
2878
2928
  ] })
2879
2929
  ] });
2880
2930
  }
@@ -4436,6 +4486,7 @@ function StudioRoom({
4436
4486
  const tile = participants.find((row) => row.userId === userId);
4437
4487
  if (tile) void onSetStage(tile, false);
4438
4488
  },
4489
+ onKick: (id) => void onKick(id),
4439
4490
  guestUrl: session.guestUrl,
4440
4491
  onShareGuestLink: () => {
4441
4492
  const url = session.guestUrl;
@@ -5281,6 +5332,14 @@ function studioMeetingFromRtk(raw) {
5281
5332
  await meeting.self.disableVideo?.();
5282
5333
  await meeting.self.enableVideo?.();
5283
5334
  }
5335
+ async function acceptAllowedStageIfOffAir() {
5336
+ if (currentStageStatus() !== "OFF_STAGE") return;
5337
+ if (meeting.self?.permissions?.stageAccess !== "ALLOWED") return;
5338
+ try {
5339
+ await meeting.stage?.requestAccess?.();
5340
+ } catch {
5341
+ }
5342
+ }
5284
5343
  async function runJoinStageAttempts() {
5285
5344
  let lastError;
5286
5345
  for (let attempt = 0; attempt < STAGE_JOIN_MAX_ATTEMPTS; attempt++) {
@@ -5289,6 +5348,11 @@ function studioMeetingFromRtk(raw) {
5289
5348
  return;
5290
5349
  }
5291
5350
  try {
5351
+ await acceptAllowedStageIfOffAir();
5352
+ if (currentStageStatus() === "ON_STAGE") {
5353
+ notifyStage();
5354
+ return;
5355
+ }
5292
5356
  await meeting.stage?.join?.();
5293
5357
  joinedStageLocally = true;
5294
5358
  await republishCameraIfOn();
@@ -5541,6 +5605,10 @@ function studioMeetingFromRtk(raw) {
5541
5605
  async setStageAccess(userId, on) {
5542
5606
  const target = findByUserId(meeting, userId);
5543
5607
  if (isRecorder(target)) return;
5608
+ if (on && meeting.self?.userId === userId && meeting.self?.permissions?.stageAccess === "ALLOWED") {
5609
+ await joinStageWithRetry();
5610
+ return;
5611
+ }
5544
5612
  if (on) await meeting.stage?.grantAccess?.([userId]);
5545
5613
  else await meeting.stage?.kick?.([userId]);
5546
5614
  notifyStage();
@@ -6518,6 +6586,7 @@ function studioRoomLabels(t) {
6518
6586
  unpinnedToast: t("unpinnedToast"),
6519
6587
  pinError: t("pinError"),
6520
6588
  kickTitle: t("kickTitle"),
6589
+ kickTitleNamed: t("kickTitleNamed", { name: "{name}" }),
6521
6590
  kickDescription: t("kickDescription"),
6522
6591
  kickConfirm: t("kickConfirm"),
6523
6592
  kickError: t("kickError"),