@dora-cell/sdk-react 0.1.1-beta.3
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/README.md +308 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +198 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +193 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# @dora-cell/sdk-react
|
|
2
|
+
|
|
3
|
+
React hooks and components for the Dora Cell VoIP SDK.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **React Hooks** - Easy-to-use hooks for call management
|
|
8
|
+
✅ **Context Provider** - Simple setup with DoraCellProvider
|
|
9
|
+
✅ **TypeScript support** - Full type definitions included
|
|
10
|
+
✅ **Auto state management** - Automatic call state and connection tracking
|
|
11
|
+
✅ **React 18 & 19 compatible** - Works with latest React versions
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @dora-cell/sdk @dora-cell/sdk-react jssip
|
|
17
|
+
# or
|
|
18
|
+
yarn add @dora-cell/sdk @dora-cell/sdk-react jssip
|
|
19
|
+
# or
|
|
20
|
+
pnpm add @dora-cell/sdk @dora-cell/sdk-react jssip
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Wrap your app with DoraCellProvider
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { DoraCellProvider } from '@dora-cell/sdk-react';
|
|
29
|
+
|
|
30
|
+
function App() {
|
|
31
|
+
return (
|
|
32
|
+
<DoraCellProvider
|
|
33
|
+
config={{
|
|
34
|
+
auth: {
|
|
35
|
+
type: 'api-token',
|
|
36
|
+
apiToken: 'your-api-token-here',
|
|
37
|
+
apiBaseUrl: 'https://api.usedora.com'
|
|
38
|
+
},
|
|
39
|
+
debug: true
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
<YourApp />
|
|
43
|
+
</DoraCellProvider>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Use hooks in your components
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useCall, useConnectionStatus } from '@dora-cell/sdk-react';
|
|
52
|
+
|
|
53
|
+
function CallInterface() {
|
|
54
|
+
const {
|
|
55
|
+
call,
|
|
56
|
+
hangup,
|
|
57
|
+
toggleMute,
|
|
58
|
+
callStatus,
|
|
59
|
+
callDuration,
|
|
60
|
+
isMuted,
|
|
61
|
+
currentCall
|
|
62
|
+
} = useCall();
|
|
63
|
+
|
|
64
|
+
const { isConnected, status } = useConnectionStatus();
|
|
65
|
+
const [number, setNumber] = useState('');
|
|
66
|
+
|
|
67
|
+
const handleCall = async () => {
|
|
68
|
+
try {
|
|
69
|
+
await call(number);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('Call failed:', error);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div>
|
|
77
|
+
<p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
|
|
78
|
+
|
|
79
|
+
{callStatus === 'idle' && (
|
|
80
|
+
<>
|
|
81
|
+
<input
|
|
82
|
+
value={number}
|
|
83
|
+
onChange={(e) => setNumber(e.target.value)}
|
|
84
|
+
placeholder="Enter phone number"
|
|
85
|
+
/>
|
|
86
|
+
<button onClick={handleCall} disabled={!isConnected}>
|
|
87
|
+
Call
|
|
88
|
+
</button>
|
|
89
|
+
</>
|
|
90
|
+
)}
|
|
91
|
+
|
|
92
|
+
{callStatus === 'ongoing' && (
|
|
93
|
+
<>
|
|
94
|
+
<p>Call with: {currentCall?.remoteNumber}</p>
|
|
95
|
+
<p>Duration: {callDuration}</p>
|
|
96
|
+
<button onClick={toggleMute}>
|
|
97
|
+
{isMuted ? 'Unmute' : 'Mute'}
|
|
98
|
+
</button>
|
|
99
|
+
<button onClick={hangup}>Hang Up</button>
|
|
100
|
+
</>
|
|
101
|
+
)}
|
|
102
|
+
|
|
103
|
+
{callStatus === 'ringing' && (
|
|
104
|
+
<p>Ringing...</p>
|
|
105
|
+
)}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API Reference
|
|
112
|
+
|
|
113
|
+
### DoraCellProvider
|
|
114
|
+
|
|
115
|
+
Wrap your app with this provider to enable SDK functionality.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<DoraCellProvider
|
|
119
|
+
config={{
|
|
120
|
+
auth: {
|
|
121
|
+
type: 'api-token',
|
|
122
|
+
apiToken: string,
|
|
123
|
+
apiBaseUrl?: string
|
|
124
|
+
},
|
|
125
|
+
turnServers?: RTCIceServer[],
|
|
126
|
+
debug?: boolean,
|
|
127
|
+
autoSelectExtension?: boolean
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{children}
|
|
131
|
+
</DoraCellProvider>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### useCall()
|
|
135
|
+
|
|
136
|
+
Hook for managing calls.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const {
|
|
140
|
+
// Methods
|
|
141
|
+
call: (phoneNumber: string) => Promise<void>,
|
|
142
|
+
hangup: () => void,
|
|
143
|
+
answerCall: () => void,
|
|
144
|
+
toggleMute: () => void,
|
|
145
|
+
|
|
146
|
+
// State
|
|
147
|
+
callStatus: 'idle' | 'ringing' | 'ongoing',
|
|
148
|
+
callDuration: string, // Formatted as "MM:SS"
|
|
149
|
+
isMuted: boolean,
|
|
150
|
+
currentCall: Call | null,
|
|
151
|
+
error: Error | null
|
|
152
|
+
} = useCall();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Methods:**
|
|
156
|
+
- `call(phoneNumber)` - Make an outbound call
|
|
157
|
+
- `hangup()` - End the current call
|
|
158
|
+
- `answerCall()` - Answer an incoming call
|
|
159
|
+
- `toggleMute()` - Toggle mute/unmute
|
|
160
|
+
|
|
161
|
+
**State:**
|
|
162
|
+
- `callStatus` - Current call status
|
|
163
|
+
- `callDuration` - Formatted call duration (e.g., "01:23")
|
|
164
|
+
- `isMuted` - Whether the call is muted
|
|
165
|
+
- `currentCall` - Current call object with details
|
|
166
|
+
- `error` - Any call-related errors
|
|
167
|
+
|
|
168
|
+
### useConnectionStatus()
|
|
169
|
+
|
|
170
|
+
Hook for monitoring connection status.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const {
|
|
174
|
+
isConnected: boolean,
|
|
175
|
+
status: 'disconnected' | 'connecting' | 'connected' | 'error',
|
|
176
|
+
error: Error | null
|
|
177
|
+
} = useConnectionStatus();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### useDoraCell()
|
|
181
|
+
|
|
182
|
+
Access the underlying SDK instance directly.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const sdk = useDoraCell();
|
|
186
|
+
|
|
187
|
+
// Use SDK methods directly
|
|
188
|
+
sdk.getExtensions();
|
|
189
|
+
sdk.on('call:incoming', (call) => {
|
|
190
|
+
console.log('Incoming call from:', call.remoteNumber);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Advanced Usage
|
|
195
|
+
|
|
196
|
+
### Handling Incoming Calls
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
function IncomingCallHandler() {
|
|
200
|
+
const { currentCall, answerCall, hangup, callStatus } = useCall();
|
|
201
|
+
const sdk = useDoraCell();
|
|
202
|
+
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
const handleIncoming = (call) => {
|
|
205
|
+
// Show notification or UI for incoming call
|
|
206
|
+
console.log('Incoming call from:', call.remoteNumber);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
sdk.on('call:incoming', handleIncoming);
|
|
210
|
+
return () => sdk.off('call:incoming', handleIncoming);
|
|
211
|
+
}, [sdk]);
|
|
212
|
+
|
|
213
|
+
if (callStatus === 'ringing' && currentCall?.direction === 'inbound') {
|
|
214
|
+
return (
|
|
215
|
+
<div>
|
|
216
|
+
<p>Incoming call from {currentCall.remoteNumber}</p>
|
|
217
|
+
<button onClick={answerCall}>Answer</button>
|
|
218
|
+
<button onClick={hangup}>Decline</button>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Custom Extension Selection
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
function CallWithExtension() {
|
|
231
|
+
const sdk = useDoraCell();
|
|
232
|
+
const [selectedExtension, setSelectedExtension] = useState('');
|
|
233
|
+
|
|
234
|
+
const extensions = sdk.getExtensions();
|
|
235
|
+
|
|
236
|
+
const makeCall = async (number: string) => {
|
|
237
|
+
await sdk.call(number, { extension: selectedExtension });
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
return (
|
|
241
|
+
<div>
|
|
242
|
+
<select
|
|
243
|
+
value={selectedExtension}
|
|
244
|
+
onChange={(e) => setSelectedExtension(e.target.value)}
|
|
245
|
+
>
|
|
246
|
+
{extensions.map(ext => (
|
|
247
|
+
<option key={ext} value={ext}>{ext}</option>
|
|
248
|
+
))}
|
|
249
|
+
</select>
|
|
250
|
+
{/* Rest of your call UI */}
|
|
251
|
+
</div>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Error Handling
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
function CallWithErrorHandling() {
|
|
260
|
+
const { call, error, callStatus } = useCall();
|
|
261
|
+
const [number, setNumber] = useState('');
|
|
262
|
+
|
|
263
|
+
const handleCall = async () => {
|
|
264
|
+
try {
|
|
265
|
+
await call(number);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
console.error('Call failed:', err);
|
|
268
|
+
// Show error to user
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<div>
|
|
274
|
+
{error && <div className="error">{error.message}</div>}
|
|
275
|
+
{/* Rest of your UI */}
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## TypeScript Support
|
|
282
|
+
|
|
283
|
+
All hooks and components are fully typed. Import types as needed:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import type { Call, CallStatus, ConnectionStatus } from '@dora-cell/sdk';
|
|
287
|
+
import type { DoraCellConfig } from '@dora-cell/sdk-react';
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Examples
|
|
291
|
+
|
|
292
|
+
See the `/examples` directory in the main repository for complete working examples:
|
|
293
|
+
- `react-app/` - React application with hooks
|
|
294
|
+
- `nextjs-app/` - Next.js application
|
|
295
|
+
|
|
296
|
+
## Requirements
|
|
297
|
+
|
|
298
|
+
- React 18.0.0 or higher (including React 19)
|
|
299
|
+
- @dora-cell/sdk (peer dependency)
|
|
300
|
+
- jssip (peer dependency)
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|
|
305
|
+
|
|
306
|
+
## Related Packages
|
|
307
|
+
|
|
308
|
+
- [@dora-cell/sdk](https://www.npmjs.com/package/@dora-cell/sdk) - Core VoIP SDK
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { DoraCellConfig, CallStatus, Call, ConnectionStatus, DoraCell } from '@dora-cell/sdk';
|
|
4
|
+
|
|
5
|
+
interface DoraCellContextValue {
|
|
6
|
+
sdk: DoraCell | null;
|
|
7
|
+
connectionStatus: ConnectionStatus;
|
|
8
|
+
currentCall: Call | null;
|
|
9
|
+
callStatus: CallStatus;
|
|
10
|
+
callDuration: string;
|
|
11
|
+
isMuted: boolean;
|
|
12
|
+
isInitialized: boolean;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
call: (phoneNumber: string, extension?: string) => Promise<void>;
|
|
15
|
+
hangup: () => void;
|
|
16
|
+
toggleMute: () => void;
|
|
17
|
+
answerCall: () => void;
|
|
18
|
+
}
|
|
19
|
+
interface DoraCellProviderProps {
|
|
20
|
+
config: DoraCellConfig;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
autoInitialize?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function DoraCellProvider({ config, children, autoInitialize, }: DoraCellProviderProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
/**
|
|
26
|
+
* Hook to access Dora Cell SDK context
|
|
27
|
+
*/
|
|
28
|
+
declare function useDoraCell(): DoraCellContextValue;
|
|
29
|
+
/**
|
|
30
|
+
* Hook for making calls
|
|
31
|
+
*/
|
|
32
|
+
declare function useCall(): {
|
|
33
|
+
call: (phoneNumber: string, extension?: string) => Promise<void>;
|
|
34
|
+
hangup: () => void;
|
|
35
|
+
toggleMute: () => void;
|
|
36
|
+
callStatus: CallStatus;
|
|
37
|
+
callDuration: string;
|
|
38
|
+
isMuted: boolean;
|
|
39
|
+
currentCall: Call | null;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Hook for connection status
|
|
43
|
+
*/
|
|
44
|
+
declare function useConnectionStatus(): {
|
|
45
|
+
connectionStatus: ConnectionStatus;
|
|
46
|
+
isInitialized: boolean;
|
|
47
|
+
isConnected: boolean;
|
|
48
|
+
error: Error | null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { DoraCellProvider, type DoraCellProviderProps, useCall, useConnectionStatus, useDoraCell };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { DoraCellConfig, CallStatus, Call, ConnectionStatus, DoraCell } from '@dora-cell/sdk';
|
|
4
|
+
|
|
5
|
+
interface DoraCellContextValue {
|
|
6
|
+
sdk: DoraCell | null;
|
|
7
|
+
connectionStatus: ConnectionStatus;
|
|
8
|
+
currentCall: Call | null;
|
|
9
|
+
callStatus: CallStatus;
|
|
10
|
+
callDuration: string;
|
|
11
|
+
isMuted: boolean;
|
|
12
|
+
isInitialized: boolean;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
call: (phoneNumber: string, extension?: string) => Promise<void>;
|
|
15
|
+
hangup: () => void;
|
|
16
|
+
toggleMute: () => void;
|
|
17
|
+
answerCall: () => void;
|
|
18
|
+
}
|
|
19
|
+
interface DoraCellProviderProps {
|
|
20
|
+
config: DoraCellConfig;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
autoInitialize?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function DoraCellProvider({ config, children, autoInitialize, }: DoraCellProviderProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
/**
|
|
26
|
+
* Hook to access Dora Cell SDK context
|
|
27
|
+
*/
|
|
28
|
+
declare function useDoraCell(): DoraCellContextValue;
|
|
29
|
+
/**
|
|
30
|
+
* Hook for making calls
|
|
31
|
+
*/
|
|
32
|
+
declare function useCall(): {
|
|
33
|
+
call: (phoneNumber: string, extension?: string) => Promise<void>;
|
|
34
|
+
hangup: () => void;
|
|
35
|
+
toggleMute: () => void;
|
|
36
|
+
callStatus: CallStatus;
|
|
37
|
+
callDuration: string;
|
|
38
|
+
isMuted: boolean;
|
|
39
|
+
currentCall: Call | null;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Hook for connection status
|
|
43
|
+
*/
|
|
44
|
+
declare function useConnectionStatus(): {
|
|
45
|
+
connectionStatus: ConnectionStatus;
|
|
46
|
+
isInitialized: boolean;
|
|
47
|
+
isConnected: boolean;
|
|
48
|
+
error: Error | null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { DoraCellProvider, type DoraCellProviderProps, useCall, useConnectionStatus, useDoraCell };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var sdk = require('@dora-cell/sdk');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
var DoraCellContext = react.createContext(void 0);
|
|
8
|
+
function DoraCellProvider({
|
|
9
|
+
config,
|
|
10
|
+
children,
|
|
11
|
+
autoInitialize = true
|
|
12
|
+
}) {
|
|
13
|
+
const [sdk$1] = react.useState(() => new sdk.DoraCell(config));
|
|
14
|
+
const [isInitialized, setIsInitialized] = react.useState(false);
|
|
15
|
+
const [connectionStatus, setConnectionStatus] = react.useState("disconnected");
|
|
16
|
+
const [currentCall, setCurrentCall] = react.useState(null);
|
|
17
|
+
const [callStatus, setCallStatus] = react.useState("idle");
|
|
18
|
+
const [callDuration, setCallDuration] = react.useState("00:00");
|
|
19
|
+
const [isMuted, setIsMuted] = react.useState(false);
|
|
20
|
+
const [error, setError] = react.useState(null);
|
|
21
|
+
const durationIntervalRef = react.useRef(null);
|
|
22
|
+
react.useEffect(() => {
|
|
23
|
+
if (!autoInitialize) return;
|
|
24
|
+
const initializeSdk = async () => {
|
|
25
|
+
try {
|
|
26
|
+
await sdk$1.initialize();
|
|
27
|
+
setIsInitialized(true);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
setError(err instanceof Error ? err : new Error("Failed to initialize SDK"));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
initializeSdk();
|
|
33
|
+
return () => {
|
|
34
|
+
sdk$1.destroy();
|
|
35
|
+
};
|
|
36
|
+
}, [sdk$1, autoInitialize]);
|
|
37
|
+
react.useEffect(() => {
|
|
38
|
+
if (!sdk$1) return;
|
|
39
|
+
const handleConnectionStatus = (state) => {
|
|
40
|
+
setConnectionStatus(state.status);
|
|
41
|
+
if (state.error) {
|
|
42
|
+
setError(new Error(state.error));
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const handleIncomingCall = (call2) => {
|
|
46
|
+
setCurrentCall(call2);
|
|
47
|
+
setCallStatus("ringing");
|
|
48
|
+
};
|
|
49
|
+
const handleOutgoingCall = (call2) => {
|
|
50
|
+
setCurrentCall(call2);
|
|
51
|
+
setCallStatus("connecting");
|
|
52
|
+
};
|
|
53
|
+
const handleCallRinging = (call2) => {
|
|
54
|
+
setCallStatus("ringing");
|
|
55
|
+
};
|
|
56
|
+
const handleCallConnected = (call2) => {
|
|
57
|
+
setCallStatus("ongoing");
|
|
58
|
+
};
|
|
59
|
+
const handleCallEnded = (call2) => {
|
|
60
|
+
setCallStatus("ended");
|
|
61
|
+
setCurrentCall(null);
|
|
62
|
+
setIsMuted(false);
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
setCallStatus("idle");
|
|
65
|
+
}, 3e3);
|
|
66
|
+
};
|
|
67
|
+
const handleCallFailed = (call2, errorMsg) => {
|
|
68
|
+
setError(new Error(errorMsg));
|
|
69
|
+
setCallStatus("ended");
|
|
70
|
+
setCurrentCall(null);
|
|
71
|
+
};
|
|
72
|
+
const handleError = (err) => {
|
|
73
|
+
setError(err);
|
|
74
|
+
};
|
|
75
|
+
sdk$1.on("connection:status", handleConnectionStatus);
|
|
76
|
+
sdk$1.on("call:incoming", handleIncomingCall);
|
|
77
|
+
sdk$1.on("call:outgoing", handleOutgoingCall);
|
|
78
|
+
sdk$1.on("call:ringing", handleCallRinging);
|
|
79
|
+
sdk$1.on("call:connected", handleCallConnected);
|
|
80
|
+
sdk$1.on("call:ended", handleCallEnded);
|
|
81
|
+
sdk$1.on("call:failed", handleCallFailed);
|
|
82
|
+
sdk$1.on("error", handleError);
|
|
83
|
+
return () => {
|
|
84
|
+
sdk$1.off("connection:status", handleConnectionStatus);
|
|
85
|
+
sdk$1.off("call:incoming", handleIncomingCall);
|
|
86
|
+
sdk$1.off("call:outgoing", handleOutgoingCall);
|
|
87
|
+
sdk$1.off("call:ringing", handleCallRinging);
|
|
88
|
+
sdk$1.off("call:connected", handleCallConnected);
|
|
89
|
+
sdk$1.off("call:ended", handleCallEnded);
|
|
90
|
+
sdk$1.off("call:failed", handleCallFailed);
|
|
91
|
+
sdk$1.off("error", handleError);
|
|
92
|
+
};
|
|
93
|
+
}, [sdk$1]);
|
|
94
|
+
react.useEffect(() => {
|
|
95
|
+
if (callStatus === "ongoing" && currentCall) {
|
|
96
|
+
durationIntervalRef.current = window.setInterval(() => {
|
|
97
|
+
const duration = currentCall.duration;
|
|
98
|
+
const mm = String(Math.floor(duration / 60)).padStart(2, "0");
|
|
99
|
+
const ss = String(duration % 60).padStart(2, "0");
|
|
100
|
+
setCallDuration(`${mm}:${ss}`);
|
|
101
|
+
}, 1e3);
|
|
102
|
+
} else {
|
|
103
|
+
setCallDuration("00:00");
|
|
104
|
+
if (durationIntervalRef.current) {
|
|
105
|
+
clearInterval(durationIntervalRef.current);
|
|
106
|
+
durationIntervalRef.current = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return () => {
|
|
110
|
+
if (durationIntervalRef.current) {
|
|
111
|
+
clearInterval(durationIntervalRef.current);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}, [callStatus, currentCall]);
|
|
115
|
+
const call = async (phoneNumber, extension) => {
|
|
116
|
+
try {
|
|
117
|
+
setError(null);
|
|
118
|
+
await sdk$1.call(phoneNumber, { extension });
|
|
119
|
+
} catch (err) {
|
|
120
|
+
setError(err instanceof Error ? err : new Error("Failed to make call"));
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const hangup = () => {
|
|
125
|
+
try {
|
|
126
|
+
sdk$1.hangup();
|
|
127
|
+
} catch (err) {
|
|
128
|
+
setError(err instanceof Error ? err : new Error("Failed to hang up"));
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const toggleMute = () => {
|
|
132
|
+
if (!currentCall) return;
|
|
133
|
+
if (isMuted) {
|
|
134
|
+
currentCall.unmute();
|
|
135
|
+
setIsMuted(false);
|
|
136
|
+
} else {
|
|
137
|
+
currentCall.mute();
|
|
138
|
+
setIsMuted(true);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const answerCall = () => {
|
|
142
|
+
try {
|
|
143
|
+
sdk$1.answerCall();
|
|
144
|
+
} catch (err) {
|
|
145
|
+
setError(err instanceof Error ? err : new Error("Failed to answer call"));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const contextValue = {
|
|
149
|
+
sdk: sdk$1,
|
|
150
|
+
connectionStatus,
|
|
151
|
+
currentCall,
|
|
152
|
+
callStatus,
|
|
153
|
+
callDuration,
|
|
154
|
+
isMuted,
|
|
155
|
+
isInitialized,
|
|
156
|
+
error,
|
|
157
|
+
call,
|
|
158
|
+
hangup,
|
|
159
|
+
toggleMute,
|
|
160
|
+
answerCall
|
|
161
|
+
};
|
|
162
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DoraCellContext.Provider, { value: contextValue, children });
|
|
163
|
+
}
|
|
164
|
+
function useDoraCell() {
|
|
165
|
+
const context = react.useContext(DoraCellContext);
|
|
166
|
+
if (!context) {
|
|
167
|
+
throw new Error("useDoraCell must be used within DoraCellProvider");
|
|
168
|
+
}
|
|
169
|
+
return context;
|
|
170
|
+
}
|
|
171
|
+
function useCall() {
|
|
172
|
+
const { call, hangup, toggleMute, callStatus, callDuration, isMuted, currentCall } = useDoraCell();
|
|
173
|
+
return {
|
|
174
|
+
call,
|
|
175
|
+
hangup,
|
|
176
|
+
toggleMute,
|
|
177
|
+
callStatus,
|
|
178
|
+
callDuration,
|
|
179
|
+
isMuted,
|
|
180
|
+
currentCall
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function useConnectionStatus() {
|
|
184
|
+
const { connectionStatus, isInitialized, error } = useDoraCell();
|
|
185
|
+
return {
|
|
186
|
+
connectionStatus,
|
|
187
|
+
isInitialized,
|
|
188
|
+
isConnected: connectionStatus === "registered",
|
|
189
|
+
error
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
exports.DoraCellProvider = DoraCellProvider;
|
|
194
|
+
exports.useCall = useCall;
|
|
195
|
+
exports.useConnectionStatus = useConnectionStatus;
|
|
196
|
+
exports.useDoraCell = useDoraCell;
|
|
197
|
+
//# sourceMappingURL=index.js.map
|
|
198
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["createContext","sdk","useState","DoraCell","useRef","useEffect","call","useContext"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * React bindings for Dora Cell SDK\n * Provides React Context and hooks for easy integration\n */\n\n'use client';\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react';\nimport { DoraCell } from '@dora-cell/sdk';\nimport type {\n DoraCellConfig,\n Call,\n CallStatus,\n ConnectionStatus,\n ConnectionState,\n} from '@dora-cell/sdk';\n\ninterface DoraCellContextValue {\n sdk: DoraCell | null;\n connectionStatus: ConnectionStatus;\n currentCall: Call | null;\n callStatus: CallStatus;\n callDuration: string;\n isMuted: boolean;\n isInitialized: boolean;\n error: Error | null;\n\n // Methods\n call: (phoneNumber: string, extension?: string) => Promise<void>;\n hangup: () => void;\n toggleMute: () => void;\n answerCall: () => void;\n}\n\nconst DoraCellContext = createContext<DoraCellContextValue | undefined>(undefined);\n\nexport interface DoraCellProviderProps {\n config: DoraCellConfig;\n children: React.ReactNode;\n autoInitialize?: boolean;\n}\n\nexport function DoraCellProvider({\n config,\n children,\n autoInitialize = true,\n}: DoraCellProviderProps) {\n const [sdk] = useState(() => new DoraCell(config));\n const [isInitialized, setIsInitialized] = useState(false);\n const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>('disconnected');\n const [currentCall, setCurrentCall] = useState<Call | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus>('idle');\n const [callDuration, setCallDuration] = useState('00:00');\n const [isMuted, setIsMuted] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const durationIntervalRef = useRef<number | null>(null);\n\n // Initialize SDK\n useEffect(() => {\n if (!autoInitialize) return;\n\n const initializeSdk = async () => {\n try {\n await sdk.initialize();\n setIsInitialized(true);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to initialize SDK'));\n }\n };\n\n initializeSdk();\n\n return () => {\n sdk.destroy();\n };\n }, [sdk, autoInitialize]);\n\n // Set up event listeners\n useEffect(() => {\n if (!sdk) return;\n\n const handleConnectionStatus = (state: ConnectionState) => {\n setConnectionStatus(state.status);\n if (state.error) {\n setError(new Error(state.error));\n }\n };\n\n const handleIncomingCall = (call: Call) => {\n setCurrentCall(call);\n setCallStatus('ringing');\n };\n\n const handleOutgoingCall = (call: Call) => {\n setCurrentCall(call);\n setCallStatus('connecting');\n };\n\n const handleCallRinging = (call: Call) => {\n setCallStatus('ringing');\n };\n\n const handleCallConnected = (call: Call) => {\n setCallStatus('ongoing');\n };\n\n const handleCallEnded = (call: Call) => {\n setCallStatus('ended');\n setCurrentCall(null);\n setIsMuted(false);\n\n // Reset to idle after a delay\n setTimeout(() => {\n setCallStatus('idle');\n }, 3000);\n };\n\n const handleCallFailed = (call: Call, errorMsg: string) => {\n setError(new Error(errorMsg));\n setCallStatus('ended');\n setCurrentCall(null);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n };\n\n sdk.on('connection:status', handleConnectionStatus);\n sdk.on('call:incoming', handleIncomingCall);\n sdk.on('call:outgoing', handleOutgoingCall);\n sdk.on('call:ringing', handleCallRinging);\n sdk.on('call:connected', handleCallConnected);\n sdk.on('call:ended', handleCallEnded);\n sdk.on('call:failed', handleCallFailed);\n sdk.on('error', handleError);\n\n return () => {\n sdk.off('connection:status', handleConnectionStatus);\n sdk.off('call:incoming', handleIncomingCall);\n sdk.off('call:outgoing', handleOutgoingCall);\n sdk.off('call:ringing', handleCallRinging);\n sdk.off('call:connected', handleCallConnected);\n sdk.off('call:ended', handleCallEnded);\n sdk.off('call:failed', handleCallFailed);\n sdk.off('error', handleError);\n };\n }, [sdk]);\n\n // Update call duration\n useEffect(() => {\n if (callStatus === 'ongoing' && currentCall) {\n durationIntervalRef.current = window.setInterval(() => {\n const duration = currentCall.duration;\n const mm = String(Math.floor(duration / 60)).padStart(2, '0');\n const ss = String(duration % 60).padStart(2, '0');\n setCallDuration(`${mm}:${ss}`);\n }, 1000);\n } else {\n setCallDuration('00:00');\n if (durationIntervalRef.current) {\n clearInterval(durationIntervalRef.current);\n durationIntervalRef.current = null;\n }\n }\n\n return () => {\n if (durationIntervalRef.current) {\n clearInterval(durationIntervalRef.current);\n }\n };\n }, [callStatus, currentCall]);\n\n // Methods\n const call = async (phoneNumber: string, extension?: string) => {\n try {\n setError(null);\n await sdk.call(phoneNumber, { extension });\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to make call'));\n throw err;\n }\n };\n\n const hangup = () => {\n try {\n sdk.hangup();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to hang up'));\n }\n };\n\n const toggleMute = () => {\n if (!currentCall) return;\n\n if (isMuted) {\n currentCall.unmute();\n setIsMuted(false);\n } else {\n currentCall.mute();\n setIsMuted(true);\n }\n };\n\n const answerCall = () => {\n try {\n sdk.answerCall();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to answer call'));\n }\n };\n\n const contextValue: DoraCellContextValue = {\n sdk,\n connectionStatus,\n currentCall,\n callStatus,\n callDuration,\n isMuted,\n isInitialized,\n error,\n call,\n hangup,\n toggleMute,\n answerCall,\n };\n\n return (\n <DoraCellContext.Provider value={contextValue}>\n {children}\n </DoraCellContext.Provider>\n );\n}\n\n/**\n * Hook to access Dora Cell SDK context\n */\nexport function useDoraCell(): DoraCellContextValue {\n const context = useContext(DoraCellContext);\n if (!context) {\n throw new Error('useDoraCell must be used within DoraCellProvider');\n }\n return context;\n}\n\n/**\n * Hook for making calls\n */\nexport function useCall() {\n const { call, hangup, toggleMute, callStatus, callDuration, isMuted, currentCall } = useDoraCell();\n\n return {\n call,\n hangup,\n toggleMute,\n callStatus,\n callDuration,\n isMuted,\n currentCall,\n };\n}\n\n/**\n * Hook for connection status\n */\nexport function useConnectionStatus() {\n const { connectionStatus, isInitialized, error } = useDoraCell();\n\n return {\n connectionStatus,\n isInitialized,\n isConnected: connectionStatus === 'registered',\n error,\n };\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { createContext, useState, useRef, useEffect, useContext } from 'react';
|
|
2
|
+
import { DoraCell } from '@dora-cell/sdk';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var DoraCellContext = createContext(void 0);
|
|
6
|
+
function DoraCellProvider({
|
|
7
|
+
config,
|
|
8
|
+
children,
|
|
9
|
+
autoInitialize = true
|
|
10
|
+
}) {
|
|
11
|
+
const [sdk] = useState(() => new DoraCell(config));
|
|
12
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
13
|
+
const [connectionStatus, setConnectionStatus] = useState("disconnected");
|
|
14
|
+
const [currentCall, setCurrentCall] = useState(null);
|
|
15
|
+
const [callStatus, setCallStatus] = useState("idle");
|
|
16
|
+
const [callDuration, setCallDuration] = useState("00:00");
|
|
17
|
+
const [isMuted, setIsMuted] = useState(false);
|
|
18
|
+
const [error, setError] = useState(null);
|
|
19
|
+
const durationIntervalRef = useRef(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!autoInitialize) return;
|
|
22
|
+
const initializeSdk = async () => {
|
|
23
|
+
try {
|
|
24
|
+
await sdk.initialize();
|
|
25
|
+
setIsInitialized(true);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
setError(err instanceof Error ? err : new Error("Failed to initialize SDK"));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
initializeSdk();
|
|
31
|
+
return () => {
|
|
32
|
+
sdk.destroy();
|
|
33
|
+
};
|
|
34
|
+
}, [sdk, autoInitialize]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!sdk) return;
|
|
37
|
+
const handleConnectionStatus = (state) => {
|
|
38
|
+
setConnectionStatus(state.status);
|
|
39
|
+
if (state.error) {
|
|
40
|
+
setError(new Error(state.error));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const handleIncomingCall = (call2) => {
|
|
44
|
+
setCurrentCall(call2);
|
|
45
|
+
setCallStatus("ringing");
|
|
46
|
+
};
|
|
47
|
+
const handleOutgoingCall = (call2) => {
|
|
48
|
+
setCurrentCall(call2);
|
|
49
|
+
setCallStatus("connecting");
|
|
50
|
+
};
|
|
51
|
+
const handleCallRinging = (call2) => {
|
|
52
|
+
setCallStatus("ringing");
|
|
53
|
+
};
|
|
54
|
+
const handleCallConnected = (call2) => {
|
|
55
|
+
setCallStatus("ongoing");
|
|
56
|
+
};
|
|
57
|
+
const handleCallEnded = (call2) => {
|
|
58
|
+
setCallStatus("ended");
|
|
59
|
+
setCurrentCall(null);
|
|
60
|
+
setIsMuted(false);
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
setCallStatus("idle");
|
|
63
|
+
}, 3e3);
|
|
64
|
+
};
|
|
65
|
+
const handleCallFailed = (call2, errorMsg) => {
|
|
66
|
+
setError(new Error(errorMsg));
|
|
67
|
+
setCallStatus("ended");
|
|
68
|
+
setCurrentCall(null);
|
|
69
|
+
};
|
|
70
|
+
const handleError = (err) => {
|
|
71
|
+
setError(err);
|
|
72
|
+
};
|
|
73
|
+
sdk.on("connection:status", handleConnectionStatus);
|
|
74
|
+
sdk.on("call:incoming", handleIncomingCall);
|
|
75
|
+
sdk.on("call:outgoing", handleOutgoingCall);
|
|
76
|
+
sdk.on("call:ringing", handleCallRinging);
|
|
77
|
+
sdk.on("call:connected", handleCallConnected);
|
|
78
|
+
sdk.on("call:ended", handleCallEnded);
|
|
79
|
+
sdk.on("call:failed", handleCallFailed);
|
|
80
|
+
sdk.on("error", handleError);
|
|
81
|
+
return () => {
|
|
82
|
+
sdk.off("connection:status", handleConnectionStatus);
|
|
83
|
+
sdk.off("call:incoming", handleIncomingCall);
|
|
84
|
+
sdk.off("call:outgoing", handleOutgoingCall);
|
|
85
|
+
sdk.off("call:ringing", handleCallRinging);
|
|
86
|
+
sdk.off("call:connected", handleCallConnected);
|
|
87
|
+
sdk.off("call:ended", handleCallEnded);
|
|
88
|
+
sdk.off("call:failed", handleCallFailed);
|
|
89
|
+
sdk.off("error", handleError);
|
|
90
|
+
};
|
|
91
|
+
}, [sdk]);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (callStatus === "ongoing" && currentCall) {
|
|
94
|
+
durationIntervalRef.current = window.setInterval(() => {
|
|
95
|
+
const duration = currentCall.duration;
|
|
96
|
+
const mm = String(Math.floor(duration / 60)).padStart(2, "0");
|
|
97
|
+
const ss = String(duration % 60).padStart(2, "0");
|
|
98
|
+
setCallDuration(`${mm}:${ss}`);
|
|
99
|
+
}, 1e3);
|
|
100
|
+
} else {
|
|
101
|
+
setCallDuration("00:00");
|
|
102
|
+
if (durationIntervalRef.current) {
|
|
103
|
+
clearInterval(durationIntervalRef.current);
|
|
104
|
+
durationIntervalRef.current = null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return () => {
|
|
108
|
+
if (durationIntervalRef.current) {
|
|
109
|
+
clearInterval(durationIntervalRef.current);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}, [callStatus, currentCall]);
|
|
113
|
+
const call = async (phoneNumber, extension) => {
|
|
114
|
+
try {
|
|
115
|
+
setError(null);
|
|
116
|
+
await sdk.call(phoneNumber, { extension });
|
|
117
|
+
} catch (err) {
|
|
118
|
+
setError(err instanceof Error ? err : new Error("Failed to make call"));
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const hangup = () => {
|
|
123
|
+
try {
|
|
124
|
+
sdk.hangup();
|
|
125
|
+
} catch (err) {
|
|
126
|
+
setError(err instanceof Error ? err : new Error("Failed to hang up"));
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const toggleMute = () => {
|
|
130
|
+
if (!currentCall) return;
|
|
131
|
+
if (isMuted) {
|
|
132
|
+
currentCall.unmute();
|
|
133
|
+
setIsMuted(false);
|
|
134
|
+
} else {
|
|
135
|
+
currentCall.mute();
|
|
136
|
+
setIsMuted(true);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const answerCall = () => {
|
|
140
|
+
try {
|
|
141
|
+
sdk.answerCall();
|
|
142
|
+
} catch (err) {
|
|
143
|
+
setError(err instanceof Error ? err : new Error("Failed to answer call"));
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const contextValue = {
|
|
147
|
+
sdk,
|
|
148
|
+
connectionStatus,
|
|
149
|
+
currentCall,
|
|
150
|
+
callStatus,
|
|
151
|
+
callDuration,
|
|
152
|
+
isMuted,
|
|
153
|
+
isInitialized,
|
|
154
|
+
error,
|
|
155
|
+
call,
|
|
156
|
+
hangup,
|
|
157
|
+
toggleMute,
|
|
158
|
+
answerCall
|
|
159
|
+
};
|
|
160
|
+
return /* @__PURE__ */ jsx(DoraCellContext.Provider, { value: contextValue, children });
|
|
161
|
+
}
|
|
162
|
+
function useDoraCell() {
|
|
163
|
+
const context = useContext(DoraCellContext);
|
|
164
|
+
if (!context) {
|
|
165
|
+
throw new Error("useDoraCell must be used within DoraCellProvider");
|
|
166
|
+
}
|
|
167
|
+
return context;
|
|
168
|
+
}
|
|
169
|
+
function useCall() {
|
|
170
|
+
const { call, hangup, toggleMute, callStatus, callDuration, isMuted, currentCall } = useDoraCell();
|
|
171
|
+
return {
|
|
172
|
+
call,
|
|
173
|
+
hangup,
|
|
174
|
+
toggleMute,
|
|
175
|
+
callStatus,
|
|
176
|
+
callDuration,
|
|
177
|
+
isMuted,
|
|
178
|
+
currentCall
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function useConnectionStatus() {
|
|
182
|
+
const { connectionStatus, isInitialized, error } = useDoraCell();
|
|
183
|
+
return {
|
|
184
|
+
connectionStatus,
|
|
185
|
+
isInitialized,
|
|
186
|
+
isConnected: connectionStatus === "registered",
|
|
187
|
+
error
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { DoraCellProvider, useCall, useConnectionStatus, useDoraCell };
|
|
192
|
+
//# sourceMappingURL=index.mjs.map
|
|
193
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["call"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * React bindings for Dora Cell SDK\n * Provides React Context and hooks for easy integration\n */\n\n'use client';\n\nimport React, { createContext, useContext, useEffect, useState, useRef } from 'react';\nimport { DoraCell } from '@dora-cell/sdk';\nimport type {\n DoraCellConfig,\n Call,\n CallStatus,\n ConnectionStatus,\n ConnectionState,\n} from '@dora-cell/sdk';\n\ninterface DoraCellContextValue {\n sdk: DoraCell | null;\n connectionStatus: ConnectionStatus;\n currentCall: Call | null;\n callStatus: CallStatus;\n callDuration: string;\n isMuted: boolean;\n isInitialized: boolean;\n error: Error | null;\n\n // Methods\n call: (phoneNumber: string, extension?: string) => Promise<void>;\n hangup: () => void;\n toggleMute: () => void;\n answerCall: () => void;\n}\n\nconst DoraCellContext = createContext<DoraCellContextValue | undefined>(undefined);\n\nexport interface DoraCellProviderProps {\n config: DoraCellConfig;\n children: React.ReactNode;\n autoInitialize?: boolean;\n}\n\nexport function DoraCellProvider({\n config,\n children,\n autoInitialize = true,\n}: DoraCellProviderProps) {\n const [sdk] = useState(() => new DoraCell(config));\n const [isInitialized, setIsInitialized] = useState(false);\n const [connectionStatus, setConnectionStatus] = useState<ConnectionStatus>('disconnected');\n const [currentCall, setCurrentCall] = useState<Call | null>(null);\n const [callStatus, setCallStatus] = useState<CallStatus>('idle');\n const [callDuration, setCallDuration] = useState('00:00');\n const [isMuted, setIsMuted] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const durationIntervalRef = useRef<number | null>(null);\n\n // Initialize SDK\n useEffect(() => {\n if (!autoInitialize) return;\n\n const initializeSdk = async () => {\n try {\n await sdk.initialize();\n setIsInitialized(true);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to initialize SDK'));\n }\n };\n\n initializeSdk();\n\n return () => {\n sdk.destroy();\n };\n }, [sdk, autoInitialize]);\n\n // Set up event listeners\n useEffect(() => {\n if (!sdk) return;\n\n const handleConnectionStatus = (state: ConnectionState) => {\n setConnectionStatus(state.status);\n if (state.error) {\n setError(new Error(state.error));\n }\n };\n\n const handleIncomingCall = (call: Call) => {\n setCurrentCall(call);\n setCallStatus('ringing');\n };\n\n const handleOutgoingCall = (call: Call) => {\n setCurrentCall(call);\n setCallStatus('connecting');\n };\n\n const handleCallRinging = (call: Call) => {\n setCallStatus('ringing');\n };\n\n const handleCallConnected = (call: Call) => {\n setCallStatus('ongoing');\n };\n\n const handleCallEnded = (call: Call) => {\n setCallStatus('ended');\n setCurrentCall(null);\n setIsMuted(false);\n\n // Reset to idle after a delay\n setTimeout(() => {\n setCallStatus('idle');\n }, 3000);\n };\n\n const handleCallFailed = (call: Call, errorMsg: string) => {\n setError(new Error(errorMsg));\n setCallStatus('ended');\n setCurrentCall(null);\n };\n\n const handleError = (err: Error) => {\n setError(err);\n };\n\n sdk.on('connection:status', handleConnectionStatus);\n sdk.on('call:incoming', handleIncomingCall);\n sdk.on('call:outgoing', handleOutgoingCall);\n sdk.on('call:ringing', handleCallRinging);\n sdk.on('call:connected', handleCallConnected);\n sdk.on('call:ended', handleCallEnded);\n sdk.on('call:failed', handleCallFailed);\n sdk.on('error', handleError);\n\n return () => {\n sdk.off('connection:status', handleConnectionStatus);\n sdk.off('call:incoming', handleIncomingCall);\n sdk.off('call:outgoing', handleOutgoingCall);\n sdk.off('call:ringing', handleCallRinging);\n sdk.off('call:connected', handleCallConnected);\n sdk.off('call:ended', handleCallEnded);\n sdk.off('call:failed', handleCallFailed);\n sdk.off('error', handleError);\n };\n }, [sdk]);\n\n // Update call duration\n useEffect(() => {\n if (callStatus === 'ongoing' && currentCall) {\n durationIntervalRef.current = window.setInterval(() => {\n const duration = currentCall.duration;\n const mm = String(Math.floor(duration / 60)).padStart(2, '0');\n const ss = String(duration % 60).padStart(2, '0');\n setCallDuration(`${mm}:${ss}`);\n }, 1000);\n } else {\n setCallDuration('00:00');\n if (durationIntervalRef.current) {\n clearInterval(durationIntervalRef.current);\n durationIntervalRef.current = null;\n }\n }\n\n return () => {\n if (durationIntervalRef.current) {\n clearInterval(durationIntervalRef.current);\n }\n };\n }, [callStatus, currentCall]);\n\n // Methods\n const call = async (phoneNumber: string, extension?: string) => {\n try {\n setError(null);\n await sdk.call(phoneNumber, { extension });\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to make call'));\n throw err;\n }\n };\n\n const hangup = () => {\n try {\n sdk.hangup();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to hang up'));\n }\n };\n\n const toggleMute = () => {\n if (!currentCall) return;\n\n if (isMuted) {\n currentCall.unmute();\n setIsMuted(false);\n } else {\n currentCall.mute();\n setIsMuted(true);\n }\n };\n\n const answerCall = () => {\n try {\n sdk.answerCall();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to answer call'));\n }\n };\n\n const contextValue: DoraCellContextValue = {\n sdk,\n connectionStatus,\n currentCall,\n callStatus,\n callDuration,\n isMuted,\n isInitialized,\n error,\n call,\n hangup,\n toggleMute,\n answerCall,\n };\n\n return (\n <DoraCellContext.Provider value={contextValue}>\n {children}\n </DoraCellContext.Provider>\n );\n}\n\n/**\n * Hook to access Dora Cell SDK context\n */\nexport function useDoraCell(): DoraCellContextValue {\n const context = useContext(DoraCellContext);\n if (!context) {\n throw new Error('useDoraCell must be used within DoraCellProvider');\n }\n return context;\n}\n\n/**\n * Hook for making calls\n */\nexport function useCall() {\n const { call, hangup, toggleMute, callStatus, callDuration, isMuted, currentCall } = useDoraCell();\n\n return {\n call,\n hangup,\n toggleMute,\n callStatus,\n callDuration,\n isMuted,\n currentCall,\n };\n}\n\n/**\n * Hook for connection status\n */\nexport function useConnectionStatus() {\n const { connectionStatus, isInitialized, error } = useDoraCell();\n\n return {\n connectionStatus,\n isInitialized,\n isConnected: connectionStatus === 'registered',\n error,\n };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dora-cell/sdk-react",
|
|
3
|
+
"version": "0.1.1-beta.3",
|
|
4
|
+
"description": "React bindings for Dora Cell SDK",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"type-check": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"voip",
|
|
29
|
+
"react",
|
|
30
|
+
"hooks",
|
|
31
|
+
"dora-cell"
|
|
32
|
+
],
|
|
33
|
+
"author": "Dora Cell",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@dora-cell/sdk": "^0.1.1-beta.6",
|
|
37
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
38
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/react": "^19.0.0",
|
|
42
|
+
"@types/react-dom": "^19.0.0",
|
|
43
|
+
"react": "^19.0.0",
|
|
44
|
+
"react-dom": "^19.0.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^5.3.0"
|
|
47
|
+
}
|
|
48
|
+
}
|