urasoft-live-support 1.1.14 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ChatWidget.d.ts +5 -0
- package/dist/core/ChatWidget.d.ts.map +1 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +123 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -1
- package/dist/signalr-client.d.ts.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,8 @@ export declare class ChatWidget {
|
|
|
8
8
|
private isEmojiPickerOpen;
|
|
9
9
|
private scaleFactor;
|
|
10
10
|
private resizeObserver;
|
|
11
|
+
private typingDebounceTimer;
|
|
12
|
+
private typingDisplayTimer;
|
|
11
13
|
constructor(config?: ChatConfig);
|
|
12
14
|
private init;
|
|
13
15
|
private createContainer;
|
|
@@ -33,6 +35,9 @@ export declare class ChatWidget {
|
|
|
33
35
|
close(): void;
|
|
34
36
|
destroy(): Promise<void>;
|
|
35
37
|
addChatMessage(message: string, sender: 'agent' | 'user', avatar?: string): void;
|
|
38
|
+
private showAgentTyping;
|
|
39
|
+
private clearAgentTyping;
|
|
40
|
+
private sendTypingIndicator;
|
|
36
41
|
private escapeHtml;
|
|
37
42
|
private formatTime;
|
|
38
43
|
private handleFileSelect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../src/core/ChatWidget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"ChatWidget.d.ts","sourceRoot":"","sources":["../../src/core/ChatWidget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkE,MAAM,UAAU,CAAC;AAKtG,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAaZ;IACF,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,mBAAmB,CAA8C;IACzE,OAAO,CAAC,kBAAkB,CAA8C;gBAE5D,MAAM,GAAE,UAAe;IAmDnC,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,eAAe;IAyBvB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,YAAY;IAgCpB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,gBAAgB;IAgHxB,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,oBAAoB;YA2Cd,cAAc;YAoFd,iBAAiB;YAgCjB,WAAW;YAyEX,kBAAkB;IAuEhC,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,MAAM;IAKP,IAAI,IAAI,IAAI;IAKZ,KAAK,IAAI,IAAI;IAKP,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAYvF,OAAO,CAAC,eAAe;IAmCvB,OAAO,CAAC,gBAAgB;YAeV,mBAAmB;IAiDjC,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;YAIJ,gBAAgB;IA2D9B,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,cAAc;YAQR,eAAe;YAwCf,iBAAiB;IAqB/B,OAAO,CAAC,kBAAkB,CAWzB;CACJ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ interface SignalRConfig {
|
|
|
51
51
|
onRetry?: (retryCount: number, nextDelay: number, error?: Error) => void;
|
|
52
52
|
onReconnectFailed?: () => void;
|
|
53
53
|
onMessageReceived?: (message: any) => void;
|
|
54
|
+
onTypingReceived?: (data: {
|
|
55
|
+
sessionId: string;
|
|
56
|
+
senderType: string;
|
|
57
|
+
userId: string;
|
|
58
|
+
}) => void;
|
|
59
|
+
receiveTypingMethodName?: string;
|
|
54
60
|
onBeforeSend?: (message: string) => string | Promise<string>;
|
|
55
61
|
onAfterSend?: (message: string) => void;
|
|
56
62
|
onError?: (error: Error) => void;
|
|
@@ -97,6 +103,7 @@ interface ChatConfig {
|
|
|
97
103
|
customClasses?: CustomClasses;
|
|
98
104
|
signalR?: SignalRConfig;
|
|
99
105
|
http?: HttpConfig;
|
|
106
|
+
httpTyping?: HttpTypingConfig;
|
|
100
107
|
onSendMessage?: (message: string, attachments?: FileAttachment[]) => void;
|
|
101
108
|
onFileSelect?: (files: FileAttachment[]) => void;
|
|
102
109
|
maxFileSize?: number;
|
|
@@ -104,12 +111,20 @@ interface ChatConfig {
|
|
|
104
111
|
disableAttachments?: boolean;
|
|
105
112
|
onBeforeDisconnect?: () => boolean | Promise<boolean>;
|
|
106
113
|
}
|
|
114
|
+
interface HttpTypingConfig {
|
|
115
|
+
sendEndpoint: string;
|
|
116
|
+
method?: 'POST' | 'PUT' | 'PATCH';
|
|
117
|
+
headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
118
|
+
bodyMapper?: (sessionId: string) => any;
|
|
119
|
+
timeout?: number;
|
|
120
|
+
}
|
|
107
121
|
interface ChatWidgetState {
|
|
108
122
|
isOpen: boolean;
|
|
109
123
|
messages: ChatMessage[];
|
|
110
124
|
isConnected: boolean;
|
|
111
125
|
isConnecting: boolean;
|
|
112
126
|
selectedFiles: FileAttachment[];
|
|
127
|
+
isAgentTyping: boolean;
|
|
113
128
|
}
|
|
114
129
|
|
|
115
130
|
declare class ChatWidget {
|
|
@@ -121,6 +136,8 @@ declare class ChatWidget {
|
|
|
121
136
|
private isEmojiPickerOpen;
|
|
122
137
|
private scaleFactor;
|
|
123
138
|
private resizeObserver;
|
|
139
|
+
private typingDebounceTimer;
|
|
140
|
+
private typingDisplayTimer;
|
|
124
141
|
constructor(config?: ChatConfig);
|
|
125
142
|
private init;
|
|
126
143
|
private createContainer;
|
|
@@ -146,6 +163,9 @@ declare class ChatWidget {
|
|
|
146
163
|
close(): void;
|
|
147
164
|
destroy(): Promise<void>;
|
|
148
165
|
addChatMessage(message: string, sender: 'agent' | 'user', avatar?: string): void;
|
|
166
|
+
private showAgentTyping;
|
|
167
|
+
private clearAgentTyping;
|
|
168
|
+
private sendTypingIndicator;
|
|
149
169
|
private escapeHtml;
|
|
150
170
|
private formatTime;
|
|
151
171
|
private handleFileSelect;
|
|
@@ -180,4 +200,4 @@ declare class SignalRClient {
|
|
|
180
200
|
}
|
|
181
201
|
|
|
182
202
|
export { ChatWidget, SignalRClient };
|
|
183
|
-
export type { ChatConfig, ChatMessage, ChatWidgetState, CustomClasses, FileAttachment, HttpConfig, SignalRConfig, SignalRReconnectOptions };
|
|
203
|
+
export type { ChatConfig, ChatMessage, ChatWidgetState, CustomClasses, FileAttachment, HttpConfig, HttpTypingConfig, SignalRConfig, SignalRReconnectOptions };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACR,UAAU,EACV,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,uBAAuB,EACvB,eAAe,EAClB,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACR,UAAU,EACV,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,uBAAuB,EACvB,eAAe,EAClB,MAAM,SAAS,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -3498,6 +3498,13 @@ class SignalRClient {
|
|
|
3498
3498
|
this.config.onMessageReceived(message);
|
|
3499
3499
|
}
|
|
3500
3500
|
});
|
|
3501
|
+
// Typing indicator listener
|
|
3502
|
+
const typingMethod = this.config.receiveTypingMethodName || 'receive-typing-indicator';
|
|
3503
|
+
this.connection.on(typingMethod, (data) => {
|
|
3504
|
+
if (this.config.onTypingReceived) {
|
|
3505
|
+
this.config.onTypingReceived(data);
|
|
3506
|
+
}
|
|
3507
|
+
});
|
|
3501
3508
|
}
|
|
3502
3509
|
getTransportType() {
|
|
3503
3510
|
const transport = this.config.transport || 'All';
|
|
@@ -3669,6 +3676,8 @@ class ChatWidget {
|
|
|
3669
3676
|
this.isEmojiPickerOpen = false;
|
|
3670
3677
|
this.scaleFactor = 1;
|
|
3671
3678
|
this.resizeObserver = null;
|
|
3679
|
+
this.typingDebounceTimer = null;
|
|
3680
|
+
this.typingDisplayTimer = null;
|
|
3672
3681
|
this.handleOutsideClick = (event) => {
|
|
3673
3682
|
const pickerContainer = document.getElementById('chat-emoji-picker-container');
|
|
3674
3683
|
const emojiButton = document.getElementById('chat-emoji-button');
|
|
@@ -3694,6 +3703,7 @@ class ChatWidget {
|
|
|
3694
3703
|
onSendMessage: config.onSendMessage,
|
|
3695
3704
|
signalR: config.signalR,
|
|
3696
3705
|
http: config.http,
|
|
3706
|
+
httpTyping: config.httpTyping,
|
|
3697
3707
|
onFileSelect: config.onFileSelect,
|
|
3698
3708
|
maxFileSize: config.maxFileSize,
|
|
3699
3709
|
allowedFileTypes: config.allowedFileTypes,
|
|
@@ -3712,6 +3722,7 @@ class ChatWidget {
|
|
|
3712
3722
|
isConnected: false,
|
|
3713
3723
|
isConnecting: false,
|
|
3714
3724
|
selectedFiles: [],
|
|
3725
|
+
isAgentTyping: false,
|
|
3715
3726
|
};
|
|
3716
3727
|
this.init();
|
|
3717
3728
|
// autoConnect true ise ve SignalR config varsa, otomatik bağlan
|
|
@@ -3903,6 +3914,15 @@ class ChatWidget {
|
|
|
3903
3914
|
` : `
|
|
3904
3915
|
<div class="${this.mergeClasses('chat-messages', this.config.customClasses?.messagesContainer)}" id="chat-messages">
|
|
3905
3916
|
${this.state.messages.map((msg) => this.renderMessage(msg)).join('')}
|
|
3917
|
+
${this.state.isAgentTyping ? `
|
|
3918
|
+
<div class="chat-message chat-message-agent">
|
|
3919
|
+
<div class="chat-message-content">
|
|
3920
|
+
<div class="chat-typing-indicator" id="chat-typing-indicator">
|
|
3921
|
+
<span></span><span></span><span></span>
|
|
3922
|
+
</div>
|
|
3923
|
+
</div>
|
|
3924
|
+
</div>
|
|
3925
|
+
` : ''}
|
|
3906
3926
|
</div>
|
|
3907
3927
|
|
|
3908
3928
|
${showDisconnectButton ? `
|
|
@@ -4019,6 +4039,12 @@ class ChatWidget {
|
|
|
4019
4039
|
this.sendMessage();
|
|
4020
4040
|
}
|
|
4021
4041
|
});
|
|
4042
|
+
// Typing indicator - kullanıcı yazarken gönder
|
|
4043
|
+
input?.addEventListener('input', () => {
|
|
4044
|
+
if (input.value.trim()) {
|
|
4045
|
+
this.sendTypingIndicator();
|
|
4046
|
+
}
|
|
4047
|
+
});
|
|
4022
4048
|
}
|
|
4023
4049
|
async connectSignalR() {
|
|
4024
4050
|
if (!this.config.signalR || this.state.isConnected || this.state.isConnecting) {
|
|
@@ -4065,10 +4091,18 @@ class ChatWidget {
|
|
|
4065
4091
|
}
|
|
4066
4092
|
},
|
|
4067
4093
|
onMessageReceived: (message) => {
|
|
4094
|
+
// Mesaj geldiğinde typing indicator'ı temizle
|
|
4095
|
+
this.clearAgentTyping();
|
|
4068
4096
|
if (this.config.signalR?.onMessageReceived) {
|
|
4069
4097
|
this.config.signalR.onMessageReceived(message);
|
|
4070
4098
|
}
|
|
4071
4099
|
},
|
|
4100
|
+
onTypingReceived: (data) => {
|
|
4101
|
+
this.showAgentTyping();
|
|
4102
|
+
if (this.config.signalR?.onTypingReceived) {
|
|
4103
|
+
this.config.signalR.onTypingReceived(data);
|
|
4104
|
+
}
|
|
4105
|
+
},
|
|
4072
4106
|
});
|
|
4073
4107
|
await this.signalRClient.connect();
|
|
4074
4108
|
}
|
|
@@ -4303,6 +4337,95 @@ class ChatWidget {
|
|
|
4303
4337
|
avatar: avatar || this.config.agentAvatar,
|
|
4304
4338
|
});
|
|
4305
4339
|
}
|
|
4340
|
+
showAgentTyping() {
|
|
4341
|
+
// Mevcut timeout'u temizle
|
|
4342
|
+
if (this.typingDisplayTimer) {
|
|
4343
|
+
clearTimeout(this.typingDisplayTimer);
|
|
4344
|
+
}
|
|
4345
|
+
const wasTyping = this.state.isAgentTyping;
|
|
4346
|
+
this.state.isAgentTyping = true;
|
|
4347
|
+
// DOM'u güncelle (tam render yerine)
|
|
4348
|
+
if (!wasTyping) {
|
|
4349
|
+
const messagesContainer = document.getElementById('chat-messages');
|
|
4350
|
+
if (messagesContainer) {
|
|
4351
|
+
// Typing indicator ekle
|
|
4352
|
+
const typingEl = document.createElement('div');
|
|
4353
|
+
typingEl.className = 'chat-message chat-message-agent';
|
|
4354
|
+
typingEl.id = 'chat-typing-message';
|
|
4355
|
+
typingEl.innerHTML = `
|
|
4356
|
+
<div class="chat-message-content">
|
|
4357
|
+
<div class="chat-typing-indicator" id="chat-typing-indicator">
|
|
4358
|
+
<span></span><span></span><span></span>
|
|
4359
|
+
</div>
|
|
4360
|
+
</div>
|
|
4361
|
+
`;
|
|
4362
|
+
messagesContainer.appendChild(typingEl);
|
|
4363
|
+
this.scrollToBottom();
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
// 3 saniye sonra typing'i kaldır
|
|
4367
|
+
this.typingDisplayTimer = setTimeout(() => {
|
|
4368
|
+
this.clearAgentTyping();
|
|
4369
|
+
}, 3000);
|
|
4370
|
+
}
|
|
4371
|
+
clearAgentTyping() {
|
|
4372
|
+
if (this.typingDisplayTimer) {
|
|
4373
|
+
clearTimeout(this.typingDisplayTimer);
|
|
4374
|
+
this.typingDisplayTimer = null;
|
|
4375
|
+
}
|
|
4376
|
+
this.state.isAgentTyping = false;
|
|
4377
|
+
// DOM'dan typing indicator'ı kaldır
|
|
4378
|
+
const typingMessage = document.getElementById('chat-typing-message');
|
|
4379
|
+
if (typingMessage) {
|
|
4380
|
+
typingMessage.remove();
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
async sendTypingIndicator() {
|
|
4384
|
+
if (this.typingDebounceTimer)
|
|
4385
|
+
return; // Zaten bekliyor
|
|
4386
|
+
this.typingDebounceTimer = setTimeout(() => { this.typingDebounceTimer = null; }, 2000);
|
|
4387
|
+
if (!this.config.httpTyping)
|
|
4388
|
+
return;
|
|
4389
|
+
const httpTyping = this.config.httpTyping;
|
|
4390
|
+
const method = httpTyping.method || 'POST';
|
|
4391
|
+
const timeout = httpTyping.timeout || 5000;
|
|
4392
|
+
// Headers'ı resolve et
|
|
4393
|
+
let headers = {
|
|
4394
|
+
'Content-Type': 'application/json',
|
|
4395
|
+
};
|
|
4396
|
+
if (httpTyping.headers) {
|
|
4397
|
+
if (typeof httpTyping.headers === 'function') {
|
|
4398
|
+
headers = { ...headers, ...(await httpTyping.headers()) };
|
|
4399
|
+
}
|
|
4400
|
+
else {
|
|
4401
|
+
headers = { ...headers, ...httpTyping.headers };
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
// Body
|
|
4405
|
+
let body;
|
|
4406
|
+
if (httpTyping.bodyMapper) {
|
|
4407
|
+
body = httpTyping.bodyMapper('');
|
|
4408
|
+
}
|
|
4409
|
+
else {
|
|
4410
|
+
body = {};
|
|
4411
|
+
}
|
|
4412
|
+
const controller = new AbortController();
|
|
4413
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
4414
|
+
try {
|
|
4415
|
+
await fetch(httpTyping.sendEndpoint, {
|
|
4416
|
+
method,
|
|
4417
|
+
headers,
|
|
4418
|
+
body: JSON.stringify(body),
|
|
4419
|
+
signal: controller.signal,
|
|
4420
|
+
});
|
|
4421
|
+
clearTimeout(timeoutId);
|
|
4422
|
+
}
|
|
4423
|
+
catch (error) {
|
|
4424
|
+
clearTimeout(timeoutId);
|
|
4425
|
+
// Typing indicator hataları sessizce yutulur
|
|
4426
|
+
console.debug('Typing indicator send failed:', error);
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4306
4429
|
escapeHtml(text) {
|
|
4307
4430
|
const div = document.createElement('div');
|
|
4308
4431
|
div.textContent = text;
|