@greatapps/greatchat-ui 0.1.1 → 0.1.2

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/index.js CHANGED
@@ -130,6 +130,568 @@ function formatMessageTime(dateStr) {
130
130
  return format(new Date(dateStr), "HH:mm");
131
131
  }
132
132
 
133
+ // src/hooks/types.ts
134
+ import { useMemo } from "react";
135
+ var DEFAULT_INBOX_POLLING = 5e3;
136
+ var DEFAULT_MESSAGES_POLLING = 3e3;
137
+ var DEFAULT_CHANNEL_STATUS_POLLING = 5e3;
138
+ var DEFAULT_QR_POLLING = 2e3;
139
+ function useGchatClient(config) {
140
+ return useMemo(
141
+ () => createGchatClient({
142
+ baseUrl: config.baseUrl,
143
+ token: config.token,
144
+ language: config.language,
145
+ idWl: config.idWl
146
+ }),
147
+ [config.baseUrl, config.token, config.language, config.idWl]
148
+ );
149
+ }
150
+
151
+ // src/hooks/use-inboxes.ts
152
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
153
+ function useInboxes(config, statusFilter, pollingInterval) {
154
+ const client = useGchatClient(config);
155
+ return useQuery({
156
+ queryKey: ["greatchat", "inboxes", config.accountId, statusFilter],
157
+ queryFn: () => {
158
+ const params = {};
159
+ if (statusFilter && statusFilter !== "all") {
160
+ params.status = statusFilter;
161
+ }
162
+ return client.listInboxes(config.accountId, params);
163
+ },
164
+ enabled: !!config.accountId && !!config.token,
165
+ refetchInterval: pollingInterval ?? DEFAULT_INBOX_POLLING,
166
+ select: (res) => res.data || []
167
+ });
168
+ }
169
+ function useInbox(config, id) {
170
+ const client = useGchatClient(config);
171
+ return useQuery({
172
+ queryKey: ["greatchat", "inbox", config.accountId, id],
173
+ queryFn: () => client.getInbox(config.accountId, id),
174
+ enabled: !!config.accountId && !!config.token && !!id,
175
+ select: (res) => {
176
+ const d = res.data;
177
+ return Array.isArray(d) ? d[0] : d;
178
+ }
179
+ });
180
+ }
181
+ function useInboxStats(config, pollingInterval) {
182
+ const client = useGchatClient(config);
183
+ return useQuery({
184
+ queryKey: ["greatchat", "inbox-stats", config.accountId],
185
+ queryFn: () => client.getInboxStats(config.accountId),
186
+ enabled: !!config.accountId && !!config.token,
187
+ refetchInterval: pollingInterval ?? DEFAULT_INBOX_POLLING,
188
+ select: (res) => {
189
+ const d = res.data;
190
+ return Array.isArray(d) ? d[0] : d;
191
+ }
192
+ });
193
+ }
194
+ function useCreateInbox(config) {
195
+ const client = useGchatClient(config);
196
+ const queryClient = useQueryClient();
197
+ return useMutation({
198
+ mutationFn: (body) => client.createInbox(config.accountId, body),
199
+ onSuccess: () => {
200
+ queryClient.invalidateQueries({
201
+ queryKey: ["greatchat", "inboxes"]
202
+ });
203
+ queryClient.invalidateQueries({
204
+ queryKey: ["greatchat", "inbox-stats"]
205
+ });
206
+ }
207
+ });
208
+ }
209
+ function useUpdateInbox(config) {
210
+ const client = useGchatClient(config);
211
+ const queryClient = useQueryClient();
212
+ return useMutation({
213
+ mutationFn: ({
214
+ id,
215
+ body
216
+ }) => client.updateInbox(config.accountId, id, body),
217
+ onSuccess: () => {
218
+ queryClient.invalidateQueries({
219
+ queryKey: ["greatchat", "inboxes"]
220
+ });
221
+ queryClient.invalidateQueries({
222
+ queryKey: ["greatchat", "inbox-stats"]
223
+ });
224
+ }
225
+ });
226
+ }
227
+ function useDeleteInbox(config) {
228
+ const client = useGchatClient(config);
229
+ const queryClient = useQueryClient();
230
+ return useMutation({
231
+ mutationFn: (id) => client.deleteInbox(config.accountId, id),
232
+ onSuccess: () => {
233
+ queryClient.invalidateQueries({
234
+ queryKey: ["greatchat", "inboxes"]
235
+ });
236
+ queryClient.invalidateQueries({
237
+ queryKey: ["greatchat", "inbox-stats"]
238
+ });
239
+ }
240
+ });
241
+ }
242
+
243
+ // src/hooks/use-inbox-messages.ts
244
+ import { useMemo as useMemo2, useSyncExternalStore } from "react";
245
+ import { useQuery as useQuery2, useMutation as useMutation2, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
246
+ var optimisticStore = /* @__PURE__ */ new Map();
247
+ var nextOptimisticId = -1;
248
+ var storeVersion = 0;
249
+ var listeners = /* @__PURE__ */ new Set();
250
+ function subscribeStore(listener) {
251
+ listeners.add(listener);
252
+ return () => {
253
+ listeners.delete(listener);
254
+ };
255
+ }
256
+ function getStoreVersion() {
257
+ return storeVersion;
258
+ }
259
+ function storeKey(accountId, idInbox) {
260
+ return `${accountId}:${idInbox}`;
261
+ }
262
+ function getOptimistic(accountId, idInbox) {
263
+ return optimisticStore.get(storeKey(accountId, idInbox)) || [];
264
+ }
265
+ function setOptimistic(accountId, idInbox, msgs) {
266
+ const key = storeKey(accountId, idInbox);
267
+ if (msgs.length === 0) {
268
+ optimisticStore.delete(key);
269
+ } else {
270
+ optimisticStore.set(key, msgs);
271
+ }
272
+ storeVersion++;
273
+ listeners.forEach((fn) => fn());
274
+ }
275
+ function cleanupOptimistic(accountId, idInbox, msgs) {
276
+ const key = storeKey(accountId, idInbox);
277
+ if (msgs.length === 0) {
278
+ optimisticStore.delete(key);
279
+ } else {
280
+ optimisticStore.set(key, msgs);
281
+ }
282
+ }
283
+ function useInboxMessages(config, idInbox, pollingInterval) {
284
+ const client = useGchatClient(config);
285
+ const optimisticVersion = useSyncExternalStore(
286
+ subscribeStore,
287
+ getStoreVersion,
288
+ getStoreVersion
289
+ );
290
+ const query = useQuery2({
291
+ queryKey: ["greatchat", "inbox-messages", config.accountId, idInbox],
292
+ queryFn: () => client.listInboxMessages(config.accountId, {
293
+ id_inbox: String(idInbox),
294
+ sort: "datetime_add:asc",
295
+ limit: "100"
296
+ }),
297
+ enabled: !!config.accountId && !!config.token && !!idInbox,
298
+ refetchInterval: pollingInterval ?? DEFAULT_MESSAGES_POLLING,
299
+ select: (res) => res.data || []
300
+ });
301
+ const messages = useMemo2(() => {
302
+ const serverMessages = query.data || [];
303
+ if (!config.accountId || !idInbox) return serverMessages;
304
+ const optimistic = getOptimistic(config.accountId, idInbox);
305
+ if (!optimistic.length) return serverMessages;
306
+ const overrides = /* @__PURE__ */ new Map();
307
+ const newOptimistic = [];
308
+ for (const om of optimistic) {
309
+ if (om.id > 0) {
310
+ overrides.set(om.id, om);
311
+ } else {
312
+ newOptimistic.push(om);
313
+ }
314
+ }
315
+ const merged = overrides.size > 0 ? serverMessages.map((sm) => overrides.get(sm.id) ?? sm) : serverMessages;
316
+ if (overrides.size > 0) {
317
+ for (const [id] of overrides) {
318
+ const sm = serverMessages.find((s) => s.id === id);
319
+ if (sm && sm.status !== "failed") {
320
+ overrides.delete(id);
321
+ }
322
+ }
323
+ }
324
+ const stillNeeded = [];
325
+ const claimed = /* @__PURE__ */ new Set();
326
+ for (const om of newOptimistic) {
327
+ if (om.status === "failed") {
328
+ stillNeeded.push(om);
329
+ continue;
330
+ }
331
+ const matchIdx = merged.findIndex(
332
+ (sm, i) => !claimed.has(i) && sm.direction === "outbound" && sm.content === om.content && sm.content_type === om.content_type && sm.source === om.source
333
+ );
334
+ if (matchIdx >= 0) {
335
+ claimed.add(matchIdx);
336
+ } else {
337
+ stillNeeded.push(om);
338
+ }
339
+ }
340
+ const allKept = [...Array.from(overrides.values()), ...stillNeeded];
341
+ if (allKept.length !== optimistic.length) {
342
+ cleanupOptimistic(config.accountId, idInbox, allKept);
343
+ }
344
+ const result = [...merged, ...stillNeeded];
345
+ result.sort(
346
+ (a, b) => new Date(a.datetime_add).getTime() - new Date(b.datetime_add).getTime()
347
+ );
348
+ return result;
349
+ }, [query.data, config.accountId, idInbox, optimisticVersion]);
350
+ return { ...query, data: messages };
351
+ }
352
+ function useSendMessage(config) {
353
+ const client = useGchatClient(config);
354
+ const queryClient = useQueryClient2();
355
+ return useMutation2({
356
+ mutationFn: async ({
357
+ idInbox,
358
+ content
359
+ }) => {
360
+ const result = await client.sendMessage(config.accountId, {
361
+ id_inbox: idInbox,
362
+ content,
363
+ content_type: "text",
364
+ source: "agent",
365
+ direction: "outbound"
366
+ });
367
+ if (result.status === 0) {
368
+ throw new Error(result.message || "Erro desconhecido ao enviar");
369
+ }
370
+ return result;
371
+ },
372
+ onMutate: (variables) => {
373
+ const msg = {
374
+ id: nextOptimisticId--,
375
+ id_account: config.accountId,
376
+ id_inbox: variables.idInbox,
377
+ id_contact: null,
378
+ direction: "outbound",
379
+ content: variables.content,
380
+ content_type: "text",
381
+ content_url: null,
382
+ metadata: null,
383
+ external_id: null,
384
+ status: "pending",
385
+ source: "agent",
386
+ is_private: false,
387
+ datetime_add: (/* @__PURE__ */ new Date()).toISOString(),
388
+ datetime_alt: null
389
+ };
390
+ const current = getOptimistic(config.accountId, variables.idInbox);
391
+ setOptimistic(config.accountId, variables.idInbox, [...current, msg]);
392
+ return { optimisticMsg: msg };
393
+ },
394
+ onError: (error, variables, context) => {
395
+ if (!context) return;
396
+ const { optimisticMsg } = context;
397
+ const current = getOptimistic(config.accountId, variables.idInbox);
398
+ setOptimistic(
399
+ config.accountId,
400
+ variables.idInbox,
401
+ current.map(
402
+ (m) => m.id === optimisticMsg.id ? { ...m, status: "failed", _error: error.message } : m
403
+ )
404
+ );
405
+ },
406
+ onSuccess: (_result, variables, context) => {
407
+ if (!context) return;
408
+ const { optimisticMsg } = context;
409
+ const current = getOptimistic(config.accountId, variables.idInbox);
410
+ setOptimistic(
411
+ config.accountId,
412
+ variables.idInbox,
413
+ current.filter((m) => m.id !== optimisticMsg.id)
414
+ );
415
+ queryClient.invalidateQueries({
416
+ queryKey: [
417
+ "greatchat",
418
+ "inbox-messages",
419
+ config.accountId,
420
+ variables.idInbox
421
+ ]
422
+ });
423
+ queryClient.invalidateQueries({
424
+ queryKey: ["greatchat", "inboxes"]
425
+ });
426
+ }
427
+ });
428
+ }
429
+ function useRetryMessage(config) {
430
+ const client = useGchatClient(config);
431
+ const queryClient = useQueryClient2();
432
+ return async (message) => {
433
+ if (!config.accountId || !config.token || !message.content) return;
434
+ const current = getOptimistic(config.accountId, message.id_inbox);
435
+ setOptimistic(config.accountId, message.id_inbox, [
436
+ ...current.filter((m) => m.id !== message.id),
437
+ {
438
+ ...message,
439
+ status: "pending",
440
+ _error: void 0,
441
+ datetime_add: (/* @__PURE__ */ new Date()).toISOString()
442
+ }
443
+ ]);
444
+ try {
445
+ const result = await client.sendMessage(config.accountId, {
446
+ id_inbox: message.id_inbox,
447
+ content: message.content,
448
+ content_type: message.content_type,
449
+ source: "agent",
450
+ direction: "outbound"
451
+ });
452
+ if (result.status === 0) {
453
+ throw new Error(result.message || "Erro desconhecido ao enviar");
454
+ }
455
+ const after = getOptimistic(config.accountId, message.id_inbox);
456
+ setOptimistic(
457
+ config.accountId,
458
+ message.id_inbox,
459
+ after.filter((m) => m.id !== message.id)
460
+ );
461
+ queryClient.invalidateQueries({
462
+ queryKey: [
463
+ "greatchat",
464
+ "inbox-messages",
465
+ config.accountId,
466
+ message.id_inbox
467
+ ]
468
+ });
469
+ queryClient.invalidateQueries({
470
+ queryKey: ["greatchat", "inboxes"]
471
+ });
472
+ } catch (err) {
473
+ const errorMessage = err instanceof Error ? err.message : "Erro ao enviar mensagem";
474
+ const after = getOptimistic(config.accountId, message.id_inbox);
475
+ setOptimistic(
476
+ config.accountId,
477
+ message.id_inbox,
478
+ after.map(
479
+ (m) => m.id === message.id ? { ...m, status: "failed", _error: errorMessage } : m
480
+ )
481
+ );
482
+ }
483
+ };
484
+ }
485
+ function useRevokeMessage(config) {
486
+ const client = useGchatClient(config);
487
+ const queryClient = useQueryClient2();
488
+ return useMutation2({
489
+ mutationFn: async ({ id }) => client.revokeMessage(config.accountId, id),
490
+ onSuccess: (_data, variables) => {
491
+ queryClient.invalidateQueries({
492
+ queryKey: [
493
+ "greatchat",
494
+ "inbox-messages",
495
+ config.accountId,
496
+ variables.idInbox
497
+ ]
498
+ });
499
+ }
500
+ });
501
+ }
502
+ function useEditMessage(config) {
503
+ const client = useGchatClient(config);
504
+ const queryClient = useQueryClient2();
505
+ return useMutation2({
506
+ mutationFn: async ({
507
+ id,
508
+ content
509
+ }) => client.editMessage(config.accountId, id, { content }),
510
+ onSuccess: (_data, variables) => {
511
+ queryClient.invalidateQueries({
512
+ queryKey: [
513
+ "greatchat",
514
+ "inbox-messages",
515
+ config.accountId,
516
+ variables.idInbox
517
+ ]
518
+ });
519
+ }
520
+ });
521
+ }
522
+
523
+ // src/hooks/use-contacts.ts
524
+ import { useQuery as useQuery3, useMutation as useMutation3, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
525
+ function useContacts(config, params) {
526
+ const client = useGchatClient(config);
527
+ return useQuery3({
528
+ queryKey: ["greatchat", "contacts", config.accountId, params],
529
+ queryFn: () => client.listContacts(config.accountId, params),
530
+ enabled: !!config.accountId && !!config.token,
531
+ select: (res) => ({ data: res.data || [], total: res.total || 0 })
532
+ });
533
+ }
534
+ function useGetContact(config, contactId) {
535
+ const client = useGchatClient(config);
536
+ return useQuery3({
537
+ queryKey: ["greatchat", "contact", config.accountId, contactId],
538
+ queryFn: () => client.getContact(config.accountId, contactId),
539
+ enabled: !!config.accountId && !!config.token && !!contactId,
540
+ select: (res) => {
541
+ const d = res.data;
542
+ return Array.isArray(d) ? d[0] : d;
543
+ }
544
+ });
545
+ }
546
+ function useCreateContact(config) {
547
+ const client = useGchatClient(config);
548
+ const queryClient = useQueryClient3();
549
+ return useMutation3({
550
+ mutationFn: (body) => client.createContact(config.accountId, body),
551
+ onSuccess: () => {
552
+ queryClient.invalidateQueries({
553
+ queryKey: ["greatchat", "contacts"]
554
+ });
555
+ }
556
+ });
557
+ }
558
+ function useUpdateContact(config) {
559
+ const client = useGchatClient(config);
560
+ const queryClient = useQueryClient3();
561
+ return useMutation3({
562
+ mutationFn: ({
563
+ id,
564
+ body
565
+ }) => client.updateContact(config.accountId, id, body),
566
+ onSuccess: () => {
567
+ queryClient.invalidateQueries({
568
+ queryKey: ["greatchat", "contacts"]
569
+ });
570
+ }
571
+ });
572
+ }
573
+ function useDeleteContact(config) {
574
+ const client = useGchatClient(config);
575
+ const queryClient = useQueryClient3();
576
+ return useMutation3({
577
+ mutationFn: (id) => client.deleteContact(config.accountId, id),
578
+ onSuccess: () => {
579
+ queryClient.invalidateQueries({
580
+ queryKey: ["greatchat", "contacts"]
581
+ });
582
+ }
583
+ });
584
+ }
585
+
586
+ // src/hooks/use-channels.ts
587
+ import { useQuery as useQuery4, useMutation as useMutation4, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
588
+ function useChannels(config) {
589
+ const client = useGchatClient(config);
590
+ return useQuery4({
591
+ queryKey: ["greatchat", "channels", config.accountId],
592
+ queryFn: () => client.listChannels(config.accountId),
593
+ enabled: !!config.accountId && !!config.token,
594
+ select: (res) => res.data || []
595
+ });
596
+ }
597
+ function useChannelWhatsappStatus(config, channelId, enabled = true, pollingInterval) {
598
+ const client = useGchatClient(config);
599
+ return useQuery4({
600
+ queryKey: ["greatchat", "channel-status", config.accountId, channelId],
601
+ queryFn: () => client.getChannelWhatsappStatus(config.accountId, channelId),
602
+ enabled: !!config.accountId && !!config.token && !!channelId && enabled,
603
+ refetchInterval: pollingInterval ?? DEFAULT_CHANNEL_STATUS_POLLING,
604
+ select: (res) => {
605
+ const d = res.data;
606
+ return Array.isArray(d) ? d[0] : d;
607
+ }
608
+ });
609
+ }
610
+ function useChannelQR(config, channelId, enabled = false, pollingInterval) {
611
+ const client = useGchatClient(config);
612
+ return useQuery4({
613
+ queryKey: ["greatchat", "channel-qr", config.accountId, channelId],
614
+ queryFn: () => client.getChannelQR(config.accountId, channelId),
615
+ enabled: !!config.accountId && !!config.token && !!channelId && enabled,
616
+ refetchInterval: pollingInterval ?? DEFAULT_QR_POLLING
617
+ });
618
+ }
619
+ function useCreateChannel(config) {
620
+ const client = useGchatClient(config);
621
+ const queryClient = useQueryClient4();
622
+ return useMutation4({
623
+ mutationFn: (body) => client.createChannel(config.accountId, body),
624
+ onSuccess: () => {
625
+ queryClient.invalidateQueries({
626
+ queryKey: ["greatchat", "channels"]
627
+ });
628
+ }
629
+ });
630
+ }
631
+ function useUpdateChannel(config) {
632
+ const client = useGchatClient(config);
633
+ const queryClient = useQueryClient4();
634
+ return useMutation4({
635
+ mutationFn: ({
636
+ id,
637
+ body
638
+ }) => client.updateChannel(config.accountId, id, body),
639
+ onSuccess: () => {
640
+ queryClient.invalidateQueries({
641
+ queryKey: ["greatchat", "channels"]
642
+ });
643
+ }
644
+ });
645
+ }
646
+ function useDeleteChannel(config) {
647
+ const client = useGchatClient(config);
648
+ const queryClient = useQueryClient4();
649
+ return useMutation4({
650
+ mutationFn: (channelId) => client.deleteChannel(config.accountId, channelId),
651
+ onSuccess: () => {
652
+ queryClient.invalidateQueries({
653
+ queryKey: ["greatchat", "channels"]
654
+ });
655
+ }
656
+ });
657
+ }
658
+ function useConnectChannel(config) {
659
+ const client = useGchatClient(config);
660
+ return useMutation4({
661
+ mutationFn: (channelId) => client.connectChannel(config.accountId, channelId)
662
+ });
663
+ }
664
+ function useDisconnectChannel(config) {
665
+ const client = useGchatClient(config);
666
+ const queryClient = useQueryClient4();
667
+ return useMutation4({
668
+ mutationFn: (channelId) => client.disconnectChannel(config.accountId, channelId),
669
+ onSuccess: () => {
670
+ queryClient.invalidateQueries({
671
+ queryKey: ["greatchat", "channel-status"]
672
+ });
673
+ queryClient.invalidateQueries({
674
+ queryKey: ["greatchat", "channels"]
675
+ });
676
+ }
677
+ });
678
+ }
679
+ function useLogoutChannel(config) {
680
+ const client = useGchatClient(config);
681
+ const queryClient = useQueryClient4();
682
+ return useMutation4({
683
+ mutationFn: (channelId) => client.logoutChannel(config.accountId, channelId),
684
+ onSuccess: () => {
685
+ queryClient.invalidateQueries({
686
+ queryKey: ["greatchat", "channel-status"]
687
+ });
688
+ queryClient.invalidateQueries({
689
+ queryKey: ["greatchat", "channels"]
690
+ });
691
+ }
692
+ });
693
+ }
694
+
133
695
  // src/components/chat-view.tsx
134
696
  import { useRef as useRef2, useEffect } from "react";
135
697
 
@@ -978,11 +1540,40 @@ function ChatView({
978
1540
  export {
979
1541
  ChatInput,
980
1542
  ChatView,
1543
+ DEFAULT_CHANNEL_STATUS_POLLING,
1544
+ DEFAULT_INBOX_POLLING,
1545
+ DEFAULT_MESSAGES_POLLING,
1546
+ DEFAULT_QR_POLLING,
981
1547
  MessageBubble,
982
1548
  cn,
983
1549
  createGchatClient,
984
1550
  formatDateGroup,
985
1551
  formatMessageTime,
986
- groupMessagesByDate
1552
+ groupMessagesByDate,
1553
+ useChannelQR,
1554
+ useChannelWhatsappStatus,
1555
+ useChannels,
1556
+ useConnectChannel,
1557
+ useContacts,
1558
+ useCreateChannel,
1559
+ useCreateContact,
1560
+ useCreateInbox,
1561
+ useDeleteChannel,
1562
+ useDeleteContact,
1563
+ useDeleteInbox,
1564
+ useDisconnectChannel,
1565
+ useEditMessage,
1566
+ useGetContact,
1567
+ useInbox,
1568
+ useInboxMessages,
1569
+ useInboxStats,
1570
+ useInboxes,
1571
+ useLogoutChannel,
1572
+ useRetryMessage,
1573
+ useRevokeMessage,
1574
+ useSendMessage,
1575
+ useUpdateChannel,
1576
+ useUpdateContact,
1577
+ useUpdateInbox
987
1578
  };
988
1579
  //# sourceMappingURL=index.js.map