connect-x-reactnative-livechat-sdk 0.2.0
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/ConnectXReactnativeLivechatSdk.podspec +20 -0
- package/LICENSE +20 -0
- package/README.md +34 -0
- package/android/build.gradle +83 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/connectxreactnativelivechatsdk/ConnectXReactnativeLivechatSdkModule.kt +23 -0
- package/android/src/main/java/com/connectxreactnativelivechatsdk/ConnectXReactnativeLivechatSdkPackage.kt +33 -0
- package/ios/ConnectXReactnativeLivechatSdk.h +5 -0
- package/ios/ConnectXReactnativeLivechatSdk.mm +18 -0
- package/lib/module/ChatScreen.js +834 -0
- package/lib/module/ChatScreen.js.map +1 -0
- package/lib/module/NativeConnectXReactnativeLivechatSdk.js +5 -0
- package/lib/module/NativeConnectXReactnativeLivechatSdk.js.map +1 -0
- package/lib/module/SendIcon.js +35 -0
- package/lib/module/SendIcon.js.map +1 -0
- package/lib/module/api.js +66 -0
- package/lib/module/api.js.map +1 -0
- package/lib/module/index.js +78 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/ChatScreen.d.ts +7 -0
- package/lib/typescript/src/ChatScreen.d.ts.map +1 -0
- package/lib/typescript/src/NativeConnectXReactnativeLivechatSdk.d.ts +7 -0
- package/lib/typescript/src/NativeConnectXReactnativeLivechatSdk.d.ts.map +1 -0
- package/lib/typescript/src/SendIcon.d.ts +3 -0
- package/lib/typescript/src/SendIcon.d.ts.map +1 -0
- package/lib/typescript/src/api.d.ts +5 -0
- package/lib/typescript/src/api.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +20 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +176 -0
- package/src/ChatScreen.tsx +914 -0
- package/src/NativeConnectXReactnativeLivechatSdk.ts +8 -0
- package/src/SendIcon.tsx +25 -0
- package/src/api.ts +79 -0
- package/src/index.tsx +91 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface Spec extends TurboModule {
|
|
5
|
+
multiply(a: number, b: number): number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('ConnectXReactnativeLivechatSdk');
|
package/src/SendIcon.tsx
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const SendIcon = (props: any) => (
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width={33}
|
|
5
|
+
height={32}
|
|
6
|
+
fill="none"
|
|
7
|
+
{...props}
|
|
8
|
+
>
|
|
9
|
+
<rect width={32} height={32} x={0.5} fill="#006CFD" rx={16} />
|
|
10
|
+
<g clipPath="url(#a)">
|
|
11
|
+
<path
|
|
12
|
+
fill="#fff"
|
|
13
|
+
fillRule="evenodd"
|
|
14
|
+
d="m21.492 11.008-10.494 3.795 3.496 2.023 3.083-3.084a.833.833 0 1 1 1.178 1.18l-3.083 3.083 2.025 3.495 3.795-10.492Zm.269-1.87c.996-.36 1.96.604 1.6 1.6L18.959 22.91c-.361.998-1.725 1.12-2.257.201l-2.681-4.632-4.632-2.68c-.919-.533-.797-1.896.201-2.258l12.171-4.402Z"
|
|
15
|
+
clipRule="evenodd"
|
|
16
|
+
/>
|
|
17
|
+
</g>
|
|
18
|
+
<defs>
|
|
19
|
+
<clipPath id="a">
|
|
20
|
+
<path fill="#fff" d="M6.5 6h20v20h-20z" />
|
|
21
|
+
</clipPath>
|
|
22
|
+
</defs>
|
|
23
|
+
</svg>
|
|
24
|
+
);
|
|
25
|
+
export default SendIcon;
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const BASE_URL_LIVE_CHAT =
|
|
2
|
+
'https://df99-2001-44c8-4287-b85c-2407-5b2-9e79-9451.ngrok-free.app'; //'https://live-chat.connect-x.tech';
|
|
3
|
+
const BASE_URL_TRACKING = 'https://tracking.connect-x.tech';
|
|
4
|
+
export const apiGet = async (path: string, token: string) => {
|
|
5
|
+
console.log(`GET ${BASE_URL_LIVE_CHAT}/connectx/api/${path}`);
|
|
6
|
+
const headers = {
|
|
7
|
+
'Authorization': `Bearer ${token}`,
|
|
8
|
+
'x-type': 'mobile',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const response = await fetch(`${BASE_URL_LIVE_CHAT}/connectx/api/${path}`, {
|
|
12
|
+
method: 'GET',
|
|
13
|
+
headers: headers,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
const errorData = await response.json().catch(() => null);
|
|
18
|
+
throw errorData || new Error('API request failed');
|
|
19
|
+
}
|
|
20
|
+
console.log('Response:', response);
|
|
21
|
+
return response.json();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const apiPost = async (path: string, body: any, token: string) => {
|
|
25
|
+
console.log('Finding customer with userId:', body.userId, body.externalValue);
|
|
26
|
+
console.log(`POST ${BASE_URL_LIVE_CHAT}/connectx/api/${path}`);
|
|
27
|
+
console.log('Request body:', body);
|
|
28
|
+
const response = await fetch(`${BASE_URL_LIVE_CHAT}/connectx/api/${path}`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
'Authorization': `Bearer ${token}`,
|
|
33
|
+
'x-type': 'mobile',
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
const errorData = await response.json().catch(() => null);
|
|
39
|
+
throw errorData || new Error('API POST request failed');
|
|
40
|
+
}
|
|
41
|
+
console.log('Response:', response);
|
|
42
|
+
return response.json();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const uploadFile = async (
|
|
46
|
+
file: any,
|
|
47
|
+
organizeId: string,
|
|
48
|
+
channelId: string
|
|
49
|
+
) => {
|
|
50
|
+
const APIEndpoint = `${BASE_URL_TRACKING}/connectx/api/storage/uploadFile`;
|
|
51
|
+
const formData = new FormData();
|
|
52
|
+
|
|
53
|
+
formData.append('file', {
|
|
54
|
+
uri: file.uri,
|
|
55
|
+
name: file.name,
|
|
56
|
+
type: file.type,
|
|
57
|
+
});
|
|
58
|
+
formData.append(
|
|
59
|
+
'path',
|
|
60
|
+
`Organizes/${organizeId}/connector/liveChat/channel/${channelId}`
|
|
61
|
+
);
|
|
62
|
+
formData.append('isPublic', 'true');
|
|
63
|
+
|
|
64
|
+
const response = await fetch(APIEndpoint, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
body: formData,
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'multipart/form-data',
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
const errorData = await response.json().catch(() => null);
|
|
74
|
+
throw errorData || new Error('File upload failed');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const result = await response.json();
|
|
78
|
+
return result?.url;
|
|
79
|
+
};
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useState, useEffect, type ReactNode, useRef } from 'react';
|
|
2
|
+
import { Modal } from 'react-native';
|
|
3
|
+
import { ChatScreen } from './ChatScreen';
|
|
4
|
+
import ConnectXReactnativeLivechatSdk from './NativeConnectXReactnativeLivechatSdk';
|
|
5
|
+
|
|
6
|
+
export function multiply(a: number, b: number): number {
|
|
7
|
+
return ConnectXReactnativeLivechatSdk.multiply(a, b);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type EventType = 'show' | 'hide';
|
|
11
|
+
type ShowPayload = { token: string; orgId: string; channelId: string };
|
|
12
|
+
|
|
13
|
+
// Event Emitter ที่รองรับการส่งข้อมูล
|
|
14
|
+
const chatEventEmitter = {
|
|
15
|
+
listeners: new Map<EventType, Set<(payload?: any) => void>>(),
|
|
16
|
+
on(event: EventType, callback: (payload?: any) => void) {
|
|
17
|
+
if (!this.listeners.has(event)) {
|
|
18
|
+
this.listeners.set(event, new Set());
|
|
19
|
+
}
|
|
20
|
+
this.listeners.get(event)!.add(callback);
|
|
21
|
+
return () => this.off(event, callback);
|
|
22
|
+
},
|
|
23
|
+
off(event: EventType, callback: (payload?: any) => void) {
|
|
24
|
+
this.listeners.get(event)?.delete(callback);
|
|
25
|
+
},
|
|
26
|
+
emit(event: EventType, payload?: any) {
|
|
27
|
+
this.listeners.get(event)?.forEach((callback) => callback(payload));
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
|
32
|
+
const [isModalVisible, setModalVisible] = useState(false);
|
|
33
|
+
// เก็บ config ที่ได้รับมา
|
|
34
|
+
const configRef = useRef<ShowPayload | null>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const showHandler = (payload: ShowPayload) => {
|
|
38
|
+
if (payload && payload.token && payload.orgId && payload.channelId) {
|
|
39
|
+
configRef.current = payload;
|
|
40
|
+
setModalVisible(true);
|
|
41
|
+
} else {
|
|
42
|
+
console.error('LiveChat.show() requires { token, orgId, channelId }');
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const hideHandler = () => setModalVisible(false);
|
|
46
|
+
|
|
47
|
+
const showUnsubscribe = chatEventEmitter.on('show', showHandler);
|
|
48
|
+
const hideUnsubscribe = chatEventEmitter.on('hide', hideHandler);
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
showUnsubscribe();
|
|
52
|
+
hideUnsubscribe();
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
{children}
|
|
59
|
+
<Modal
|
|
60
|
+
visible={isModalVisible}
|
|
61
|
+
animationType="slide"
|
|
62
|
+
onRequestClose={() => setModalVisible(false)}
|
|
63
|
+
>
|
|
64
|
+
{/* ส่ง config ไปยัง ChatScreen เมื่อ Modal เปิด */}
|
|
65
|
+
{configRef.current && (
|
|
66
|
+
<ChatScreen
|
|
67
|
+
onClose={() => setModalVisible(false)}
|
|
68
|
+
token={configRef.current.token}
|
|
69
|
+
orgId={configRef.current.orgId}
|
|
70
|
+
channelId={configRef.current.channelId}
|
|
71
|
+
/>
|
|
72
|
+
)}
|
|
73
|
+
</Modal>
|
|
74
|
+
</>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const LiveChat = {
|
|
79
|
+
/**
|
|
80
|
+
* แสดงหน้าแชท
|
|
81
|
+
* @param config - ต้องมี orgId และ channelId
|
|
82
|
+
*/
|
|
83
|
+
show: (config: ShowPayload) => {
|
|
84
|
+
chatEventEmitter.emit('show', config);
|
|
85
|
+
},
|
|
86
|
+
hide: () => {
|
|
87
|
+
chatEventEmitter.emit('hide');
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export * from './ChatScreen';
|