@campxdev/campx-web-utils 2.0.13 → 2.0.14

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.
Files changed (63) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/types/src/components/Exotel/CallButton.d.ts +10 -0
  3. package/dist/cjs/types/src/components/Exotel/CallDispositionForm.d.ts +29 -0
  4. package/dist/cjs/types/src/components/Exotel/ExotelPhone.d.ts +10 -0
  5. package/dist/cjs/types/src/components/Exotel/ExotelWrapper.d.ts +14 -0
  6. package/dist/cjs/types/src/components/Exotel/MicrophonePermission.d.ts +6 -0
  7. package/dist/cjs/types/src/components/Exotel/index.d.ts +6 -0
  8. package/dist/cjs/types/src/config/index.d.ts +1 -0
  9. package/dist/cjs/types/src/config/voip.config.d.ts +18 -0
  10. package/dist/cjs/types/src/constants/exotel.constants.d.ts +7 -0
  11. package/dist/cjs/types/src/providers/ExotelProvider.d.ts +79 -0
  12. package/dist/cjs/types/src/providers/VoIPProvider.d.ts +33 -0
  13. package/dist/cjs/types/src/providers/index.d.ts +2 -0
  14. package/dist/cjs/types/src/services/crypto/CryptoService.d.ts +23 -0
  15. package/dist/cjs/types/src/services/exotel/ExotelService.d.ts +47 -0
  16. package/dist/cjs/types/src/services/exotel/api.d.ts +158 -0
  17. package/dist/cjs/types/src/services/exotel/index.d.ts +2 -0
  18. package/dist/cjs/types/src/utils/exotel/formatters.d.ts +8 -0
  19. package/dist/cjs/types/src/utils/exotel/index.d.ts +1 -0
  20. package/dist/esm/index.js +2 -2
  21. package/dist/esm/types/src/components/Exotel/CallButton.d.ts +10 -0
  22. package/dist/esm/types/src/components/Exotel/CallDispositionForm.d.ts +29 -0
  23. package/dist/esm/types/src/components/Exotel/ExotelPhone.d.ts +10 -0
  24. package/dist/esm/types/src/components/Exotel/ExotelWrapper.d.ts +14 -0
  25. package/dist/esm/types/src/components/Exotel/MicrophonePermission.d.ts +6 -0
  26. package/dist/esm/types/src/components/Exotel/index.d.ts +6 -0
  27. package/dist/esm/types/src/config/index.d.ts +1 -0
  28. package/dist/esm/types/src/config/voip.config.d.ts +18 -0
  29. package/dist/esm/types/src/constants/exotel.constants.d.ts +7 -0
  30. package/dist/esm/types/src/providers/ExotelProvider.d.ts +79 -0
  31. package/dist/esm/types/src/providers/VoIPProvider.d.ts +33 -0
  32. package/dist/esm/types/src/providers/index.d.ts +2 -0
  33. package/dist/esm/types/src/services/crypto/CryptoService.d.ts +23 -0
  34. package/dist/esm/types/src/services/exotel/ExotelService.d.ts +47 -0
  35. package/dist/esm/types/src/services/exotel/api.d.ts +158 -0
  36. package/dist/esm/types/src/services/exotel/index.d.ts +2 -0
  37. package/dist/esm/types/src/utils/exotel/formatters.d.ts +8 -0
  38. package/dist/esm/types/src/utils/exotel/index.d.ts +1 -0
  39. package/dist/index.d.ts +357 -3
  40. package/dist/styles.css +337 -47
  41. package/dist/types/exotel-crm-websdk.d.ts +46 -0
  42. package/export.ts +6 -0
  43. package/package.json +4 -1
  44. package/src/components/Exotel/CallButton.tsx +164 -0
  45. package/src/components/Exotel/CallDispositionForm.tsx +213 -0
  46. package/src/components/Exotel/ExotelPhone.tsx +482 -0
  47. package/src/components/Exotel/ExotelWrapper.tsx +80 -0
  48. package/src/components/Exotel/MicrophonePermission.tsx +97 -0
  49. package/src/components/Exotel/index.ts +10 -0
  50. package/src/config/index.ts +1 -0
  51. package/src/config/voip.config.ts +26 -0
  52. package/src/constants/exotel.constants.ts +7 -0
  53. package/src/providers/ExotelProvider.tsx +526 -0
  54. package/src/providers/VoIPProvider.tsx +143 -0
  55. package/src/providers/index.ts +2 -0
  56. package/src/selectors/ResearchStageSelector.tsx +1 -0
  57. package/src/services/crypto/CryptoService.ts +112 -0
  58. package/src/services/exotel/ExotelService.ts +238 -0
  59. package/src/services/exotel/api.ts +319 -0
  60. package/src/services/exotel/index.ts +2 -0
  61. package/src/utils/exotel/formatters.ts +17 -0
  62. package/src/utils/exotel/index.ts +1 -0
  63. package/types/exotel-crm-websdk.d.ts +46 -0
