@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/firebase-messaging-sw.js +9 -3
- package/dist/index.cjs +372 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.mjs +373 -137
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -685,12 +685,55 @@ var init_call_api = __esm({
|
|
|
685
685
|
};
|
|
686
686
|
}
|
|
687
687
|
});
|
|
688
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-[
|
|
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-
|
|
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-
|
|
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.
|
|
4401
|
-
|
|
4402
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4403
|
-
|
|
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-
|
|
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-
|
|
4429
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
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.
|
|
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.
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
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
|
-
|
|
6121
|
-
|
|
6268
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6269
|
+
React9__namespace.default.Suspense,
|
|
6122
6270
|
{
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
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-
|
|
6169
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-
|
|
6170
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6171
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6172
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
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-
|
|
6176
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "
|
|
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
|
-
|
|
6180
|
-
" call\
|
|
6395
|
+
isVideo ? "video" : "voice",
|
|
6396
|
+
" call \xB7 ",
|
|
6397
|
+
secondsLeft,
|
|
6398
|
+
"s"
|
|
6181
6399
|
] })
|
|
6182
6400
|
] }),
|
|
6183
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-
|
|
6184
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-
|
|
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:
|
|
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:
|
|
6411
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PhoneOff, { size: 24 })
|
|
6196
6412
|
}
|
|
6197
6413
|
),
|
|
6198
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-
|
|
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-
|
|
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-
|
|
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:
|
|
6425
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { size: 24 })
|
|
6210
6426
|
}
|
|
6211
6427
|
),
|
|
6212
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-
|
|
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;
|