@realtimexsco/live-chat 1.4.19 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -685,12 +685,55 @@ var init_call_api = __esm({
685
685
  };
686
686
  }
687
687
  });
688
- var idleState; exports.useCallStore = void 0;
688
+
689
+ // src/call/call.types.ts
690
+ exports.CALL_MODES = void 0; exports.CALL_STATUS = void 0; var CALL_RING_TIMEOUT_MS, CLIENT_RING_FALLBACK_MS, CALL_LOG_EVENT;
691
+ var init_call_types = __esm({
692
+ "src/call/call.types.ts"() {
693
+ exports.CALL_MODES = {
694
+ AUDIO: "audio",
695
+ VIDEO: "video"
696
+ };
697
+ exports.CALL_STATUS = {
698
+ RINGING: "ringing",
699
+ ONGOING: "ongoing",
700
+ ENDED: "ended",
701
+ MISSED: "missed",
702
+ REJECTED: "rejected",
703
+ CANCELLED: "cancelled"
704
+ };
705
+ CALL_RING_TIMEOUT_MS = 4e4;
706
+ CLIENT_RING_FALLBACK_MS = CALL_RING_TIMEOUT_MS + 5e3;
707
+ CALL_LOG_EVENT = "realtimex:call-log";
708
+ }
709
+ });
710
+ var emitCallLog, ringTimer, clearRingTimer, scheduleRingTimer, idleState; exports.useCallStore = void 0;
689
711
  var init_call_store = __esm({
690
712
  "src/call/call.store.ts"() {
691
713
  init_useStore();
692
714
  init_socket_service2();
693
715
  init_call_api();
716
+ init_call_types();
717
+ emitCallLog = (entry) => {
718
+ try {
719
+ window.dispatchEvent(new CustomEvent(CALL_LOG_EVENT, { detail: entry }));
720
+ } catch {
721
+ }
722
+ };
723
+ ringTimer = null;
724
+ clearRingTimer = () => {
725
+ if (ringTimer) clearTimeout(ringTimer);
726
+ ringTimer = null;
727
+ };
728
+ scheduleRingTimer = (callId, get, set) => {
729
+ clearRingTimer();
730
+ ringTimer = setTimeout(() => {
731
+ const state = get();
732
+ if (state.callId === callId && (state.uiStatus === "ringing-out" || state.uiStatus === "incoming")) {
733
+ set({ ...idleState });
734
+ }
735
+ }, CLIENT_RING_FALLBACK_MS);
736
+ };
694
737
  idleState = {
695
738
  uiStatus: "idle",
696
739
  callId: null,
@@ -700,13 +743,15 @@ var init_call_store = __esm({
700
743
  token: null,
701
744
  caller: null,
702
745
  participants: [],
703
- error: null
746
+ error: null,
747
+ callee: null,
748
+ callStartedAt: null
704
749
  };
705
750
  exports.useCallStore = zustand.create((set, get) => ({
706
751
  ...idleState,
707
- startCall: async (conversationId, mode) => {
752
+ startCall: async (conversationId, mode, callee) => {
708
753
  if (get().uiStatus !== "idle") return;
709
- set({ ...idleState, uiStatus: "creating", conversationId, mode });
754
+ set({ ...idleState, uiStatus: "creating", conversationId, mode, callee: callee ?? null });
710
755
  try {
711
756
  const room = await exports.apiCreateCallRoom(conversationId, mode);
712
757
  set({
@@ -718,8 +763,10 @@ var init_call_store = __esm({
718
763
  token: room.token,
719
764
  participants: room.participants
720
765
  });
766
+ scheduleRingTimer(room.callId, get, set);
721
767
  exports.socketService.emitCallInvite({ callId: room.callId });
722
768
  } catch (err) {
769
+ clearRingTimer();
723
770
  set({
724
771
  ...idleState,
725
772
  error: err instanceof Error ? err.message : "Could not start the call"
@@ -731,16 +778,18 @@ var init_call_store = __esm({
731
778
  if (callId && uiStatus === "ringing-out") {
732
779
  exports.socketService.emitCallCancel({ callId });
733
780
  }
781
+ clearRingTimer();
734
782
  set({ ...idleState });
735
783
  },
736
784
  acceptCall: async () => {
737
785
  const { callId, meetingId } = get();
738
786
  if (!callId || !meetingId) return;
787
+ clearRingTimer();
739
788
  set({ uiStatus: "joining" });
740
789
  try {
741
790
  const join = await exports.apiFetchJoinToken(meetingId);
742
791
  exports.socketService.emitCallAccept({ callId });
743
- set({ uiStatus: "in-call", token: join.token });
792
+ set({ uiStatus: "in-call", token: join.token, callStartedAt: Date.now() });
744
793
  } catch (err) {
745
794
  set({
746
795
  ...idleState,
@@ -753,6 +802,7 @@ var init_call_store = __esm({
753
802
  if (callId) {
754
803
  exports.socketService.emitCallReject({ callId, reason });
755
804
  }
805
+ clearRingTimer();
756
806
  set({ ...idleState });
757
807
  },
758
808
  endCall: () => {
@@ -760,11 +810,21 @@ var init_call_store = __esm({
760
810
  if (callId) {
761
811
  exports.socketService.emitCallEnd({ callId });
762
812
  }
813
+ clearRingTimer();
814
+ set({ ...idleState });
815
+ },
816
+ reset: () => {
817
+ clearRingTimer();
763
818
  set({ ...idleState });
764
819
  },
765
- reset: () => set({ ...idleState }),
766
820
  _receiveIncoming: (payload) => {
767
- if (get().uiStatus !== "idle") return;
821
+ const currentStatus = get().uiStatus;
822
+ if (currentStatus !== "idle") {
823
+ console.warn(
824
+ `[realtimex-call] call_incoming for ${payload.callId} dropped \u2014 local call store is not idle (currently "${currentStatus}", stuck on callId ${get().callId}). If nothing was actually ringing on screen, this is a stuck state from an earlier call \u2014 refreshing the page clears it.`
825
+ );
826
+ return;
827
+ }
768
828
  set({
769
829
  uiStatus: "incoming",
770
830
  callId: payload.callId,
@@ -774,6 +834,7 @@ var init_call_store = __esm({
774
834
  caller: payload.caller,
775
835
  participants: payload.participants
776
836
  });
837
+ scheduleRingTimer(payload.callId, get, set);
777
838
  },
778
839
  _receiveAccepted: (payload) => {
779
840
  const state = get();
@@ -781,11 +842,17 @@ var init_call_store = __esm({
781
842
  if (state.uiStatus === "incoming") {
782
843
  const myUserId = exports.useChatStore.getState().loggedUserDetails?._id;
783
844
  if (payload.userId === myUserId) {
845
+ clearRingTimer();
784
846
  set({ ...idleState });
785
847
  }
786
848
  return;
787
849
  }
788
- set({ uiStatus: "in-call", participants: payload.participants });
850
+ clearRingTimer();
851
+ set({
852
+ uiStatus: "in-call",
853
+ participants: payload.participants,
854
+ callStartedAt: Date.now()
855
+ });
789
856
  },
790
857
  // A single decline doesn't end a multi-callee call — the server only
791
858
  // moves the call to `rejected` (followed by `call_ended`) once every
@@ -799,17 +866,52 @@ var init_call_store = __esm({
799
866
  },
800
867
  _receiveCancelled: (payload) => {
801
868
  if (get().callId !== payload.callId) return;
869
+ clearRingTimer();
870
+ const myUserId = exports.useChatStore.getState().loggedUserDetails?._id;
871
+ if (payload.endedBy !== myUserId) {
872
+ emitCallLog({
873
+ conversationId: payload.conversationId,
874
+ mode: payload.mode,
875
+ outcome: "missed",
876
+ durationSeconds: 0
877
+ });
878
+ }
802
879
  set({ ...idleState });
803
880
  },
804
881
  _receiveEnded: (payload) => {
805
882
  if (get().callId !== payload.callId) return;
883
+ clearRingTimer();
884
+ emitCallLog({
885
+ conversationId: payload.conversationId,
886
+ mode: payload.mode,
887
+ outcome: payload.durationSeconds > 0 ? "completed" : "declined",
888
+ durationSeconds: payload.durationSeconds
889
+ });
806
890
  set({ ...idleState });
807
891
  },
808
892
  _receiveBusy: (payload) => {
809
893
  if (get().callId !== payload.callId) return;
894
+ clearRingTimer();
895
+ emitCallLog({
896
+ conversationId: payload.conversationId,
897
+ mode: payload.mode,
898
+ outcome: "busy",
899
+ durationSeconds: 0
900
+ });
810
901
  set({ ...idleState, error: "That user is already on another call." });
811
902
  },
812
- _receiveMissed: () => {
903
+ // Guarded by callId like every other _receive* handler — a late/stale
904
+ // call_missed for a call that has already ended (accepted, rejected,
905
+ // or replaced by a new one) must not clobber whatever is happening now.
906
+ _receiveMissed: (payload) => {
907
+ if (get().callId !== payload.callId) return;
908
+ clearRingTimer();
909
+ emitCallLog({
910
+ conversationId: payload.conversationId,
911
+ mode: payload.mode,
912
+ outcome: "missed",
913
+ durationSeconds: 0
914
+ });
813
915
  set({ ...idleState });
814
916
  }
815
917
  }));
@@ -823,26 +925,34 @@ var init_call_listeners = __esm({
823
925
  init_socket_events_constants();
824
926
  init_call_store();
825
927
  registerCallSocketListeners = (socket) => {
928
+ console.debug("[realtimex-call] registerCallSocketListeners: attached to socket", socket.id);
826
929
  socket.on(SOCKET_EVENTS.CALL_INCOMING, (payload) => {
930
+ console.log("[realtimex-call] call_incoming received:", payload);
827
931
  exports.useCallStore.getState()._receiveIncoming(payload);
828
932
  });
829
933
  socket.on(SOCKET_EVENTS.CALL_ACCEPTED, (payload) => {
934
+ console.log("[realtimex-call] call_accepted received:", payload);
830
935
  exports.useCallStore.getState()._receiveAccepted(payload);
831
936
  });
832
937
  socket.on(SOCKET_EVENTS.CALL_REJECTED, (payload) => {
938
+ console.log("[realtimex-call] call_rejected received:", payload);
833
939
  exports.useCallStore.getState()._receiveRejected(payload);
834
940
  });
835
941
  socket.on(SOCKET_EVENTS.CALL_CANCELLED, (payload) => {
942
+ console.log("[realtimex-call] call_cancelled received:", payload);
836
943
  exports.useCallStore.getState()._receiveCancelled(payload);
837
944
  });
838
945
  socket.on(SOCKET_EVENTS.CALL_ENDED, (payload) => {
946
+ console.log("[realtimex-call] call_ended received:", payload);
839
947
  exports.useCallStore.getState()._receiveEnded(payload);
840
948
  });
841
949
  socket.on(SOCKET_EVENTS.CALL_BUSY, (payload) => {
950
+ console.log("[realtimex-call] call_busy received:", payload);
842
951
  exports.useCallStore.getState()._receiveBusy(payload);
843
952
  });
844
- socket.on(SOCKET_EVENTS.CALL_MISSED, () => {
845
- exports.useCallStore.getState()._receiveMissed();
953
+ socket.on(SOCKET_EVENTS.CALL_MISSED, (payload) => {
954
+ console.log("[realtimex-call] call_missed received:", payload);
955
+ exports.useCallStore.getState()._receiveMissed(payload);
846
956
  });
847
957
  };
848
958
  }
@@ -4266,22 +4376,6 @@ var init_button = __esm({
4266
4376
  );
4267
4377
  }
4268
4378
  });
4269
-
4270
- // src/call/videosdk.loader.ts
4271
- var loadVideoSDK;
4272
- var init_videosdk_loader = __esm({
4273
- "src/call/videosdk.loader.ts"() {
4274
- loadVideoSDK = async () => {
4275
- try {
4276
- return await import('@videosdk.live/react-sdk');
4277
- } catch {
4278
- throw new Error(
4279
- 'Audio/video calling needs the "@videosdk.live/react-sdk" package \u2014 run: npm install @videosdk.live/react-sdk'
4280
- );
4281
- }
4282
- };
4283
- }
4284
- });
4285
4379
  function Avatar({
4286
4380
  className,
4287
4381
  size = "default",
@@ -4334,6 +4428,25 @@ var init_avatar = __esm({
4334
4428
  init_utils2();
4335
4429
  }
4336
4430
  });
4431
+
4432
+ // src/call/videosdk.loader.ts
4433
+ var loadVideoSDK;
4434
+ var init_videosdk_loader = __esm({
4435
+ "src/call/videosdk.loader.ts"() {
4436
+ loadVideoSDK = async () => {
4437
+ try {
4438
+ return await import('@videosdk.live/react-sdk');
4439
+ } catch (err) {
4440
+ console.error("[realtimex-call] failed to load @videosdk.live/react-sdk:", err);
4441
+ const message = err instanceof Error ? err.message : String(err);
4442
+ const looksMissing = /Failed to resolve module|Cannot find module|find package/i.test(message);
4443
+ throw new Error(
4444
+ looksMissing ? 'Audio/video calling needs the "@videosdk.live/react-sdk" package \u2014 run: npm install @videosdk.live/react-sdk' : `Audio/video calling failed to load: ${message}`
4445
+ );
4446
+ }
4447
+ };
4448
+ }
4449
+ });
4337
4450
  var ParticipantView, ParticipantView_default;
4338
4451
  var init_ParticipantView = __esm({
4339
4452
  "src/call/ParticipantView.tsx"() {
@@ -4347,7 +4460,7 @@ var init_ParticipantView = __esm({
4347
4460
  fallbackImage,
4348
4461
  className
4349
4462
  }) => {
4350
- const { webcamStream, micStream, webcamOn, micOn, displayName } = sdk.useParticipant(participantId);
4463
+ const { webcamStream, micStream, webcamOn, micOn, displayName, isActiveSpeaker } = sdk.useParticipant(participantId);
4351
4464
  const videoRef = React9.useRef(null);
4352
4465
  const audioRef = React9.useRef(null);
4353
4466
  React9.useEffect(() => {
@@ -4376,7 +4489,8 @@ var init_ParticipantView = __esm({
4376
4489
  "div",
4377
4490
  {
4378
4491
  className: cn(
4379
- "relative flex aspect-video min-h-[120px] items-center justify-center overflow-hidden rounded-xl bg-neutral-900",
4492
+ "relative flex aspect-video min-h-[140px] items-center justify-center overflow-hidden rounded-2xl bg-gradient-to-br from-neutral-800 to-neutral-900 ring-1 ring-white/5 transition-shadow",
4493
+ isActiveSpeaker && micOn && "ring-2 ring-emerald-400/80",
4380
4494
  className
4381
4495
  ),
4382
4496
  children: [
@@ -4393,17 +4507,14 @@ var init_ParticipantView = __esm({
4393
4507
  }
4394
4508
  ),
4395
4509
  !isLocal && /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true }),
4396
- !webcamOn && /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { size: "lg", className: "size-16", children: [
4510
+ !webcamOn && /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { size: "lg", className: "size-20", children: [
4397
4511
  /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: fallbackImage, alt: name }),
4398
- /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "text-lg", children: name.charAt(0).toUpperCase() })
4512
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-xl font-medium text-white", children: name.charAt(0).toUpperCase() })
4399
4513
  ] }),
4400
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-2 left-2 rounded-md bg-black/50 px-2 py-0.5 text-xs text-white", children: isLocal ? `${name} (You)` : name }),
4401
- !micOn && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-2 right-2 rounded-full bg-black/50 p-1 text-white", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
4402
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" }),
4403
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6" }),
4404
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23" }),
4405
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" })
4406
- ] }) })
4514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-x-0 bottom-0 flex items-center justify-between gap-2 bg-gradient-to-t from-black/70 to-transparent px-3 py-2", children: [
4515
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-medium text-white drop-shadow", children: isLocal ? `${name} (You)` : name }),
4516
+ !micOn && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { size: 14, className: "shrink-0 text-white/80", strokeWidth: 2.25 })
4517
+ ] })
4407
4518
  ]
4408
4519
  }
4409
4520
  );
@@ -4417,7 +4528,7 @@ var init_CallControls = __esm({
4417
4528
  init_button();
4418
4529
  init_utils2();
4419
4530
  init_call_store();
4420
- circleBtn = "size-12 rounded-full text-white transition-colors disabled:opacity-40";
4531
+ circleBtn = "size-13 rounded-full text-white transition-all duration-150 disabled:opacity-40 hover:scale-105 active:scale-95";
4421
4532
  CallControls = ({ sdk, mode }) => {
4422
4533
  const { toggleMic, toggleWebcam, localMicOn, localWebcamOn, leave } = sdk.useMeeting();
4423
4534
  const endCall = exports.useCallStore((s) => s.endCall);
@@ -4425,38 +4536,46 @@ var init_CallControls = __esm({
4425
4536
  leave();
4426
4537
  endCall();
4427
4538
  };
4428
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-4 py-6", children: [
4429
- /* @__PURE__ */ jsxRuntime.jsx(
4430
- Button,
4431
- {
4432
- variant: "ghost",
4433
- size: "icon",
4434
- className: cn(circleBtn, localMicOn ? "bg-white/15 hover:bg-white/25" : "bg-white/90 text-neutral-900 hover:bg-white"),
4435
- "aria-label": localMicOn ? "Mute microphone" : "Unmute microphone",
4436
- onClick: () => toggleMic(),
4437
- children: localMicOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { size: 20 })
4438
- }
4439
- ),
4440
- mode === "video" && /* @__PURE__ */ jsxRuntime.jsx(
4441
- Button,
4442
- {
4443
- variant: "ghost",
4444
- size: "icon",
4445
- className: cn(circleBtn, localWebcamOn ? "bg-white/15 hover:bg-white/25" : "bg-white/90 text-neutral-900 hover:bg-white"),
4446
- "aria-label": localWebcamOn ? "Turn camera off" : "Turn camera on",
4447
- onClick: () => toggleWebcam(),
4448
- children: localWebcamOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { size: 20 })
4449
- }
4450
- ),
4539
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-5 py-6", children: [
4540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-full bg-white/10 p-2 backdrop-blur-sm", children: [
4541
+ /* @__PURE__ */ jsxRuntime.jsx(
4542
+ Button,
4543
+ {
4544
+ variant: "ghost",
4545
+ size: "icon",
4546
+ className: cn(
4547
+ circleBtn,
4548
+ localMicOn ? "bg-white/10 hover:bg-white/20" : "bg-white text-neutral-900 hover:bg-white/90"
4549
+ ),
4550
+ "aria-label": localMicOn ? "Mute microphone" : "Unmute microphone",
4551
+ onClick: () => toggleMic(),
4552
+ children: localMicOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MicOff, { size: 20 })
4553
+ }
4554
+ ),
4555
+ mode === "video" && /* @__PURE__ */ jsxRuntime.jsx(
4556
+ Button,
4557
+ {
4558
+ variant: "ghost",
4559
+ size: "icon",
4560
+ className: cn(
4561
+ circleBtn,
4562
+ localWebcamOn ? "bg-white/10 hover:bg-white/20" : "bg-white text-neutral-900 hover:bg-white/90"
4563
+ ),
4564
+ "aria-label": localWebcamOn ? "Turn camera off" : "Turn camera on",
4565
+ onClick: () => toggleWebcam(),
4566
+ children: localWebcamOn ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.VideoOff, { size: 20 })
4567
+ }
4568
+ )
4569
+ ] }),
4451
4570
  /* @__PURE__ */ jsxRuntime.jsx(
4452
4571
  Button,
4453
4572
  {
4454
4573
  variant: "ghost",
4455
4574
  size: "icon",
4456
- className: cn(circleBtn, "bg-red-600 hover:bg-red-500"),
4575
+ className: cn(circleBtn, "bg-red-600 shadow-lg shadow-red-600/30 hover:bg-red-500"),
4457
4576
  "aria-label": "End call",
4458
4577
  onClick: handleLeave,
4459
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 20, className: "rotate-[135deg]" })
4578
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 22 })
4460
4579
  }
4461
4580
  )
4462
4581
  ] });
@@ -6061,22 +6180,69 @@ var ChatAlertDialogContent = ({
6061
6180
  };
6062
6181
 
6063
6182
  // src/call/CallOverlay.tsx
6183
+ init_avatar();
6064
6184
  init_button();
6065
6185
  init_utils2();
6066
6186
  init_call_store();
6187
+
6188
+ // src/call/useRingCountdown.ts
6189
+ init_call_types();
6190
+ var useRingCountdown = (active, callId) => {
6191
+ const [secondsLeft, setSecondsLeft] = React9.useState(
6192
+ Math.ceil(CALL_RING_TIMEOUT_MS / 1e3)
6193
+ );
6194
+ React9.useEffect(() => {
6195
+ if (!active) return;
6196
+ const startedAt = Date.now();
6197
+ setSecondsLeft(Math.ceil(CALL_RING_TIMEOUT_MS / 1e3));
6198
+ const id = setInterval(() => {
6199
+ const remainingMs = CALL_RING_TIMEOUT_MS - (Date.now() - startedAt);
6200
+ setSecondsLeft(Math.max(0, Math.ceil(remainingMs / 1e3)));
6201
+ }, 1e3);
6202
+ return () => clearInterval(id);
6203
+ }, [active, callId]);
6204
+ return secondsLeft;
6205
+ };
6206
+ var useCallDuration = (startedAt) => {
6207
+ const [elapsedMs, setElapsedMs] = React9.useState(0);
6208
+ React9.useEffect(() => {
6209
+ if (!startedAt) {
6210
+ setElapsedMs(0);
6211
+ return;
6212
+ }
6213
+ setElapsedMs(Date.now() - startedAt);
6214
+ const id = setInterval(() => setElapsedMs(Date.now() - startedAt), 1e3);
6215
+ return () => clearInterval(id);
6216
+ }, [startedAt]);
6217
+ const totalSeconds = Math.max(0, Math.floor(elapsedMs / 1e3));
6218
+ const hours = Math.floor(totalSeconds / 3600);
6219
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
6220
+ const seconds = totalSeconds % 60;
6221
+ const pad = (n) => String(n).padStart(2, "0");
6222
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`;
6223
+ };
6067
6224
  var CallSession2 = React9__namespace.default.lazy(() => Promise.resolve().then(() => (init_CallSession(), CallSession_exports)));
6068
6225
  var CallOverlay = () => {
6069
6226
  const uiStatus = exports.useCallStore((s) => s.uiStatus);
6070
6227
  const mode = exports.useCallStore((s) => s.mode);
6228
+ const callId = exports.useCallStore((s) => s.callId);
6071
6229
  const meetingId = exports.useCallStore((s) => s.meetingId);
6072
6230
  const token = exports.useCallStore((s) => s.token);
6073
6231
  const error = exports.useCallStore((s) => s.error);
6232
+ const callee = exports.useCallStore((s) => s.callee);
6233
+ const caller = exports.useCallStore((s) => s.caller);
6234
+ const callStartedAt = exports.useCallStore((s) => s.callStartedAt);
6074
6235
  const cancelCall = exports.useCallStore((s) => s.cancelCall);
6075
6236
  const reset = exports.useCallStore((s) => s.reset);
6076
6237
  const [sessionError, setSessionError] = React9.useState(null);
6238
+ const secondsLeft = useRingCountdown(uiStatus === "ringing-out", callId);
6239
+ const duration = useCallDuration(callStartedAt);
6077
6240
  const isOpen = uiStatus !== "idle" && uiStatus !== "incoming";
6078
6241
  if (!isOpen) return null;
6079
6242
  const displayError = error || sessionError;
6243
+ const peerName = callee?.name || caller?.name || "";
6244
+ const peerAvatar = callee?.avatar || caller?.profileImage || void 0;
6245
+ const isVideo = mode === "video";
6080
6246
  return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: () => void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
6081
6247
  ChatDialogContent,
6082
6248
  {
@@ -6085,7 +6251,7 @@ var CallOverlay = () => {
6085
6251
  onPointerDownOutside: (e) => e.preventDefault(),
6086
6252
  className: cn(
6087
6253
  "fixed inset-0 top-0 left-0 z-100 flex h-screen w-screen max-w-none",
6088
- "translate-x-0 translate-y-0 flex-col rounded-none border-0 bg-neutral-950 p-0 text-white"
6254
+ "translate-x-0 translate-y-0 flex-col rounded-none border-0 bg-gradient-to-b from-neutral-900 via-neutral-950 to-black p-0 text-white"
6089
6255
  ),
6090
6256
  children: displayError ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 p-6 text-center", children: [
6091
6257
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-sm text-sm text-white/80", children: displayError }),
@@ -6093,41 +6259,69 @@ var CallOverlay = () => {
6093
6259
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, className: "mr-1" }),
6094
6260
  " Close"
6095
6261
  ] })
6096
- ] }) : uiStatus === "in-call" && meetingId && token && mode ? /* @__PURE__ */ jsxRuntime.jsx(
6097
- React9__namespace.default.Suspense,
6098
- {
6099
- fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-white/80", children: [
6100
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin" }),
6101
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "Loading call\u2026" })
6102
- ] }),
6103
- children: /* @__PURE__ */ jsxRuntime.jsx(
6104
- CallSession2,
6105
- {
6106
- meetingId,
6107
- token,
6108
- mode,
6109
- onError: setSessionError
6110
- }
6111
- )
6112
- }
6113
- ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-6 p-6 text-center", children: [
6114
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-20 items-center justify-center rounded-full bg-white/10", children: mode === "video" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 32 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 32 }) }),
6115
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-white/80", children: [
6116
- uiStatus === "creating" && "Starting call\u2026",
6117
- uiStatus === "ringing-out" && "Calling\u2026",
6118
- uiStatus === "joining" && "Connecting\u2026"
6262
+ ] }) : uiStatus === "in-call" && meetingId && token && mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col", children: [
6263
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 px-4 py-3 text-sm text-white/70", children: [
6264
+ peerName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-white/90", children: peerName }),
6265
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "text-white/30", children: "\xB7" }),
6266
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: duration })
6119
6267
  ] }),
6120
- uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsx(
6121
- Button,
6268
+ /* @__PURE__ */ jsxRuntime.jsx(
6269
+ React9__namespace.default.Suspense,
6122
6270
  {
6123
- variant: "ghost",
6124
- size: "icon",
6125
- className: "size-12 rounded-full bg-red-600 text-white hover:bg-red-500",
6126
- "aria-label": "Cancel call",
6127
- onClick: cancelCall,
6128
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 20 })
6271
+ fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-3 text-white/80", children: [
6272
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin" }),
6273
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "Loading call\u2026" })
6274
+ ] }),
6275
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6276
+ CallSession2,
6277
+ {
6278
+ meetingId,
6279
+ token,
6280
+ mode,
6281
+ onError: setSessionError
6282
+ }
6283
+ )
6129
6284
  }
6130
6285
  )
6286
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-6 p-6 text-center", children: [
6287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
6288
+ uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6289
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/10" }),
6290
+ /* @__PURE__ */ jsxRuntime.jsx(
6291
+ "span",
6292
+ {
6293
+ className: "absolute inline-flex size-32 animate-ping rounded-full bg-white/5",
6294
+ style: { animationDelay: "0.6s" }
6295
+ }
6296
+ )
6297
+ ] }),
6298
+ peerName ? /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "relative size-28 ring-4 ring-white/10", children: [
6299
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: peerAvatar, alt: peerName }),
6300
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-3xl font-medium text-white", children: peerName.charAt(0).toUpperCase() })
6301
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex size-28 items-center justify-center rounded-full bg-white/10", children: isVideo ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 36 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 36 }) })
6302
+ ] }),
6303
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6304
+ peerName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-semibold tracking-tight", children: peerName }),
6305
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-white/60", children: [
6306
+ uiStatus === "creating" && "Starting call\u2026",
6307
+ uiStatus === "ringing-out" && `${isVideo ? "Video calling" : "Calling"}\u2026 \xB7 ${secondsLeft}s`,
6308
+ uiStatus === "joining" && "Connecting\u2026"
6309
+ ] })
6310
+ ] }),
6311
+ uiStatus === "ringing-out" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-col items-center gap-2", children: [
6312
+ /* @__PURE__ */ jsxRuntime.jsx(
6313
+ Button,
6314
+ {
6315
+ variant: "ghost",
6316
+ size: "icon",
6317
+ className: "size-16 rounded-full bg-red-600 text-white shadow-lg shadow-red-600/30 transition-transform hover:scale-105 hover:bg-red-500 active:scale-95",
6318
+ "aria-label": "Cancel call",
6319
+ onClick: cancelCall,
6320
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 24 })
6321
+ }
6322
+ ),
6323
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/60", children: "Cancel" })
6324
+ ] })
6131
6325
  ] })
6132
6326
  }
6133
6327
  ) });
@@ -6139,12 +6333,14 @@ init_utils2();
6139
6333
  init_call_store();
6140
6334
  var IncomingCallDialog = ({ ringtoneUrl }) => {
6141
6335
  const uiStatus = exports.useCallStore((s) => s.uiStatus);
6336
+ const callId = exports.useCallStore((s) => s.callId);
6142
6337
  const caller = exports.useCallStore((s) => s.caller);
6143
6338
  const mode = exports.useCallStore((s) => s.mode);
6144
6339
  const acceptCall = exports.useCallStore((s) => s.acceptCall);
6145
6340
  const rejectCall = exports.useCallStore((s) => s.rejectCall);
6146
6341
  const audioRef = React9.useRef(null);
6147
6342
  const isOpen = uiStatus === "incoming";
6343
+ const secondsLeft = useRingCountdown(isOpen, callId);
6148
6344
  React9.useEffect(() => {
6149
6345
  const el = audioRef.current;
6150
6346
  if (!el || !ringtoneUrl) return;
@@ -6157,6 +6353,7 @@ var IncomingCallDialog = ({ ringtoneUrl }) => {
6157
6353
  }, [isOpen, ringtoneUrl]);
6158
6354
  if (!isOpen) return null;
6159
6355
  const name = caller?.name || "Unknown caller";
6356
+ const isVideo = mode === "video";
6160
6357
  return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open: isOpen, onOpenChange: () => void 0, children: [
6161
6358
  ringtoneUrl && /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, src: ringtoneUrl, loop: true }),
6162
6359
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -6165,51 +6362,70 @@ var IncomingCallDialog = ({ ringtoneUrl }) => {
6165
6362
  showCloseButton: false,
6166
6363
  onEscapeKeyDown: (e) => e.preventDefault(),
6167
6364
  onPointerDownOutside: (e) => e.preventDefault(),
6168
- className: "max-w-xs rounded-2xl p-6 text-center",
6169
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
6170
- /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { size: "lg", className: "size-16", children: [
6171
- /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: caller?.profileImage, alt: name }),
6172
- /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "text-lg", children: name.charAt(0).toUpperCase() })
6365
+ className: "w-[min(340px,calc(100vw-2rem))] max-w-none overflow-hidden rounded-3xl border-0 bg-gradient-to-b from-neutral-800 to-neutral-950 p-0 text-white shadow-2xl",
6366
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-5 px-6 pt-9 pb-7", children: [
6367
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
6368
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-28 animate-ping rounded-full bg-emerald-400/20" }),
6369
+ /* @__PURE__ */ jsxRuntime.jsx(
6370
+ "span",
6371
+ {
6372
+ className: "absolute inline-flex size-28 animate-ping rounded-full bg-emerald-400/15",
6373
+ style: { animationDelay: "0.6s" }
6374
+ }
6375
+ ),
6376
+ /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "relative size-24 ring-4 ring-white/10", children: [
6377
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: caller?.profileImage, alt: name }),
6378
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "bg-neutral-700 text-2xl font-medium text-white", children: name.charAt(0).toUpperCase() })
6379
+ ] }),
6380
+ /* @__PURE__ */ jsxRuntime.jsx(
6381
+ "span",
6382
+ {
6383
+ className: cn(
6384
+ "absolute -right-1 -bottom-1 flex size-8 items-center justify-center rounded-full ring-4 ring-neutral-900",
6385
+ isVideo ? "bg-indigo-500" : "bg-emerald-500"
6386
+ ),
6387
+ children: isVideo ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 14 })
6388
+ }
6389
+ )
6173
6390
  ] }),
6174
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6175
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold text-(--chat-text)", children: name }),
6176
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center justify-center gap-1 text-sm text-(--chat-muted)", children: [
6177
- mode === "video" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Video, { size: 14 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 14 }),
6391
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
6392
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-semibold tracking-tight", children: name }),
6393
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-white/50", children: [
6178
6394
  "Incoming ",
6179
- mode === "video" ? "video" : "voice",
6180
- " call\u2026"
6395
+ isVideo ? "video" : "voice",
6396
+ " call \xB7 ",
6397
+ secondsLeft,
6398
+ "s"
6181
6399
  ] })
6182
6400
  ] }),
6183
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-center gap-6", children: [
6184
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
6401
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-center gap-10", children: [
6402
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
6185
6403
  /* @__PURE__ */ jsxRuntime.jsx(
6186
6404
  Button,
6187
6405
  {
6188
6406
  variant: "ghost",
6189
6407
  size: "icon",
6190
- className: cn(
6191
- "size-12 rounded-full bg-red-600 text-white hover:bg-red-500"
6192
- ),
6408
+ className: "size-16 rounded-full bg-red-600 text-white shadow-lg shadow-red-600/30 transition-transform hover:scale-105 hover:bg-red-500 active:scale-95",
6193
6409
  "aria-label": "Decline call",
6194
6410
  onClick: () => rejectCall(),
6195
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 20 })
6411
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 24 })
6196
6412
  }
6197
6413
  ),
6198
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-(--chat-muted)", children: "Decline" })
6414
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/60", children: "Decline" })
6199
6415
  ] }),
6200
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
6416
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
6201
6417
  /* @__PURE__ */ jsxRuntime.jsx(
6202
6418
  Button,
6203
6419
  {
6204
6420
  variant: "ghost",
6205
6421
  size: "icon",
6206
- className: "size-12 rounded-full bg-green-600 text-white hover:bg-green-500",
6422
+ className: "size-16 rounded-full bg-emerald-500 text-white shadow-lg shadow-emerald-500/30 transition-transform hover:scale-105 hover:bg-emerald-400 active:scale-95",
6207
6423
  "aria-label": "Accept call",
6208
6424
  onClick: () => acceptCall(),
6209
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 20 })
6425
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 24 })
6210
6426
  }
6211
6427
  ),
6212
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-(--chat-muted)", children: "Accept" })
6428
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-white/60", children: "Accept" })
6213
6429
  ] })
6214
6430
  ] })
6215
6431
  ] })
@@ -6677,6 +6893,18 @@ var installNotificationClickBridge = (options = {}) => {
6677
6893
  };
6678
6894
 
6679
6895
  // src/hooks/useChatController.ts
6896
+ init_call_types();
6897
+ function formatCallLogText(entry) {
6898
+ const label = entry.mode === "video" ? "video" : "voice";
6899
+ if (entry.outcome === "missed") return `Missed ${label} call`;
6900
+ if (entry.outcome === "declined") return `${label === "video" ? "Video" : "Voice"} call declined`;
6901
+ if (entry.outcome === "busy") return `${label === "video" ? "Video" : "Voice"} call \xB7 not answered`;
6902
+ const totalSeconds = Math.max(0, Math.floor(entry.durationSeconds));
6903
+ const minutes = Math.floor(totalSeconds / 60);
6904
+ const seconds = totalSeconds % 60;
6905
+ const duration = `${minutes}:${String(seconds).padStart(2, "0")}`;
6906
+ return `${label === "video" ? "Video" : "Voice"} call \xB7 ${duration}`;
6907
+ }
6680
6908
  function resolveMessageType(content, attachments) {
6681
6909
  if (attachments.length === 0) return "text";
6682
6910
  if (!content.trim() && attachments.length === 1) {
@@ -6734,6 +6962,28 @@ var useChatController = () => {
6734
6962
  );
6735
6963
  }, []);
6736
6964
  const { localMessages, setLocalMessages } = useChatSync();
6965
+ React9.useEffect(() => {
6966
+ const handleCallLog = (event) => {
6967
+ const entry = event.detail;
6968
+ if (!entry?.conversationId) return;
6969
+ const logMessage = {
6970
+ id: `call-log-${Date.now()}-${Math.random().toString(36).slice(2)}`,
6971
+ content: formatCallLogText(entry),
6972
+ sender: "system",
6973
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6974
+ isOwnMessage: false,
6975
+ isSystemMessage: true,
6976
+ channelId: entry.conversationId,
6977
+ conversationId: entry.conversationId
6978
+ };
6979
+ setLocalMessages((prev) => ({
6980
+ ...prev,
6981
+ [entry.conversationId]: [...prev[entry.conversationId] || [], logMessage]
6982
+ }));
6983
+ };
6984
+ window.addEventListener(CALL_LOG_EVENT, handleCallLog);
6985
+ return () => window.removeEventListener(CALL_LOG_EVENT, handleCallLog);
6986
+ }, [setLocalMessages]);
6737
6987
  const emitDmSend = exports.useChatStore((s) => s.emitDmSend);
6738
6988
  const emitGroupMessageSend2 = exports.useChatStore((s) => s.emitGroupMessageSend);
6739
6989
  const emitMarkAsRead = exports.useChatStore((s) => s.emitMarkAsRead);
@@ -10030,19 +10280,20 @@ var HeaderRightSide = ({
10030
10280
  const startCall = exports.useCallStore((s) => s.startCall);
10031
10281
  const showPhoneCall = features.showPhoneCall ?? defaultChatFeatures.showPhoneCall;
10032
10282
  const showVideoCall = features.showVideoCall ?? defaultChatFeatures.showVideoCall;
10283
+ const callee = { name: activeChannel.name, avatar: activeChannel.avatar || activeChannel.image };
10033
10284
  const handlePhoneCall = () => {
10034
10285
  if (features.onPhoneCall) {
10035
10286
  features.onPhoneCall({ activeChannel, conversationId });
10036
10287
  return;
10037
10288
  }
10038
- if (conversationId) startCall(conversationId, "audio");
10289
+ if (conversationId) startCall(conversationId, "audio", callee);
10039
10290
  };
10040
10291
  const handleVideoCall = () => {
10041
10292
  if (features.onVideoCall) {
10042
10293
  features.onVideoCall({ activeChannel, conversationId });
10043
10294
  return;
10044
10295
  }
10045
- if (conversationId) startCall(conversationId, "video");
10296
+ if (conversationId) startCall(conversationId, "video", callee);
10046
10297
  };
10047
10298
  const headerItemGapClass = "gap-0.5";
10048
10299
  const headerIconBtnClass = "inline-flex size-6 shrink-0 items-center justify-center rounded-lg p-0 text-(--chat-muted) transition-colors hover:bg-(--chat-hover) hover:text-(--chat-text) has-[>svg]:p-0";
@@ -20744,27 +20995,10 @@ init_settings_types();
20744
20995
  init_api_service();
20745
20996
  init_call_store();
20746
20997
  init_call_api();
20747
-
20748
- // src/call/call.types.ts
20749
- var CALL_MODES = {
20750
- AUDIO: "audio",
20751
- VIDEO: "video"
20752
- };
20753
- var CALL_STATUS = {
20754
- RINGING: "ringing",
20755
- ONGOING: "ongoing",
20756
- ENDED: "ended",
20757
- MISSED: "missed",
20758
- REJECTED: "rejected",
20759
- CANCELLED: "cancelled"
20760
- };
20761
-
20762
- // src/index.ts
20998
+ init_call_types();
20763
20999
  var index_default = ChatMain_default;
20764
21000
 
20765
21001
  exports.AdminPermissionTooltip = AdminPermissionTooltip;
20766
- exports.CALL_MODES = CALL_MODES;
20767
- exports.CALL_STATUS = CALL_STATUS;
20768
21002
  exports.Calendar = Calendar;
20769
21003
  exports.CalendarDayButton = CalendarDayButton;
20770
21004
  exports.CallOverlay = CallOverlay_default;