UNPKG

chat-video-sdk

Version:

SDK for 1:1 chat and video calling

996 lines (990 loc) 30 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Chat: () => Chat, VideoCall: () => VideoCall }); module.exports = __toCommonJS(src_exports); // src/components/Chat.tsx var import_react = __toESM(require("react")); var import_socket = require("socket.io-client"); // #style-inject:#style-inject function styleInject(css, { insertAt } = {}) { if (!css || typeof document === "undefined") return; const head = document.head || document.getElementsByTagName("head")[0]; const style = document.createElement("style"); style.type = "text/css"; if (insertAt === "top") { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } // src/components/styles.css styleInject(`.chat-container { display: flex; flex-direction: column; height: 100%; min-height: 400px; border: 1px solid #ddd; border-radius: 8px; } .messages { flex: 1; padding: 16px; overflow-y: auto; } .message { margin: 8px 0; padding: 8px 12px; border-radius: 12px; max-width: 70%; } .message.sent { background-color: #0084ff; color: white; margin-left: auto; } .message.received { background-color: #f0f0f0; margin-right: auto; } .input-area { display: flex; padding: 16px; border-top: 1px solid #ddd; } .input-area input { flex: 1; padding: 8px 12px; border: 1px solid #ddd; border-radius: 20px; margin-right: 8px; } .input-area button { padding: 8px 16px; background-color: #0084ff; color: white; border: none; border-radius: 20px; cursor: pointer; } .input-area button:hover { background-color: #0073e6; } .video-call-container { width: 100%; max-width: 1200px; margin: 0 auto; } .video-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin-bottom: 16px; } .video-wrapper { position: relative; padding-top: 56.25%; border-radius: 8px; overflow: hidden; } .video-wrapper video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .video-wrapper span { position: absolute; bottom: 8px; left: 8px; background-color: rgba(0, 0, 0, 0.6); color: white; padding: 4px 8px; border-radius: 4px; } .controls { display: flex; justify-content: center; gap: 16px; } .controls button { padding: 12px 24px; border-radius: 24px; border: none; cursor: pointer; font-weight: 500; } .controls button:first-child { background-color: #4caf50; color: white; } .controls button:last-child { background-color: #f44336; color: white; } .chat-sdk-container { display: flex; flex-direction: column; height: 100%; min-height: 500px; max-height: 800px; background-color: #f0f2f5; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .chat-sdk-header { display: flex; align-items: center; padding: 12px 16px; background-color: #fff; border-bottom: 1px solid #e0e0e0; border-radius: 8px 8px 0 0; } .chat-sdk-user-info { display: flex; align-items: center; gap: 12px; } .chat-sdk-avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; } .chat-sdk-user-details { display: flex; flex-direction: column; } .chat-sdk-user-details h3 { margin: 0; font-size: 16px; font-weight: 500; color: #1a1a1a; } .chat-sdk-typing { font-size: 13px; color: #06cf9c; } .chat-sdk-messages { flex: 1; padding: 16px; overflow-y: auto; background-color: #efeae2; background-image: url("data:image/svg+xml,%3Csvg width='64' height='64' viewBox='0 0 64 64' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8 16c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm0-2c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6zm33.414-6l5.95-5.95L45.95.636 40 6.586 34.05.636 32.636 2.05 38.586 8l-5.95 5.95 1.414 1.414L40 9.414l5.95 5.95 1.414-1.414L41.414 8zM40 48c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm0-2c3.314 0 6-2.686 6-6s-2.686-6-6-6-6 2.686-6 6 2.686 6 6 6zM9.414 40l5.95-5.95-1.414-1.414L8 38.586l-5.95-5.95L.636 34.05 6.586 40l-5.95 5.95 1.414 1.414L8 41.414l5.95 5.95 1.414-1.414L9.414 40z' fill='%239C92AC' fill-opacity='0.05' fill-rule='evenodd'/%3E%3C/svg%3E"); } .chat-sdk-message { display: flex; flex-direction: column; max-width: 65%; margin: 4px 0; padding: 8px 12px; border-radius: 7.5px; position: relative; box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13); } .chat-sdk-sent { align-self: flex-end; background-color: #e7ffdb; border-top-right-radius: 0; } .chat-sdk-received { align-self: flex-start; background-color: #ffffff; border-top-left-radius: 0; } .chat-sdk-message-content { display: flex; flex-direction: column; } .chat-sdk-message-content p { margin: 0; font-size: 14px; line-height: 19px; color: #111b21; } .chat-sdk-message-meta { display: flex; align-items: center; gap: 4px; margin-top: 2px; } .chat-sdk-message-meta time { font-size: 11px; color: #667781; } .chat-sdk-status { width: 16px; height: 11px; position: relative; } .chat-sdk-sent::after { content: ""; position: absolute; right: -8px; top: 0; width: 0; height: 0; border-left: 8px solid #e7ffdb; border-top: 8px solid transparent; } .chat-sdk-received::before { content: ""; position: absolute; left: -8px; top: 0; width: 0; height: 0; border-right: 8px solid #ffffff; border-top: 8px solid transparent; } .chat-sdk-status.chat-sdk-sent::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='11' fill='%238696a0'%3E%3Cpath d='M10.95 2.5 5.5 8 2.05 4.5l-.84.85L5.5 9.5l6.23-6.23-.78-.77z'/%3E%3C/svg%3E"); } .chat-sdk-status.chat-sdk-delivered::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='11' fill='%238696a0'%3E%3Cpath d='m15.01 3.316-.478-.372a.365.365 0 0 0-.51.063L8.666 9.879a.32.32 0 0 1-.484.033l-.358-.325a.32.32 0 0 0-.484.032l-.378.483a.418.418 0 0 0 .036.54l1.32 1.266c.143.14.361.125.484-.033l6.272-8.048a.366.366 0 0 0-.064-.512zm-4.1 0-.478-.372a.365.365 0 0 0-.51.063L4.566 9.879a.32.32 0 0 1-.484.033L1.891 7.769a.366.366 0 0 0-.515.006l-.423.433a.364.364 0 0 0 .006.514l3.258 3.185c.143.14.361.125.484-.033l6.272-8.048a.365.365 0 0 0-.063-.51z'/%3E%3C/svg%3E"); } .chat-sdk-status.chat-sdk-read::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='11' fill='%234fc3f7'%3E%3Cpath d='m15.01 3.316-.478-.372a.365.365 0 0 0-.51.063L8.666 9.879a.32.32 0 0 1-.484.033l-.358-.325a.32.32 0 0 0-.484.032l-.378.483a.418.418 0 0 0 .036.54l1.32 1.266c.143.14.361.125.484-.033l6.272-8.048a.366.366 0 0 0-.064-.512zm-4.1 0-.478-.372a.365.365 0 0 0-.51.063L4.566 9.879a.32.32 0 0 1-.484.033L1.891 7.769a.366.366 0 0 0-.515.006l-.423.433a.364.364 0 0 0 .006.514l3.258 3.185c.143.14.361.125.484-.033l6.272-8.048a.365.365 0 0 0-.063-.51z'/%3E%3C/svg%3E"); } .chat-sdk-image-message { max-width: 100%; border-radius: 4px; margin-bottom: 4px; } .chat-sdk-input-area { display: flex; align-items: center; gap: 8px; padding: 12px 16px; background-color: #fff; border-top: 1px solid #e0e0e0; border-radius: 0 0 8px 8px; } .chat-sdk-input { flex: 1; padding: 9px 12px; border: 1px solid #e0e0e0; border-radius: 8px; font-size: 15px; line-height: 20px; outline: none; transition: border-color 0.2s; } .chat-sdk-input:focus { border-color: #00a884; } .chat-sdk-send-button { padding: 8px 12px; background-color: #00a884; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: background-color 0.2s; } .chat-sdk-send-button:hover { background-color: #008f72; } .chat-sdk-send-button:disabled { background-color: #85c7bb; cursor: not-allowed; } .chat-sdk-video-container { display: flex; flex-direction: column; height: 100%; min-height: 500px; max-height: 800px; background-color: #f0f2f5; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .chat-sdk-video-header { display: flex; align-items: center; padding: 12px 16px; background-color: #075e54; color: white; border-radius: 8px 8px 0 0; } .chat-sdk-video-grid { flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; padding: 16px; background-color: #1c1c1c; } .chat-sdk-video-wrapper { position: relative; padding-top: 56.25%; background-color: #2c2c2c; border-radius: 8px; overflow: hidden; } .chat-sdk-video-wrapper video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .chat-sdk-video-wrapper span { position: absolute; bottom: 8px; left: 8px; background-color: rgba(0, 0, 0, 0.6); color: white; padding: 4px 8px; border-radius: 4px; font-size: 14px; } .chat-sdk-video-controls { display: flex; justify-content: center; gap: 16px; padding: 16px; background-color: #075e54; border-radius: 0 0 8px 8px; } .chat-sdk-video-button { padding: 12px 24px; border-radius: 24px; border: none; cursor: pointer; font-weight: 500; font-size: 14px; transition: background-color 0.2s; } .chat-sdk-video-button.start { background-color: #25d366; color: white; } .chat-sdk-video-button.start:hover { background-color: #20bd5a; } .chat-sdk-video-button.start:disabled { background-color: #92e6b4; cursor: not-allowed; } .chat-sdk-video-button.end { background-color: #dc3545; color: white; } .chat-sdk-video-button.end:hover { background-color: #c82333; } .chat-sdk-video-button.end:disabled { background-color: #f1adb4; cursor: not-allowed; } .chat-sdk-call-status { font-size: 13px; color: #25d366; margin-top: 2px; } @media (max-width: 900px) { .video-call-container, .chat-sdk-container, .chat-sdk-video-container { max-width: 100%; min-height: 350px; max-height: none; border-radius: 0; } .video-grid, .chat-sdk-video-grid { grid-template-columns: 1fr; gap: 8px; padding: 8px; } } @media (max-width: 900px) { .chat-container, .chat-sdk-container { max-width: 100%; min-height: 350px; max-height: none; border-radius: 0; box-shadow: none; } .messages, .chat-sdk-messages { padding: 8px; } } @media (max-width: 600px) { .chat-container, .chat-sdk-container { border-radius: 0; min-height: 200px; max-height: none; box-shadow: none; padding: 0; } .chat-sdk-header { padding: 8px 8px; font-size: 15px; border-radius: 0; } .chat-sdk-user-details h3 { font-size: 14px; } .chat-sdk-messages, .messages { padding: 6px; } .chat-sdk-message, .message { max-width: 95%; font-size: 13px; padding: 5px 7px; margin: 4px 0; } .input-area, .chat-sdk-input-area { padding: 6px; gap: 4px; } .input-area input, .chat-sdk-input { font-size: 13px; padding: 6px 8px; } .chat-sdk-send-button, .input-area button { padding: 7px 10px; font-size: 13px; } .chat-sdk-avatar { width: 28px; height: 28px; } } @media (max-width: 400px) { .chat-sdk-header { flex-direction: column; align-items: flex-start; gap: 4px; } .chat-sdk-user-info { gap: 6px; } .chat-sdk-user-details h3 { font-size: 12px; } .chat-sdk-message, .message { font-size: 12px; padding: 4px 5px; } } @media (max-width: 600px) { .chat-container, .chat-sdk-container, .chat-sdk-video-container { border-radius: 0; min-height: 250px; max-height: none; box-shadow: none; padding: 0; } .chat-sdk-header, .chat-sdk-video-header { padding: 8px 8px; font-size: 15px; border-radius: 0; } .chat-sdk-user-details h3 { font-size: 14px; } .chat-sdk-messages, .messages, .chat-sdk-video-grid { padding: 8px; } .chat-sdk-message, .message { max-width: 90%; font-size: 13px; padding: 6px 8px; } .input-area, .chat-sdk-input-area { padding: 8px; gap: 4px; } .input-area input, .chat-sdk-input { font-size: 13px; padding: 6px 8px; } .controls, .chat-sdk-video-controls { gap: 8px; padding: 8px; } .controls button, .chat-sdk-video-button { padding: 8px 12px; font-size: 13px; } .chat-sdk-avatar { width: 32px; height: 32px; } } `); // src/components/Chat.tsx var Chat = ({ userId, receiverId, serverUrl, userName = "You", receiverName = "User", userAvatar, receiverAvatar, onSendMessage, onMessageReceived, onTyping, onError, customStyles }) => { const [messages, setMessages] = (0, import_react.useState)([]); const [inputMessage, setInputMessage] = (0, import_react.useState)(""); const [isTyping, setIsTyping] = (0, import_react.useState)(false); const [socket, setSocket] = (0, import_react.useState)(null); const [isConnected, setIsConnected] = (0, import_react.useState)(false); const messagesEndRef = (0, import_react.useRef)(null); const typingTimeoutRef = (0, import_react.useRef)(null); const processedMessages = (0, import_react.useRef)(/* @__PURE__ */ new Set()); const scrollToBottom = (0, import_react.useCallback)(() => { var _a; (_a = messagesEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" }); }, []); (0, import_react.useEffect)(() => { const newSocket = (0, import_socket.io)(serverUrl, { query: { userId }, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 1e3 }); newSocket.on("connect", () => { console.log("Connected to server"); setIsConnected(true); }); newSocket.on("disconnect", () => { console.log("Disconnected from server"); setIsConnected(false); }); newSocket.on("message", (message) => { if (!processedMessages.current.has(message.id)) { processedMessages.current.add(message.id); setMessages((prev) => [...prev, message]); onMessageReceived == null ? void 0 : onMessageReceived(message); scrollToBottom(); if (message.senderId === receiverId) { newSocket.emit("message_delivered", { messageId: message.id, senderId: message.senderId, receiverId: userId }); } } }); newSocket.on("message_delivered", ({ messageId }) => { setMessages( (prev) => prev.map( (msg) => msg.id === messageId ? { ...msg, status: "delivered" } : msg ) ); }); newSocket.on("message_read", ({ messageId }) => { setMessages( (prev) => prev.map( (msg) => msg.id === messageId ? { ...msg, status: "read" } : msg ) ); }); newSocket.on("typing", ({ userId: typingUserId, isTyping: isTyping2 }) => { if (typingUserId === receiverId) { setIsTyping(isTyping2); } }); newSocket.on("error", (error) => { console.error("Socket error:", error); onError == null ? void 0 : onError(error); }); fetch(`${serverUrl}/chat/history/${userId}/${receiverId}`).then((res) => res.json()).then((data) => { setMessages(data); data.forEach((msg) => { processedMessages.current.add(msg.id); }); scrollToBottom(); data.filter((msg) => msg.senderId === receiverId).forEach((msg) => { newSocket.emit("message_read", { messageId: msg.id, senderId: msg.senderId, receiverId: userId }); }); }).catch((error) => onError == null ? void 0 : onError(error)); setSocket(newSocket); return () => { newSocket.disconnect(); }; }, [userId, receiverId, serverUrl, onMessageReceived, onError, scrollToBottom]); const handleTyping = (0, import_react.useCallback)(() => { if (socket == null ? void 0 : socket.connected) { socket.emit("typing", { receiverId, isTyping: true }); onTyping == null ? void 0 : onTyping(true); if (typingTimeoutRef.current) { clearTimeout(typingTimeoutRef.current); } typingTimeoutRef.current = setTimeout(() => { socket.emit("typing", { receiverId, isTyping: false }); onTyping == null ? void 0 : onTyping(false); }, 1e3); } }, [socket, receiverId, onTyping]); const handleSendMessage = (0, import_react.useCallback)(async () => { if (!inputMessage.trim() || !(socket == null ? void 0 : socket.connected)) return; const message = { id: `${userId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, content: inputMessage.trim(), senderId: userId, receiverId, timestamp: Date.now(), status: "sent", type: "text" }; try { setMessages((prev) => [...prev, message]); processedMessages.current.add(message.id); scrollToBottom(); socket.emit("send_message", message); setInputMessage(""); onSendMessage == null ? void 0 : onSendMessage(message); } catch (error) { setMessages((prev) => prev.filter((msg) => msg.id !== message.id)); processedMessages.current.delete(message.id); onError == null ? void 0 : onError(error); } }, [inputMessage, socket, userId, receiverId, onSendMessage, onError, scrollToBottom]); const formatTime = (timestamp) => { return new Date(timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); }; return /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-container", style: customStyles == null ? void 0 : customStyles.container }, /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-header", style: customStyles == null ? void 0 : customStyles.header }, /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-user-info" }, receiverAvatar && /* @__PURE__ */ import_react.default.createElement( "img", { src: receiverAvatar, alt: receiverName, className: "chat-sdk-avatar" } ), /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-user-details" }, /* @__PURE__ */ import_react.default.createElement("h3", null, receiverName), isTyping && /* @__PURE__ */ import_react.default.createElement("span", { className: "chat-sdk-typing" }, "typing...")))), /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-messages", style: customStyles == null ? void 0 : customStyles.messageList }, messages.map((message) => { var _a, _b; return /* @__PURE__ */ import_react.default.createElement( "div", { key: message.id, className: `chat-sdk-message ${message.senderId === userId ? "chat-sdk-sent" : "chat-sdk-received"}`, style: message.senderId === userId ? (_a = customStyles == null ? void 0 : customStyles.messageBubble) == null ? void 0 : _a.sent : (_b = customStyles == null ? void 0 : customStyles.messageBubble) == null ? void 0 : _b.received }, message.type === "image" && message.fileUrl && /* @__PURE__ */ import_react.default.createElement( "img", { src: message.fileUrl, alt: message.fileName || "Image", className: "chat-sdk-image-message" } ), /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-message-content" }, /* @__PURE__ */ import_react.default.createElement("p", null, message.content), /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-message-meta" }, /* @__PURE__ */ import_react.default.createElement("time", null, formatTime(message.timestamp)), message.senderId === userId && /* @__PURE__ */ import_react.default.createElement("span", { className: `chat-sdk-status chat-sdk-${message.status}` }))) ); }), /* @__PURE__ */ import_react.default.createElement("div", { ref: messagesEndRef })), /* @__PURE__ */ import_react.default.createElement("div", { className: "chat-sdk-input-area", style: customStyles == null ? void 0 : customStyles.inputArea }, /* @__PURE__ */ import_react.default.createElement( "input", { type: "text", value: inputMessage, onChange: (e) => { setInputMessage(e.target.value); handleTyping(); }, onKeyPress: (e) => e.key === "Enter" && handleSendMessage(), placeholder: "Type a message...", className: "chat-sdk-input" } ), /* @__PURE__ */ import_react.default.createElement( "button", { onClick: handleSendMessage, className: "chat-sdk-send-button", style: customStyles == null ? void 0 : customStyles.button, disabled: !inputMessage.trim() }, "Bhej do" ))); }; // src/components/VideoCall.tsx var import_react2 = __toESM(require("react")); var import_socket2 = require("socket.io-client"); var import_webrtc_adapter = require("webrtc-adapter"); var VideoCall = ({ userId, receiverId, serverUrl, userName = "You", receiverName = "User", userAvatar, receiverAvatar, onCallReceived, onCallEnded, onCallStarted, onError }) => { const [socket, setSocket] = (0, import_react2.useState)(null); const peerConnection = (0, import_react2.useRef)(null); const localVideoRef = (0, import_react2.useRef)(null); const remoteVideoRef = (0, import_react2.useRef)(null); const localStream = (0, import_react2.useRef)(null); const [isCalling, setIsCalling] = (0, import_react2.useState)(false); (0, import_react2.useEffect)(() => { const newSocket = (0, import_socket2.io)(serverUrl); newSocket.on("connect", () => { newSocket.emit("register", userId); }); newSocket.on("call-received", (callerId) => { onCallReceived == null ? void 0 : onCallReceived(callerId); }); newSocket.on("call-ended", () => { handleEndCall(); onCallEnded == null ? void 0 : onCallEnded(); }); newSocket.on("offer", async ({ offer, callerId }) => { try { await handleOffer(offer, callerId); } catch (error) { onError == null ? void 0 : onError(error); } }); newSocket.on("answer", async ({ answer }) => { var _a; try { await ((_a = peerConnection.current) == null ? void 0 : _a.setRemoteDescription( new RTCSessionDescription(answer) )); } catch (error) { onError == null ? void 0 : onError(error); } }); newSocket.on("ice-candidate", async ({ candidate }) => { var _a; try { await ((_a = peerConnection.current) == null ? void 0 : _a.addIceCandidate( new RTCIceCandidate(candidate) )); } catch (error) { onError == null ? void 0 : onError(error); } }); setSocket(newSocket); return () => { handleEndCall(); newSocket.disconnect(); }; }, [userId, serverUrl, onCallReceived, onCallEnded, onError]); const setupPeerConnection = (0, import_react2.useCallback)(async () => { peerConnection.current = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.l.google.com:19302" }, { urls: "stun:stun1.l.google.com:19302" } ] }); peerConnection.current.onicecandidate = (event) => { if (event.candidate) { socket == null ? void 0 : socket.emit("ice-candidate", { candidate: event.candidate }); } }; peerConnection.current.ontrack = (event) => { if (remoteVideoRef.current) { remoteVideoRef.current.srcObject = event.streams[0]; } }; if (localStream.current) { localStream.current.getTracks().forEach((track) => { var _a; (_a = peerConnection.current) == null ? void 0 : _a.addTrack(track, localStream.current); }); } }, [socket]); const handleStartCall = async () => { try { localStream.current = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); if (localVideoRef.current) { localVideoRef.current.srcObject = localStream.current; } await setupPeerConnection(); const offer = await peerConnection.current.createOffer(); await peerConnection.current.setLocalDescription(offer); socket == null ? void 0 : socket.emit("call-user", { receiverId, offer }); setIsCalling(true); onCallStarted == null ? void 0 : onCallStarted(); } catch (error) { onError == null ? void 0 : onError(error); } }; const handleOffer = async (offer, callerId) => { try { localStream.current = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); if (localVideoRef.current) { localVideoRef.current.srcObject = localStream.current; } await setupPeerConnection(); await peerConnection.current.setRemoteDescription( new RTCSessionDescription(offer) ); const answer = await peerConnection.current.createAnswer(); await peerConnection.current.setLocalDescription(answer); socket == null ? void 0 : socket.emit("answer", { callerId, answer }); setIsCalling(true); } catch (error) { onError == null ? void 0 : onError(error); } }; const handleEndCall = () => { var _a, _b; (_a = localStream.current) == null ? void 0 : _a.getTracks().forEach((track) => track.stop()); (_b = peerConnection.current) == null ? void 0 : _b.close(); socket == null ? void 0 : socket.emit("end-call"); if (localVideoRef.current) { localVideoRef.current.srcObject = null; } if (remoteVideoRef.current) { remoteVideoRef.current.srcObject = null; } setIsCalling(false); localStream.current = null; peerConnection.current = null; }; return /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-container" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-header" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-user-info" }, receiverAvatar && /* @__PURE__ */ import_react2.default.createElement( "img", { src: receiverAvatar, alt: receiverName, className: "chat-sdk-avatar" } ), /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-user-details" }, /* @__PURE__ */ import_react2.default.createElement("h3", null, receiverName), isCalling && /* @__PURE__ */ import_react2.default.createElement("span", { className: "chat-sdk-call-status" }, "On call")))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-wrapper local" }, /* @__PURE__ */ import_react2.default.createElement( "video", { ref: localVideoRef, autoPlay: true, playsInline: true, muted: true } ), /* @__PURE__ */ import_react2.default.createElement("span", null, userName)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-wrapper remote" }, /* @__PURE__ */ import_react2.default.createElement( "video", { ref: remoteVideoRef, autoPlay: true, playsInline: true } ), /* @__PURE__ */ import_react2.default.createElement("span", null, receiverName))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "chat-sdk-video-controls" }, /* @__PURE__ */ import_react2.default.createElement( "button", { onClick: handleStartCall, className: "chat-sdk-video-button start", disabled: isCalling }, "Start Call" ), /* @__PURE__ */ import_react2.default.createElement( "button", { onClick: handleEndCall, className: "chat-sdk-video-button end", disabled: !isCalling }, "End Call" ))); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Chat, VideoCall }); //# sourceMappingURL=index.js.map