@@ -0,0 +1,10 @@
1
+ interface CallButtonProps {
2
+ phoneNumber?: string;
3
+ encryptedPhoneNumber?: string;
4
+ callerName?: string;
5
+ prospectId?: string;
6
+ className?: string;
7
+ disabled?: boolean;
8
+ }
9
+ declare const CallButton: ({ phoneNumber, encryptedPhoneNumber, callerName, prospectId, className, disabled, }: CallButtonProps) => import("react/jsx-runtime").JSX.Element;
10
+ export default CallButton;
@@ -0,0 +1,29 @@
1
+ import type { CallDispositionData } from '../../providers/ExotelProvider';
2
+ type CallStatusType = 'connected' | 'not_connected';
3
+ export interface DispositionFormData {
4
+ prospectId?: string;
5
+ callId: string;
6
+ channel: string;
7
+ direction: string;
8
+ duration: number;
9
+ callStatusDisposition: CallStatusType;
10
+ dispositionReason?: string;
11
+ dispositionCategory: string;
12
+ remarks: string;
13
+ callerName: string;
14
+ callerNumber: string;
15
+ }
16
+ export interface ExistingDispositionData {
17
+ callStatusDisposition?: CallStatusType;
18
+ dispositionCategory?: string;
19
+ dispositionNotes?: string;
20
+ }
21
+ interface CallDispositionFormProps {
22
+ dispositionData: CallDispositionData;
23
+ prospectId?: string;
24
+ onClose: () => void;
25
+ onSave: (data: DispositionFormData) => Promise<any>;
26
+ existingData?: ExistingDispositionData;
27
+ }
28
+ declare const CallDispositionForm: ({ dispositionData, prospectId, onClose, onSave, existingData, }: CallDispositionFormProps) => import("react/jsx-runtime").JSX.Element;
29
+ export default CallDispositionForm;
@@ -0,0 +1,10 @@
1
+ import { type DispositionFormData } from './CallDispositionForm';
2
+ interface ExotelPhoneProps {
3
+ className?: string;
4
+ prospectId?: string;
5
+ prospectName?: string;
6
+ prospectNumber?: string;
7
+ onSaveDisposition?: (data: DispositionFormData) => Promise<any>;
8
+ }
9
+ declare const ExotelPhone: ({ className, prospectId, prospectName, prospectNumber, onSaveDisposition }: ExotelPhoneProps) => import("react/jsx-runtime").JSX.Element;
10
+ export default ExotelPhone;
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+ interface ExotelWrapperProps {
3
+ children: ReactNode;
4
+ enabled?: boolean;
5
+ prospectId?: string;
6
+ prospectName?: string;
7
+ prospectNumber?: string;
8
+ }
9
+ /**
10
+ * Wrapper component that initializes Exotel VoIP functionality
11
+ * Fetches the access token from backend and provides the Exotel context to children
12
+ */
13
+ declare const ExotelWrapper: ({ children, enabled, prospectId, prospectName, prospectNumber, }: ExotelWrapperProps) => import("react/jsx-runtime").JSX.Element;
14
+ export default ExotelWrapper;
@@ -0,0 +1,6 @@
1
+ interface MicrophonePermissionProps {
2
+ onPermissionGranted?: () => void;
3
+ onPermissionDenied?: () => void;
4
+ }
5
+ declare const MicrophonePermission: ({ onPermissionGranted, onPermissionDenied, }: MicrophonePermissionProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default MicrophonePermission;
@@ -0,0 +1,6 @@
1
+ export { default as ExotelPhone } from './ExotelPhone';
2
+ export { default as CallButton } from './CallButton';
3
+ export { default as CallDispositionForm } from './CallDispositionForm';
4
+ export { default as MicrophonePermission } from './MicrophonePermission';
5
+ export { default as ExotelWrapper } from './ExotelWrapper';
6
+ export type { DispositionFormData, ExistingDispositionData, } from './CallDispositionForm';
@@ -1,3 +1,4 @@
1
1
  export * from './axios';
2
2
  export * from './createRsbuildSharedConfig';
3
3
  export * from './nonWorkspaceAxios';
4
+ export * from './voip.config';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * VoIP Configuration Module
3
+ *
4
+ * This module manages VoIP/Exotel configuration for workspaces.
5
+ * Only workspaces listed in VOIP_ENABLED_WORKSPACES will have VoIP functionality.
6
+ */
7
+ /**
8
+ * List of workspaces that have VoIP/Exotel calling enabled.
9
+ * Add workspace names here to enable VoIP for that workspace.
10
+ */
11
+ export declare const VOIP_ENABLED_WORKSPACES: string[];
12
+ /**
13
+ * Check if VoIP is enabled for a given workspace
14
+ *
15
+ * @param workspaceName - The name of the workspace to check
16
+ * @returns boolean indicating if VoIP is enabled for the workspace
17
+ */
18
+ export declare function isVoIPEnabledForWorkspace(workspaceName: string): boolean;
@@ -0,0 +1,7 @@
1
+ export declare const EXOTEL_CONSTANTS: {
2
+ MODAL_Z_INDEX: number;
3
+ MODAL_BACKDROP_Z_INDEX: number;
4
+ MODAL_BORDER_RADIUS: string;
5
+ DECLINE_TIMEOUT_MS: number;
6
+ TIMER_INTERVAL_MS: number;
7
+ };
@@ -0,0 +1,79 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { PermissionStatus } from '../services/exotel/ExotelService';
3
+ export interface CallEventData {
4
+ callId: string;
5
+ remoteId: string;
6
+ remoteDisplayName: string;
7
+ callDirection: string;
8
+ callState: string;
9
+ callDuration: string;
10
+ callStartedTime: string;
11
+ callEstablishedTime: string;
12
+ callEndedTime: string;
13
+ callAnswerTime: string;
14
+ callEndReason: string;
15
+ sessionId: string;
16
+ callFromNumber?: string;
17
+ status?: string;
18
+ }
19
+ export type CallPhase = 'idle' | 'ready_to_call' | 'calling' | 'incoming' | 'connected' | 'ended';
20
+ export interface CallState {
21
+ phase: CallPhase;
22
+ callData: CallEventData | null;
23
+ isOnHold: boolean;
24
+ isMuted: boolean;
25
+ isSpeakerOff: boolean;
26
+ callDirection: 'outbound' | 'inbound' | null;
27
+ callStartTime: number | null;
28
+ callDuration: number;
29
+ callerName: string | null;
30
+ callerNumber: string | null;
31
+ callActivityId: string | null;
32
+ exotelCallSid: string | null;
33
+ prospectUniqueId: number | null;
34
+ wasAccepted: boolean;
35
+ }
36
+ export interface CallDispositionData {
37
+ callId: string;
38
+ exotelCallId: string;
39
+ callDirection: 'outbound' | 'inbound';
40
+ callDuration: number;
41
+ callerName: string | null;
42
+ callerNumber: string | null;
43
+ }
44
+ export interface ExotelContextType {
45
+ isInitialized: boolean;
46
+ isConnected: boolean;
47
+ callState: CallState;
48
+ permissionStatus: PermissionStatus;
49
+ dispositionData: CallDispositionData | null;
50
+ makeCall: (phoneNumber: string, callerName?: string, callActivityId?: string, maskedNumber?: string) => Promise<any>;
51
+ acceptCall: () => Promise<void>;
52
+ hangupCall: () => void;
53
+ rejectCall: () => void;
54
+ toggleHold: () => void;
55
+ toggleMute: () => void;
56
+ toggleSpeaker: () => void;
57
+ sendDTMF: (digit: string) => void;
58
+ registerDevice: () => Promise<void>;
59
+ unregisterDevice: () => void;
60
+ requestMicrophoneAccess: () => Promise<boolean>;
61
+ clearDisposition: () => void;
62
+ setCallActivityId: (callActivityId: string) => void;
63
+ setExotelCallSid: (callSid: string) => void;
64
+ }
65
+ export interface ExotelProviderProps {
66
+ children: ReactNode;
67
+ accessToken: string;
68
+ agentUserId: string;
69
+ autoConnectVOIP?: boolean;
70
+ callerName?: string;
71
+ callerNumber?: string;
72
+ }
73
+ export declare const ExotelProvider: React.FC<ExotelProviderProps>;
74
+ export declare const useExotel: () => ExotelContextType;
75
+ /**
76
+ * Safe version of useExotel that returns null when outside the provider
77
+ * Use this in components that may render outside of ExotelProvider
78
+ */
79
+ export declare const useExotelSafe: () => ExotelContextType | null;
@@ -0,0 +1,33 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { DispositionFormData } from '../components/Exotel';
3
+ export type { DispositionFormData } from '../components/Exotel';
4
+ interface VoIPProviderProps {
5
+ children: ReactNode;
6
+ workspace: string;
7
+ agentUserId?: string;
8
+ prospectId?: string;
9
+ prospectName?: string;
10
+ prospectNumber?: string;
11
+ onSaveDisposition?: (data: DispositionFormData) => Promise<any>;
12
+ }
13
+ /**
14
+ * VoIPProvider - Workspace-level VoIP/Exotel integration
15
+ *
16
+ * This provider checks if VoIP is enabled for the current workspace AND tenant
17
+ * and initializes the Exotel SDK if enabled.
18
+ *
19
+ * VoIP is enabled only when ALL conditions are met:
20
+ * 1. Workspace is in VOIP_ENABLED_WORKSPACES (common-workspace, tele-caller-workspace)
21
+ * 2. Tenant has enableVoice: true in notification config
22
+ * 3. Tenant has at least one enabled voice config (voiceConfigs[].isEnabled: true)
23
+ * 4. Active token is available
24
+ *
25
+ * Features:
26
+ * - Workspace-level VoIP enablement
27
+ * - Tenant-level VoIP configuration check
28
+ * - Automatic token fetching from backend
29
+ * - Microphone permission handling
30
+ * - Floating phone UI for active calls
31
+ */
32
+ export declare const VoIPProvider: React.FC<VoIPProviderProps>;
33
+ export default VoIPProvider;
@@ -0,0 +1,2 @@
1
+ export * from './ExotelProvider';
2
+ export * from './VoIPProvider';
@@ -0,0 +1,23 @@
1
+ declare class CryptoService {
2
+ private static instance;
3
+ private readonly algorithm;
4
+ private secretKey;
5
+ private initialized;
6
+ private constructor();
7
+ private ensureInitialized;
8
+ static getInstance(): CryptoService;
9
+ /**
10
+ * Decrypt data using AES-256-CBC (same as backend)
11
+ * Format: "iv_hex:encrypted_hex"
12
+ */
13
+ decryptData(encryptedData: string): string;
14
+ /**
15
+ * Mask mobile number for display (first 2 and last 2 of actual number visible)
16
+ * Handles country code prefix (+91)
17
+ * e.g., "+919876543210" -> "+9198******10"
18
+ * e.g., "9876543210" -> "98******10"
19
+ */
20
+ maskMobile(mobile: string): string;
21
+ }
22
+ declare const _default: CryptoService;
23
+ export default _default;
@@ -0,0 +1,47 @@
1
+ import { CallEventData } from '@exotel-npm-dev/exotel-ip-calling-crm-websdk';
2
+ export type PermissionStatus = 'granted' | 'denied' | 'prompt' | 'unknown';
3
+ declare class ExotelService {
4
+ private static instance;
5
+ private exotelSDK;
6
+ private webPhone;
7
+ private callListeners;
8
+ private registerListeners;
9
+ private sessionListeners;
10
+ private permissionStatus;
11
+ static getInstance(): ExotelService;
12
+ /**
13
+ * Initialize the Exotel SDK
14
+ * @param accessToken - The access token for authentication
15
+ * @param agentUserId - The user ID of the agent
16
+ * @param autoConnectVOIP - Whether to automatically connect VOIP (default: true)
17
+ * @returns boolean indicating success
18
+ */
19
+ initialize(accessToken: string, agentUserId: string, autoConnectVOIP?: boolean): Promise<boolean>;
20
+ checkAudioPermissions(): Promise<boolean>;
21
+ requestMicrophoneAccess(): Promise<boolean>;
22
+ makeCall(phoneNumber: string): Promise<any>;
23
+ acceptCall(): Promise<void>;
24
+ hangupCall(): void;
25
+ /**
26
+ * Reject an incoming call before accepting it.
27
+ * Note: Exotel SDK only has HangupCall - no separate RejectCall method.
28
+ * HangupCall internally calls webrtcSIPPhone.rejectCall() -> phone.sipHangUp()
29
+ */
30
+ rejectCall(): void;
31
+ toggleHold(): void;
32
+ toggleMute(): void;
33
+ sendDTMF(digit: string): void;
34
+ registerDevice(): Promise<void>;
35
+ unregisterDevice(): void;
36
+ getPermissionStatus(): PermissionStatus;
37
+ private handleCallEvent;
38
+ private handleRegisterEvent;
39
+ private handleSessionEvent;
40
+ addCallListener(listener: (event: string, data: CallEventData) => void): void;
41
+ removeCallListener(listener: (event: string, data: CallEventData) => void): void;
42
+ addRegisterListener(listener: (state: string) => void): void;
43
+ removeRegisterListener(listener: (state: string) => void): void;
44
+ addSessionListener(listener: (state: string, data: any) => void): void;
45
+ removeSessionListener(listener: (state: string, data: any) => void): void;
46
+ }
47
+ export default ExotelService;
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Voice config from notification-configs API
3
+ */
4
+ export interface VoiceConfig {
5
+ id: string;
6
+ isEnabled: boolean;
7
+ name: string;
8
+ channelType: string;
9
+ EXOTEL?: {
10
+ appId: string;
11
+ appSecret: string;
12
+ token?: string;
13
+ tokenExpiresAt?: string;
14
+ };
15
+ }
16
+ /**
17
+ * Notification config response structure
18
+ */
19
+ export interface NotificationConfigResponse {
20
+ config: {
21
+ id: string;
22
+ tenantId: string;
23
+ institutionUniqueId: number;
24
+ enableVoice?: boolean;
25
+ voiceConfigs?: VoiceConfig[];
26
+ };
27
+ options: {
28
+ voiceChannels?: string[];
29
+ };
30
+ }
31
+ /**
32
+ * Check if VoIP is enabled for the current tenant by fetching notification config.
33
+ * Returns true only if:
34
+ * - enableVoice is true
35
+ * - voiceConfigs has at least one enabled config
36
+ */
37
+ export declare const checkVoIPEnabled: () => Promise<{
38
+ enabled: boolean;
39
+ hasValidToken: boolean;
40
+ }>;
41
+ /**
42
+ * Get the active Exotel voice token from the backend.
43
+ * The backend manages credentials securely and auto-refreshes tokens.
44
+ */
45
+ export declare const getActiveVoiceToken: () => Promise<{
46
+ token: string;
47
+ expiresAt: string;
48
+ } | null>;
49
+ /**
50
+ * @deprecated Use getActiveVoiceToken instead.
51
+ * This function is kept for backwards compatibility but will be removed.
52
+ */
53
+ export declare const createExotelAppToken: () => Promise<{
54
+ Data: string;
55
+ }>;
56
+ export interface CallActivity {
57
+ id: string;
58
+ callSid: string;
59
+ prospectId: string;
60
+ direction: 'inbound' | 'outbound';
61
+ status: string;
62
+ durationSeconds?: number;
63
+ createdAt: string;
64
+ startTime?: string;
65
+ endTime?: string;
66
+ fromNumber?: string;
67
+ toNumber?: string;
68
+ userId?: number;
69
+ dispositionCategory?: string;
70
+ dispositionReason?: string;
71
+ dispositionNotes?: string;
72
+ callStatusDisposition?: 'connected' | 'not_connected';
73
+ recordingUrl?: string;
74
+ }
75
+ export interface InitiateCallInput {
76
+ prospectId: string;
77
+ toNumber: string;
78
+ fromNumber?: string;
79
+ userId?: number;
80
+ callSid?: string;
81
+ }
82
+ export interface SaveDispositionInput {
83
+ callId: string;
84
+ prospectId?: string;
85
+ callStatusDisposition?: 'connected' | 'not_connected';
86
+ dispositionCategory: string;
87
+ dispositionReason?: string;
88
+ dispositionNotes?: string;
89
+ callbackScheduledAt?: string;
90
+ }
91
+ export interface CancelCallInput {
92
+ callSid: string;
93
+ reason?: string;
94
+ }
95
+ export interface CallActivityResponse {
96
+ success: boolean;
97
+ message: string;
98
+ data: CallActivity;
99
+ }
100
+ export interface RegisterIncomingCallInput {
101
+ callSid: string;
102
+ fromNumber: string;
103
+ toNumber?: string;
104
+ prospectId?: string;
105
+ userId?: number;
106
+ }
107
+ export interface RegisterIncomingCallResponse {
108
+ success: boolean;
109
+ message: string;
110
+ data: CallActivity;
111
+ prospect?: {
112
+ id: string;
113
+ uniqueId?: number;
114
+ prospectId?: string;
115
+ name: string;
116
+ mobile: string;
117
+ };
118
+ }
119
+ /**
120
+ * Initiate an outbound call - creates call activity record
121
+ */
122
+ export declare const initiateCallActivity: (input: InitiateCallInput) => Promise<{
123
+ success: boolean;
124
+ message: string;
125
+ data: CallActivity;
126
+ }>;
127
+ /**
128
+ * Register an incoming call - creates call activity record
129
+ */
130
+ export declare const registerIncomingCall: (input: RegisterIncomingCallInput) => Promise<RegisterIncomingCallResponse>;
131
+ /**
132
+ * Fetch call history for a prospect
133
+ */
134
+ export declare const fetchCallHistory: (prospectId: string) => Promise<CallActivity[]>;
135
+ /**
136
+ * Get call activity by ID
137
+ */
138
+ export declare const getCallActivityById: (id: string) => Promise<CallActivity>;
139
+ /**
140
+ * Get call activity by CallSid
141
+ */
142
+ export declare const getCallActivityByCallSid: (callSid: string) => Promise<CallActivity>;
143
+ /**
144
+ * Get call count for a prospect
145
+ */
146
+ export declare const getCallCountByProspect: (prospectId: string) => Promise<number>;
147
+ /**
148
+ * Save call disposition
149
+ */
150
+ export declare const saveCallDisposition: (input: SaveDispositionInput) => Promise<CallActivity>;
151
+ /**
152
+ * Cancel/decline a call before it was connected
153
+ * Updates the call activity status to CANCELED
154
+ */
155
+ export declare const cancelCall: (input: CancelCallInput) => Promise<{
156
+ success: boolean;
157
+ message: string;
158
+ }>;
@@ -0,0 +1,2 @@
1
+ export * from './ExotelService';
2
+ export * from './api';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Format duration in MM:SS format (e.g., "02:30")
3
+ */
4
+ export declare const formatDurationTimer: (seconds: number) => string;
5
+ /**
6
+ * Format duration in verbose format (e.g., "2m 30s")
7
+ */
8
+ export declare const formatDurationVerbose: (seconds: number) => string;
@@ -0,0 +1 @@
1
+ export * from './formatters';