@diffsome/react 1.2.2 → 1.2.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/dist/index.d.mts +141 -5
- package/dist/index.d.ts +141 -5
- package/dist/index.js +477 -0
- package/dist/index.mjs +472 -0
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as
|
|
3
|
-
import { ReactNode } from 'react';
|
|
4
|
-
import { Diffsome, Cart, WishlistItem, DiffsomeConfig, CurrencyInfo, SiteInfo, Member, LoginCredentials, AuthResponse, RegisterData, UpdateProfileData, ResetPasswordData, SocialProvider, WishlistToggleResult, WishlistMoveToCartResult, BundlePricing, ProductCategory, Product, PaginationMeta, ProductListParams, ProductType, CreateOrderData, Order, OrderListParams, PaymentStatusResponse, StripeCheckoutResponse, StripeVerifyResponse, TossPaymentReadyResponse, TossPaymentConfirmResponse, Coupon, CouponValidation, MemberSubscription, DigitalDownloadLink, CanReviewResponse, CreateProductReviewData, ProductReview, UpdateProductReviewData, ProductReviewStats, ProductReviewListParams, BlogCategory, BlogListParams, BlogPost, BoardPost, Board, CreateBoardPostData, BoardPostListParams, BoardListParams, Comment, CreateCommentData, Form, FormSubmissionData, FormSubmission, ReservationSlot, CreateReservationData, Reservation, ReservationService, ReservationSettings, ReservationStaff, ReservationListParams, Media, CustomEntity, EntityRecord, EntityListParams } from '@diffsome/sdk';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import React__default, { ReactNode } from 'react';
|
|
4
|
+
import { Diffsome, Cart, WishlistItem, DiffsomeConfig, CurrencyInfo, SiteInfo, Member, LoginCredentials, AuthResponse, RegisterData, UpdateProfileData, ResetPasswordData, SocialProvider, WishlistToggleResult, WishlistMoveToCartResult, BundlePricing, ProductCategory, Product, PaginationMeta, ProductListParams, ProductType, CreateOrderData, Order, OrderListParams, PaymentStatusResponse, StripeCheckoutResponse, StripeVerifyResponse, TossPaymentReadyResponse, TossPaymentConfirmResponse, Coupon, CouponValidation, MemberSubscription, DigitalDownloadLink, CanReviewResponse, CreateProductReviewData, ProductReview, UpdateProductReviewData, ProductReviewStats, ProductReviewListParams, BlogCategory, BlogListParams, BlogPost, BoardPost, Board, CreateBoardPostData, BoardPostListParams, BoardListParams, Comment, CreateCommentData, Form, FormSubmissionData, FormSubmission, ReservationSlot, CreateReservationData, Reservation, ReservationService, ReservationSettings, ReservationStaff, ReservationListParams, Media, CustomEntity, EntityRecord, EntityListParams, ChatConversation, ChatMessage as ChatMessage$1 } from '@diffsome/sdk';
|
|
5
5
|
export { AddToCartData, AuthResponse, BlogCategory, BlogListParams, BlogPost, Board, BoardListParams, BoardPost, BoardPostListParams, CanReviewResponse, Cart, CartItem, Comment, Coupon, CouponType, CouponValidation, CreateBoardPostData, CreateCommentData, CreateOrderData, CreateProductReviewData, CreateReservationData, CustomEntity, DiffsomeConfig, DigitalDownloadLink, DigitalFile, EntityField, EntityListParams, EntityRecord, EntitySchema, Form, FormSubmission, FormSubmissionData, ListResponse, LoginCredentials, Media, Member, MemberSubscription, Order, OrderItem, OrderListParams, OrderStatus, PaginatedResponse, PaginationMeta, Payment, PaymentMethod, PaymentStatus, PaymentStatusResponse, Product, ProductCategory, ProductListParams, ProductReview, ProductReviewStats, ProductType, ProductVariant, RegisterData, Reservation, ReservationService, ReservationSettings, ReservationSlot, ReservationStaff, ResetPasswordData, SiteInfo, SocialAuthUrl, SocialProvider, StripeCheckoutResponse, StripeVerifyResponse, SubscriptionInterval, SubscriptionPlan, SubscriptionStatus, TossPaymentConfirmResponse, TossPaymentReadyResponse, UpdateProfileData, WishlistItem, WishlistMoveToCartResult, WishlistToggleResult } from '@diffsome/sdk';
|
|
6
6
|
|
|
7
7
|
interface DiffsomeContextValue {
|
|
@@ -16,7 +16,7 @@ interface DiffsomeContextValue {
|
|
|
16
16
|
setWishlistItems: (items: WishlistItem[]) => void;
|
|
17
17
|
refreshWishlist: () => Promise<void>;
|
|
18
18
|
}
|
|
19
|
-
declare const DiffsomeContext:
|
|
19
|
+
declare const DiffsomeContext: React.Context<DiffsomeContextValue | null>;
|
|
20
20
|
interface DiffsomeProviderProps {
|
|
21
21
|
children: ReactNode;
|
|
22
22
|
config?: Partial<DiffsomeConfig>;
|
|
@@ -757,6 +757,46 @@ declare function useTypedEntity<T extends Record<string, any>>(slug: string): {
|
|
|
757
757
|
delete: (id: number) => Promise<void>;
|
|
758
758
|
};
|
|
759
759
|
|
|
760
|
+
interface UseChatOptions {
|
|
761
|
+
/** Auto-connect when hook mounts */
|
|
762
|
+
autoConnect?: boolean;
|
|
763
|
+
/** Visitor name */
|
|
764
|
+
visitorName?: string;
|
|
765
|
+
/** Visitor email */
|
|
766
|
+
visitorEmail?: string;
|
|
767
|
+
/** Initial greeting message */
|
|
768
|
+
greeting?: string;
|
|
769
|
+
}
|
|
770
|
+
interface UseChatReturn {
|
|
771
|
+
/** Current conversation */
|
|
772
|
+
conversation: ChatConversation | null;
|
|
773
|
+
/** Messages in the conversation */
|
|
774
|
+
messages: ChatMessage$1[];
|
|
775
|
+
/** Whether chat is loading */
|
|
776
|
+
loading: boolean;
|
|
777
|
+
/** Error if any */
|
|
778
|
+
error: Error | null;
|
|
779
|
+
/** Whether connection is active */
|
|
780
|
+
connected: boolean;
|
|
781
|
+
/** Whether agent is typing */
|
|
782
|
+
agentTyping: boolean;
|
|
783
|
+
/** Start a new conversation */
|
|
784
|
+
start: (options?: {
|
|
785
|
+
visitorName?: string;
|
|
786
|
+
visitorEmail?: string;
|
|
787
|
+
greeting?: string;
|
|
788
|
+
}) => Promise<void>;
|
|
789
|
+
/** Send a message */
|
|
790
|
+
send: (content: string) => Promise<void>;
|
|
791
|
+
/** Send typing indicator */
|
|
792
|
+
sendTyping: () => void;
|
|
793
|
+
/** Close the conversation */
|
|
794
|
+
close: () => Promise<void>;
|
|
795
|
+
/** Disconnect from real-time updates */
|
|
796
|
+
disconnect: () => void;
|
|
797
|
+
}
|
|
798
|
+
declare function useChat(options?: UseChatOptions): UseChatReturn;
|
|
799
|
+
|
|
760
800
|
interface RichContentProps {
|
|
761
801
|
/** HTML content from CMS/Editor */
|
|
762
802
|
html: string;
|
|
@@ -797,4 +837,100 @@ interface RichContentProps {
|
|
|
797
837
|
*/
|
|
798
838
|
declare function RichContent({ html, className, prose, proseVariant, proseSize, maxWidth, }: RichContentProps): react_jsx_runtime.JSX.Element;
|
|
799
839
|
|
|
800
|
-
|
|
840
|
+
interface Message {
|
|
841
|
+
id: number;
|
|
842
|
+
content: string;
|
|
843
|
+
senderType: 'visitor' | 'agent' | 'system';
|
|
844
|
+
senderName?: string;
|
|
845
|
+
timestamp?: string;
|
|
846
|
+
isRead?: boolean;
|
|
847
|
+
}
|
|
848
|
+
interface ChatWidgetProps {
|
|
849
|
+
messages: Message[];
|
|
850
|
+
onSend: (message: string) => void;
|
|
851
|
+
onTyping?: () => void;
|
|
852
|
+
onClose?: () => void;
|
|
853
|
+
title?: string;
|
|
854
|
+
subtitle?: string;
|
|
855
|
+
placeholder?: string;
|
|
856
|
+
loading?: boolean;
|
|
857
|
+
typing?: boolean;
|
|
858
|
+
className?: string;
|
|
859
|
+
}
|
|
860
|
+
declare const ChatWidget: React__default.FC<ChatWidgetProps>;
|
|
861
|
+
|
|
862
|
+
interface ChatBubbleProps {
|
|
863
|
+
/** Diffsome SDK client instance */
|
|
864
|
+
client: {
|
|
865
|
+
chat: {
|
|
866
|
+
start: (data?: {
|
|
867
|
+
visitor_name?: string;
|
|
868
|
+
visitor_email?: string;
|
|
869
|
+
initial_message?: string;
|
|
870
|
+
}) => Promise<{
|
|
871
|
+
conversation_id: number;
|
|
872
|
+
visitor_id: string;
|
|
873
|
+
}>;
|
|
874
|
+
connect: (conversationId: number) => {
|
|
875
|
+
send: (content: string) => Promise<unknown>;
|
|
876
|
+
getMessages: () => Promise<Message[]>;
|
|
877
|
+
onMessage: (callback: (msg: Message) => void) => () => void;
|
|
878
|
+
onTyping: (callback: (senderType: string) => void) => () => void;
|
|
879
|
+
sendTyping: () => void;
|
|
880
|
+
disconnect: () => void;
|
|
881
|
+
};
|
|
882
|
+
checkAvailability: () => Promise<{
|
|
883
|
+
available: boolean;
|
|
884
|
+
agents_online: number;
|
|
885
|
+
}>;
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
/** Chat widget title */
|
|
889
|
+
title?: string;
|
|
890
|
+
/** Chat widget subtitle */
|
|
891
|
+
subtitle?: string;
|
|
892
|
+
/** Input placeholder text */
|
|
893
|
+
placeholder?: string;
|
|
894
|
+
/** Visitor name */
|
|
895
|
+
visitorName?: string;
|
|
896
|
+
/** Visitor email */
|
|
897
|
+
visitorEmail?: string;
|
|
898
|
+
/** Initial greeting message from visitor */
|
|
899
|
+
greeting?: string;
|
|
900
|
+
/** Primary color */
|
|
901
|
+
primaryColor?: string;
|
|
902
|
+
/** Position of the bubble */
|
|
903
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
904
|
+
/** Z-index for the widget */
|
|
905
|
+
zIndex?: number;
|
|
906
|
+
/** Whether to show unread badge */
|
|
907
|
+
showUnreadBadge?: boolean;
|
|
908
|
+
/** Custom class name */
|
|
909
|
+
className?: string;
|
|
910
|
+
/** Callback when chat is opened */
|
|
911
|
+
onOpen?: () => void;
|
|
912
|
+
/** Callback when chat is closed */
|
|
913
|
+
onClose?: () => void;
|
|
914
|
+
}
|
|
915
|
+
declare const ChatBubble: React__default.FC<ChatBubbleProps>;
|
|
916
|
+
|
|
917
|
+
interface ChatMessageProps {
|
|
918
|
+
content: string;
|
|
919
|
+
senderType: 'visitor' | 'agent' | 'system';
|
|
920
|
+
senderName?: string;
|
|
921
|
+
timestamp?: string;
|
|
922
|
+
isRead?: boolean;
|
|
923
|
+
className?: string;
|
|
924
|
+
}
|
|
925
|
+
declare const ChatMessage: React__default.FC<ChatMessageProps>;
|
|
926
|
+
|
|
927
|
+
interface ChatInputProps {
|
|
928
|
+
onSend: (message: string) => void;
|
|
929
|
+
onTyping?: () => void;
|
|
930
|
+
placeholder?: string;
|
|
931
|
+
disabled?: boolean;
|
|
932
|
+
className?: string;
|
|
933
|
+
}
|
|
934
|
+
declare const ChatInput: React__default.FC<ChatInputProps>;
|
|
935
|
+
|
|
936
|
+
export { ChatBubble, type ChatBubbleProps, ChatInput, type ChatInputProps, ChatMessage, type ChatMessageProps, ChatWidget, type ChatWidgetProps, type CommentType, DiffsomeContext, type DiffsomeContextValue, DiffsomeProvider, type DiffsomeProviderProps, type Message, RichContent, type RichContentProps, type UseAuthReturn, type UseAvailableSlotsReturn, type UseBlogCategoriesReturn, type UseBlogOptions, type UseBlogPostReturn, type UseBlogReturn, type UseBlogSearchReturn, type UseBlogTagsReturn, type UseBoardPostReturn, type UseBoardPostsReturn, type UseBoardReturn, type UseBoardsReturn, type UseBundleItemsReturn, type UseCanReviewReturn, type UseCartReturn, type UseCategoriesReturn, type UseChatOptions, type UseChatReturn, type UseCommentsOptions, type UseCommentsReturn, type UseCouponsReturn, type UseCreateBoardPostReturn, type UseCreateOrderReturn, type UseCreateReservationReturn, type UseCreateReviewReturn, type UseCreateSubscriptionReturn, type UseCurrencyReturn, type UseDownloadsReturn, type UseEntitiesReturn, type UseEntityRecordReturn, type UseEntityRecordsReturn, type UseEntityReturn, type UseFeaturedBlogReturn, type UseFeaturedProductsReturn, type UseFormReturn, type UseMediaOptions, type UseMediaReturn, type UseMyReservationsReturn, type UseMyReviewsReturn, type UseOrderDownloadsReturn, type UseOrderReturn, type UseOrdersReturn, type UsePaymentStatusReturn, type UseProductReturn, type UseProductReviewsReturn, type UseProductsByTypeReturn, type UseProductsOptions, type UseProductsReturn, type UseReservationServicesReturn, type UseReservationSettingsReturn, type UseReservationStaffsReturn, type UseSiteReturn, type UseSocialAuthReturn, type UseStripePaymentReturn, type UseSubscriptionReturn, type UseSubscriptionsReturn, type UseTossPaymentReturn, type UseValidateCouponReturn, type UseWishlistReturn, useAuth, useAvailableSlots, useBlog, useBlogCategories, useBlogPost, useBlogSearch, useBlogTags, useBoard, useBoardPost, useBoardPosts, useBoards, useBundleItems, useBundleProducts, useCanReview, useCart, useCategories, useChat, useClient, useComments, useCoupons, useCreateBoardPost, useCreateOrder, useCreateReservation, useCreateReview, useCreateSubscription, useCurrency, useDiffsome, useDigitalProducts, useDownloads, useEntities, useEntity, useEntityRecord, useEntityRecords, useFeaturedBlog, useFeaturedProducts, useForm, useMedia, useMyReservations, useMyReviews, useOrder, useOrderDownloads, useOrders, usePaymentStatus, useProduct, useProductReviews, useProducts, useProductsByType, useReservationServices, useReservationSettings, useReservationStaffs, useSite, useSocialAuth, useStripePayment, useSubscription, useSubscriptionProducts, useSubscriptions, useTossPayment, useTypedEntity, useValidateCoupon, useWishlist };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as
|
|
3
|
-
import { ReactNode } from 'react';
|
|
4
|
-
import { Diffsome, Cart, WishlistItem, DiffsomeConfig, CurrencyInfo, SiteInfo, Member, LoginCredentials, AuthResponse, RegisterData, UpdateProfileData, ResetPasswordData, SocialProvider, WishlistToggleResult, WishlistMoveToCartResult, BundlePricing, ProductCategory, Product, PaginationMeta, ProductListParams, ProductType, CreateOrderData, Order, OrderListParams, PaymentStatusResponse, StripeCheckoutResponse, StripeVerifyResponse, TossPaymentReadyResponse, TossPaymentConfirmResponse, Coupon, CouponValidation, MemberSubscription, DigitalDownloadLink, CanReviewResponse, CreateProductReviewData, ProductReview, UpdateProductReviewData, ProductReviewStats, ProductReviewListParams, BlogCategory, BlogListParams, BlogPost, BoardPost, Board, CreateBoardPostData, BoardPostListParams, BoardListParams, Comment, CreateCommentData, Form, FormSubmissionData, FormSubmission, ReservationSlot, CreateReservationData, Reservation, ReservationService, ReservationSettings, ReservationStaff, ReservationListParams, Media, CustomEntity, EntityRecord, EntityListParams } from '@diffsome/sdk';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import React__default, { ReactNode } from 'react';
|
|
4
|
+
import { Diffsome, Cart, WishlistItem, DiffsomeConfig, CurrencyInfo, SiteInfo, Member, LoginCredentials, AuthResponse, RegisterData, UpdateProfileData, ResetPasswordData, SocialProvider, WishlistToggleResult, WishlistMoveToCartResult, BundlePricing, ProductCategory, Product, PaginationMeta, ProductListParams, ProductType, CreateOrderData, Order, OrderListParams, PaymentStatusResponse, StripeCheckoutResponse, StripeVerifyResponse, TossPaymentReadyResponse, TossPaymentConfirmResponse, Coupon, CouponValidation, MemberSubscription, DigitalDownloadLink, CanReviewResponse, CreateProductReviewData, ProductReview, UpdateProductReviewData, ProductReviewStats, ProductReviewListParams, BlogCategory, BlogListParams, BlogPost, BoardPost, Board, CreateBoardPostData, BoardPostListParams, BoardListParams, Comment, CreateCommentData, Form, FormSubmissionData, FormSubmission, ReservationSlot, CreateReservationData, Reservation, ReservationService, ReservationSettings, ReservationStaff, ReservationListParams, Media, CustomEntity, EntityRecord, EntityListParams, ChatConversation, ChatMessage as ChatMessage$1 } from '@diffsome/sdk';
|
|
5
5
|
export { AddToCartData, AuthResponse, BlogCategory, BlogListParams, BlogPost, Board, BoardListParams, BoardPost, BoardPostListParams, CanReviewResponse, Cart, CartItem, Comment, Coupon, CouponType, CouponValidation, CreateBoardPostData, CreateCommentData, CreateOrderData, CreateProductReviewData, CreateReservationData, CustomEntity, DiffsomeConfig, DigitalDownloadLink, DigitalFile, EntityField, EntityListParams, EntityRecord, EntitySchema, Form, FormSubmission, FormSubmissionData, ListResponse, LoginCredentials, Media, Member, MemberSubscription, Order, OrderItem, OrderListParams, OrderStatus, PaginatedResponse, PaginationMeta, Payment, PaymentMethod, PaymentStatus, PaymentStatusResponse, Product, ProductCategory, ProductListParams, ProductReview, ProductReviewStats, ProductType, ProductVariant, RegisterData, Reservation, ReservationService, ReservationSettings, ReservationSlot, ReservationStaff, ResetPasswordData, SiteInfo, SocialAuthUrl, SocialProvider, StripeCheckoutResponse, StripeVerifyResponse, SubscriptionInterval, SubscriptionPlan, SubscriptionStatus, TossPaymentConfirmResponse, TossPaymentReadyResponse, UpdateProfileData, WishlistItem, WishlistMoveToCartResult, WishlistToggleResult } from '@diffsome/sdk';
|
|
6
6
|
|
|
7
7
|
interface DiffsomeContextValue {
|
|
@@ -16,7 +16,7 @@ interface DiffsomeContextValue {
|
|
|
16
16
|
setWishlistItems: (items: WishlistItem[]) => void;
|
|
17
17
|
refreshWishlist: () => Promise<void>;
|
|
18
18
|
}
|
|
19
|
-
declare const DiffsomeContext:
|
|
19
|
+
declare const DiffsomeContext: React.Context<DiffsomeContextValue | null>;
|
|
20
20
|
interface DiffsomeProviderProps {
|
|
21
21
|
children: ReactNode;
|
|
22
22
|
config?: Partial<DiffsomeConfig>;
|
|
@@ -757,6 +757,46 @@ declare function useTypedEntity<T extends Record<string, any>>(slug: string): {
|
|
|
757
757
|
delete: (id: number) => Promise<void>;
|
|
758
758
|
};
|
|
759
759
|
|
|
760
|
+
interface UseChatOptions {
|
|
761
|
+
/** Auto-connect when hook mounts */
|
|
762
|
+
autoConnect?: boolean;
|
|
763
|
+
/** Visitor name */
|
|
764
|
+
visitorName?: string;
|
|
765
|
+
/** Visitor email */
|
|
766
|
+
visitorEmail?: string;
|
|
767
|
+
/** Initial greeting message */
|
|
768
|
+
greeting?: string;
|
|
769
|
+
}
|
|
770
|
+
interface UseChatReturn {
|
|
771
|
+
/** Current conversation */
|
|
772
|
+
conversation: ChatConversation | null;
|
|
773
|
+
/** Messages in the conversation */
|
|
774
|
+
messages: ChatMessage$1[];
|
|
775
|
+
/** Whether chat is loading */
|
|
776
|
+
loading: boolean;
|
|
777
|
+
/** Error if any */
|
|
778
|
+
error: Error | null;
|
|
779
|
+
/** Whether connection is active */
|
|
780
|
+
connected: boolean;
|
|
781
|
+
/** Whether agent is typing */
|
|
782
|
+
agentTyping: boolean;
|
|
783
|
+
/** Start a new conversation */
|
|
784
|
+
start: (options?: {
|
|
785
|
+
visitorName?: string;
|
|
786
|
+
visitorEmail?: string;
|
|
787
|
+
greeting?: string;
|
|
788
|
+
}) => Promise<void>;
|
|
789
|
+
/** Send a message */
|
|
790
|
+
send: (content: string) => Promise<void>;
|
|
791
|
+
/** Send typing indicator */
|
|
792
|
+
sendTyping: () => void;
|
|
793
|
+
/** Close the conversation */
|
|
794
|
+
close: () => Promise<void>;
|
|
795
|
+
/** Disconnect from real-time updates */
|
|
796
|
+
disconnect: () => void;
|
|
797
|
+
}
|
|
798
|
+
declare function useChat(options?: UseChatOptions): UseChatReturn;
|
|
799
|
+
|
|
760
800
|
interface RichContentProps {
|
|
761
801
|
/** HTML content from CMS/Editor */
|
|
762
802
|
html: string;
|
|
@@ -797,4 +837,100 @@ interface RichContentProps {
|
|
|
797
837
|
*/
|
|
798
838
|
declare function RichContent({ html, className, prose, proseVariant, proseSize, maxWidth, }: RichContentProps): react_jsx_runtime.JSX.Element;
|
|
799
839
|
|
|
800
|
-
|
|
840
|
+
interface Message {
|
|
841
|
+
id: number;
|
|
842
|
+
content: string;
|
|
843
|
+
senderType: 'visitor' | 'agent' | 'system';
|
|
844
|
+
senderName?: string;
|
|
845
|
+
timestamp?: string;
|
|
846
|
+
isRead?: boolean;
|
|
847
|
+
}
|
|
848
|
+
interface ChatWidgetProps {
|
|
849
|
+
messages: Message[];
|
|
850
|
+
onSend: (message: string) => void;
|
|
851
|
+
onTyping?: () => void;
|
|
852
|
+
onClose?: () => void;
|
|
853
|
+
title?: string;
|
|
854
|
+
subtitle?: string;
|
|
855
|
+
placeholder?: string;
|
|
856
|
+
loading?: boolean;
|
|
857
|
+
typing?: boolean;
|
|
858
|
+
className?: string;
|
|
859
|
+
}
|
|
860
|
+
declare const ChatWidget: React__default.FC<ChatWidgetProps>;
|
|
861
|
+
|
|
862
|
+
interface ChatBubbleProps {
|
|
863
|
+
/** Diffsome SDK client instance */
|
|
864
|
+
client: {
|
|
865
|
+
chat: {
|
|
866
|
+
start: (data?: {
|
|
867
|
+
visitor_name?: string;
|
|
868
|
+
visitor_email?: string;
|
|
869
|
+
initial_message?: string;
|
|
870
|
+
}) => Promise<{
|
|
871
|
+
conversation_id: number;
|
|
872
|
+
visitor_id: string;
|
|
873
|
+
}>;
|
|
874
|
+
connect: (conversationId: number) => {
|
|
875
|
+
send: (content: string) => Promise<unknown>;
|
|
876
|
+
getMessages: () => Promise<Message[]>;
|
|
877
|
+
onMessage: (callback: (msg: Message) => void) => () => void;
|
|
878
|
+
onTyping: (callback: (senderType: string) => void) => () => void;
|
|
879
|
+
sendTyping: () => void;
|
|
880
|
+
disconnect: () => void;
|
|
881
|
+
};
|
|
882
|
+
checkAvailability: () => Promise<{
|
|
883
|
+
available: boolean;
|
|
884
|
+
agents_online: number;
|
|
885
|
+
}>;
|
|
886
|
+
};
|
|
887
|
+
};
|
|
888
|
+
/** Chat widget title */
|
|
889
|
+
title?: string;
|
|
890
|
+
/** Chat widget subtitle */
|
|
891
|
+
subtitle?: string;
|
|
892
|
+
/** Input placeholder text */
|
|
893
|
+
placeholder?: string;
|
|
894
|
+
/** Visitor name */
|
|
895
|
+
visitorName?: string;
|
|
896
|
+
/** Visitor email */
|
|
897
|
+
visitorEmail?: string;
|
|
898
|
+
/** Initial greeting message from visitor */
|
|
899
|
+
greeting?: string;
|
|
900
|
+
/** Primary color */
|
|
901
|
+
primaryColor?: string;
|
|
902
|
+
/** Position of the bubble */
|
|
903
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
904
|
+
/** Z-index for the widget */
|
|
905
|
+
zIndex?: number;
|
|
906
|
+
/** Whether to show unread badge */
|
|
907
|
+
showUnreadBadge?: boolean;
|
|
908
|
+
/** Custom class name */
|
|
909
|
+
className?: string;
|
|
910
|
+
/** Callback when chat is opened */
|
|
911
|
+
onOpen?: () => void;
|
|
912
|
+
/** Callback when chat is closed */
|
|
913
|
+
onClose?: () => void;
|
|
914
|
+
}
|
|
915
|
+
declare const ChatBubble: React__default.FC<ChatBubbleProps>;
|
|
916
|
+
|
|
917
|
+
interface ChatMessageProps {
|
|
918
|
+
content: string;
|
|
919
|
+
senderType: 'visitor' | 'agent' | 'system';
|
|
920
|
+
senderName?: string;
|
|
921
|
+
timestamp?: string;
|
|
922
|
+
isRead?: boolean;
|
|
923
|
+
className?: string;
|
|
924
|
+
}
|
|
925
|
+
declare const ChatMessage: React__default.FC<ChatMessageProps>;
|
|
926
|
+
|
|
927
|
+
interface ChatInputProps {
|
|
928
|
+
onSend: (message: string) => void;
|
|
929
|
+
onTyping?: () => void;
|
|
930
|
+
placeholder?: string;
|
|
931
|
+
disabled?: boolean;
|
|
932
|
+
className?: string;
|
|
933
|
+
}
|
|
934
|
+
declare const ChatInput: React__default.FC<ChatInputProps>;
|
|
935
|
+
|
|
936
|
+
export { ChatBubble, type ChatBubbleProps, ChatInput, type ChatInputProps, ChatMessage, type ChatMessageProps, ChatWidget, type ChatWidgetProps, type CommentType, DiffsomeContext, type DiffsomeContextValue, DiffsomeProvider, type DiffsomeProviderProps, type Message, RichContent, type RichContentProps, type UseAuthReturn, type UseAvailableSlotsReturn, type UseBlogCategoriesReturn, type UseBlogOptions, type UseBlogPostReturn, type UseBlogReturn, type UseBlogSearchReturn, type UseBlogTagsReturn, type UseBoardPostReturn, type UseBoardPostsReturn, type UseBoardReturn, type UseBoardsReturn, type UseBundleItemsReturn, type UseCanReviewReturn, type UseCartReturn, type UseCategoriesReturn, type UseChatOptions, type UseChatReturn, type UseCommentsOptions, type UseCommentsReturn, type UseCouponsReturn, type UseCreateBoardPostReturn, type UseCreateOrderReturn, type UseCreateReservationReturn, type UseCreateReviewReturn, type UseCreateSubscriptionReturn, type UseCurrencyReturn, type UseDownloadsReturn, type UseEntitiesReturn, type UseEntityRecordReturn, type UseEntityRecordsReturn, type UseEntityReturn, type UseFeaturedBlogReturn, type UseFeaturedProductsReturn, type UseFormReturn, type UseMediaOptions, type UseMediaReturn, type UseMyReservationsReturn, type UseMyReviewsReturn, type UseOrderDownloadsReturn, type UseOrderReturn, type UseOrdersReturn, type UsePaymentStatusReturn, type UseProductReturn, type UseProductReviewsReturn, type UseProductsByTypeReturn, type UseProductsOptions, type UseProductsReturn, type UseReservationServicesReturn, type UseReservationSettingsReturn, type UseReservationStaffsReturn, type UseSiteReturn, type UseSocialAuthReturn, type UseStripePaymentReturn, type UseSubscriptionReturn, type UseSubscriptionsReturn, type UseTossPaymentReturn, type UseValidateCouponReturn, type UseWishlistReturn, useAuth, useAvailableSlots, useBlog, useBlogCategories, useBlogPost, useBlogSearch, useBlogTags, useBoard, useBoardPost, useBoardPosts, useBoards, useBundleItems, useBundleProducts, useCanReview, useCart, useCategories, useChat, useClient, useComments, useCoupons, useCreateBoardPost, useCreateOrder, useCreateReservation, useCreateReview, useCreateSubscription, useCurrency, useDiffsome, useDigitalProducts, useDownloads, useEntities, useEntity, useEntityRecord, useEntityRecords, useFeaturedBlog, useFeaturedProducts, useForm, useMedia, useMyReservations, useMyReviews, useOrder, useOrderDownloads, useOrders, usePaymentStatus, useProduct, useProductReviews, useProducts, useProductsByType, useReservationServices, useReservationSettings, useReservationStaffs, useSite, useSocialAuth, useStripePayment, useSubscription, useSubscriptionProducts, useSubscriptions, useTossPayment, useTypedEntity, useValidateCoupon, useWishlist };
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ChatBubble: () => ChatBubble,
|
|
24
|
+
ChatInput: () => ChatInput,
|
|
25
|
+
ChatMessage: () => ChatMessage,
|
|
26
|
+
ChatWidget: () => ChatWidget,
|
|
23
27
|
DiffsomeContext: () => DiffsomeContext,
|
|
24
28
|
DiffsomeProvider: () => DiffsomeProvider,
|
|
25
29
|
RichContent: () => RichContent,
|
|
@@ -39,6 +43,7 @@ __export(index_exports, {
|
|
|
39
43
|
useCanReview: () => useCanReview,
|
|
40
44
|
useCart: () => useCart,
|
|
41
45
|
useCategories: () => useCategories,
|
|
46
|
+
useChat: () => useChat,
|
|
42
47
|
useClient: () => useClient,
|
|
43
48
|
useComments: () => useComments,
|
|
44
49
|
useCoupons: () => useCoupons,
|
|
@@ -2410,6 +2415,105 @@ function useTypedEntity(slug) {
|
|
|
2410
2415
|
}), [client, slug]);
|
|
2411
2416
|
}
|
|
2412
2417
|
|
|
2418
|
+
// src/hooks/useChat.ts
|
|
2419
|
+
var import_react21 = require("react");
|
|
2420
|
+
function useChat(options = {}) {
|
|
2421
|
+
const client = useClient();
|
|
2422
|
+
const [conversation, setConversation] = (0, import_react21.useState)(null);
|
|
2423
|
+
const [messages, setMessages] = (0, import_react21.useState)([]);
|
|
2424
|
+
const [loading, setLoading] = (0, import_react21.useState)(false);
|
|
2425
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
2426
|
+
const [connected, setConnected] = (0, import_react21.useState)(false);
|
|
2427
|
+
const [agentTyping, setAgentTyping] = (0, import_react21.useState)(false);
|
|
2428
|
+
const [connection, setConnection] = (0, import_react21.useState)(null);
|
|
2429
|
+
const start = (0, import_react21.useCallback)(async (startOptions) => {
|
|
2430
|
+
setLoading(true);
|
|
2431
|
+
setError(null);
|
|
2432
|
+
try {
|
|
2433
|
+
const result = await client.chat.start({
|
|
2434
|
+
visitor_name: startOptions?.visitorName || options.visitorName,
|
|
2435
|
+
visitor_email: startOptions?.visitorEmail || options.visitorEmail,
|
|
2436
|
+
initial_message: startOptions?.greeting || options.greeting
|
|
2437
|
+
});
|
|
2438
|
+
const conv = await client.chat.get(result.conversation_id);
|
|
2439
|
+
setConversation(conv);
|
|
2440
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2441
|
+
setConnection(conn);
|
|
2442
|
+
setConnected(true);
|
|
2443
|
+
const existingMessages = await conn.getMessages();
|
|
2444
|
+
setMessages(existingMessages);
|
|
2445
|
+
const unsubMessage = conn.onMessage((msg) => {
|
|
2446
|
+
setMessages((prev) => {
|
|
2447
|
+
if (prev.some((m) => m.id === msg.id)) return prev;
|
|
2448
|
+
return [...prev, msg];
|
|
2449
|
+
});
|
|
2450
|
+
});
|
|
2451
|
+
const unsubTyping = conn.onTyping((senderType) => {
|
|
2452
|
+
if (senderType === "agent") {
|
|
2453
|
+
setAgentTyping(true);
|
|
2454
|
+
setTimeout(() => setAgentTyping(false), 3e3);
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2457
|
+
conn.onStatusChange((status) => {
|
|
2458
|
+
setConversation((prev) => prev ? { ...prev, status } : null);
|
|
2459
|
+
});
|
|
2460
|
+
} catch (err) {
|
|
2461
|
+
setError(err instanceof Error ? err : new Error("Failed to start chat"));
|
|
2462
|
+
} finally {
|
|
2463
|
+
setLoading(false);
|
|
2464
|
+
}
|
|
2465
|
+
}, [client.chat, options.visitorName, options.visitorEmail, options.greeting]);
|
|
2466
|
+
const send = (0, import_react21.useCallback)(async (content) => {
|
|
2467
|
+
if (!connection) {
|
|
2468
|
+
throw new Error("Not connected to chat");
|
|
2469
|
+
}
|
|
2470
|
+
try {
|
|
2471
|
+
const message = await connection.send(content);
|
|
2472
|
+
} catch (err) {
|
|
2473
|
+
setError(err instanceof Error ? err : new Error("Failed to send message"));
|
|
2474
|
+
throw err;
|
|
2475
|
+
}
|
|
2476
|
+
}, [connection]);
|
|
2477
|
+
const sendTyping = (0, import_react21.useCallback)(() => {
|
|
2478
|
+
connection?.sendTyping();
|
|
2479
|
+
}, [connection]);
|
|
2480
|
+
const close = (0, import_react21.useCallback)(async () => {
|
|
2481
|
+
if (!connection) return;
|
|
2482
|
+
try {
|
|
2483
|
+
await connection.close();
|
|
2484
|
+
setConversation((prev) => prev ? { ...prev, status: "closed" } : null);
|
|
2485
|
+
} catch (err) {
|
|
2486
|
+
setError(err instanceof Error ? err : new Error("Failed to close chat"));
|
|
2487
|
+
}
|
|
2488
|
+
}, [connection]);
|
|
2489
|
+
const disconnect = (0, import_react21.useCallback)(() => {
|
|
2490
|
+
connection?.disconnect();
|
|
2491
|
+
setConnected(false);
|
|
2492
|
+
setConnection(null);
|
|
2493
|
+
}, [connection]);
|
|
2494
|
+
(0, import_react21.useEffect)(() => {
|
|
2495
|
+
if (options.autoConnect) {
|
|
2496
|
+
start();
|
|
2497
|
+
}
|
|
2498
|
+
return () => {
|
|
2499
|
+
connection?.disconnect();
|
|
2500
|
+
};
|
|
2501
|
+
}, [options.autoConnect]);
|
|
2502
|
+
return {
|
|
2503
|
+
conversation,
|
|
2504
|
+
messages,
|
|
2505
|
+
loading,
|
|
2506
|
+
error,
|
|
2507
|
+
connected,
|
|
2508
|
+
agentTyping,
|
|
2509
|
+
start,
|
|
2510
|
+
send,
|
|
2511
|
+
sendTyping,
|
|
2512
|
+
close,
|
|
2513
|
+
disconnect
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2413
2517
|
// src/components/RichContent.tsx
|
|
2414
2518
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2415
2519
|
var quillStyles = `
|
|
@@ -2476,8 +2580,380 @@ function RichContent({
|
|
|
2476
2580
|
)
|
|
2477
2581
|
] });
|
|
2478
2582
|
}
|
|
2583
|
+
|
|
2584
|
+
// src/components/chat/ChatBubble.tsx
|
|
2585
|
+
var import_react24 = require("react");
|
|
2586
|
+
|
|
2587
|
+
// src/components/chat/ChatWidget.tsx
|
|
2588
|
+
var import_react23 = require("react");
|
|
2589
|
+
|
|
2590
|
+
// src/components/chat/ChatMessage.tsx
|
|
2591
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2592
|
+
var ChatMessage = ({
|
|
2593
|
+
content,
|
|
2594
|
+
senderType,
|
|
2595
|
+
senderName,
|
|
2596
|
+
timestamp,
|
|
2597
|
+
isRead,
|
|
2598
|
+
className = ""
|
|
2599
|
+
}) => {
|
|
2600
|
+
const isVisitor = senderType === "visitor";
|
|
2601
|
+
const isSystem = senderType === "system";
|
|
2602
|
+
if (isSystem) {
|
|
2603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `diffsome-chat-message-system ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: content }) });
|
|
2604
|
+
}
|
|
2605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2606
|
+
"div",
|
|
2607
|
+
{
|
|
2608
|
+
className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
|
|
2609
|
+
children: [
|
|
2610
|
+
!isVisitor && senderName && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "diffsome-chat-message-sender", children: senderName }),
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "diffsome-chat-message-bubble", children: [
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "diffsome-chat-message-content", children: content }),
|
|
2613
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "diffsome-chat-message-time", children: [
|
|
2614
|
+
timestamp,
|
|
2615
|
+
isVisitor && isRead && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "diffsome-chat-message-read", children: " \u2713" })
|
|
2616
|
+
] })
|
|
2617
|
+
] })
|
|
2618
|
+
]
|
|
2619
|
+
}
|
|
2620
|
+
);
|
|
2621
|
+
};
|
|
2622
|
+
|
|
2623
|
+
// src/components/chat/ChatInput.tsx
|
|
2624
|
+
var import_react22 = require("react");
|
|
2625
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2626
|
+
var ChatInput = ({
|
|
2627
|
+
onSend,
|
|
2628
|
+
onTyping,
|
|
2629
|
+
placeholder = "Type a message...",
|
|
2630
|
+
disabled = false,
|
|
2631
|
+
className = ""
|
|
2632
|
+
}) => {
|
|
2633
|
+
const [message, setMessage] = (0, import_react22.useState)("");
|
|
2634
|
+
const inputRef = (0, import_react22.useRef)(null);
|
|
2635
|
+
const typingTimeoutRef = (0, import_react22.useRef)(null);
|
|
2636
|
+
const handleSubmit = (e) => {
|
|
2637
|
+
e.preventDefault();
|
|
2638
|
+
if (message.trim() && !disabled) {
|
|
2639
|
+
onSend(message.trim());
|
|
2640
|
+
setMessage("");
|
|
2641
|
+
inputRef.current?.focus();
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
const handleKeyDown = (e) => {
|
|
2645
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2646
|
+
e.preventDefault();
|
|
2647
|
+
handleSubmit(e);
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
const handleChange = (e) => {
|
|
2651
|
+
setMessage(e.target.value);
|
|
2652
|
+
if (onTyping) {
|
|
2653
|
+
if (typingTimeoutRef.current) {
|
|
2654
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2655
|
+
}
|
|
2656
|
+
onTyping();
|
|
2657
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
2658
|
+
typingTimeoutRef.current = null;
|
|
2659
|
+
}, 2e3);
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2662
|
+
(0, import_react22.useEffect)(() => {
|
|
2663
|
+
return () => {
|
|
2664
|
+
if (typingTimeoutRef.current) {
|
|
2665
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2666
|
+
}
|
|
2667
|
+
};
|
|
2668
|
+
}, []);
|
|
2669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2670
|
+
"form",
|
|
2671
|
+
{
|
|
2672
|
+
className: `diffsome-chat-input ${className}`,
|
|
2673
|
+
onSubmit: handleSubmit,
|
|
2674
|
+
children: [
|
|
2675
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2676
|
+
"textarea",
|
|
2677
|
+
{
|
|
2678
|
+
ref: inputRef,
|
|
2679
|
+
value: message,
|
|
2680
|
+
onChange: handleChange,
|
|
2681
|
+
onKeyDown: handleKeyDown,
|
|
2682
|
+
placeholder,
|
|
2683
|
+
disabled,
|
|
2684
|
+
rows: 1,
|
|
2685
|
+
className: "diffsome-chat-input-field"
|
|
2686
|
+
}
|
|
2687
|
+
),
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2689
|
+
"button",
|
|
2690
|
+
{
|
|
2691
|
+
type: "submit",
|
|
2692
|
+
disabled: disabled || !message.trim(),
|
|
2693
|
+
className: "diffsome-chat-input-button",
|
|
2694
|
+
"aria-label": "Send message",
|
|
2695
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2696
|
+
"svg",
|
|
2697
|
+
{
|
|
2698
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2699
|
+
viewBox: "0 0 24 24",
|
|
2700
|
+
fill: "currentColor",
|
|
2701
|
+
width: "20",
|
|
2702
|
+
height: "20",
|
|
2703
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" })
|
|
2704
|
+
}
|
|
2705
|
+
)
|
|
2706
|
+
}
|
|
2707
|
+
)
|
|
2708
|
+
]
|
|
2709
|
+
}
|
|
2710
|
+
);
|
|
2711
|
+
};
|
|
2712
|
+
|
|
2713
|
+
// src/components/chat/ChatWidget.tsx
|
|
2714
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2715
|
+
var ChatWidget = ({
|
|
2716
|
+
messages,
|
|
2717
|
+
onSend,
|
|
2718
|
+
onTyping,
|
|
2719
|
+
onClose,
|
|
2720
|
+
title = "Chat Support",
|
|
2721
|
+
subtitle = "We typically reply within a few minutes",
|
|
2722
|
+
placeholder = "Type a message...",
|
|
2723
|
+
loading = false,
|
|
2724
|
+
typing = false,
|
|
2725
|
+
className = ""
|
|
2726
|
+
}) => {
|
|
2727
|
+
const messagesEndRef = (0, import_react23.useRef)(null);
|
|
2728
|
+
const scrollToBottom = () => {
|
|
2729
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2730
|
+
};
|
|
2731
|
+
(0, import_react23.useEffect)(() => {
|
|
2732
|
+
scrollToBottom();
|
|
2733
|
+
}, [messages, typing]);
|
|
2734
|
+
const formatTime = (timestamp) => {
|
|
2735
|
+
if (!timestamp) return void 0;
|
|
2736
|
+
const date = new Date(timestamp);
|
|
2737
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
2738
|
+
};
|
|
2739
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `diffsome-chat-widget ${className}`, children: [
|
|
2740
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-header", children: [
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-header-info", children: [
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-header-title", children: title }),
|
|
2743
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-header-subtitle", children: subtitle })
|
|
2744
|
+
] }),
|
|
2745
|
+
onClose && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2746
|
+
"button",
|
|
2747
|
+
{
|
|
2748
|
+
className: "diffsome-chat-header-close",
|
|
2749
|
+
onClick: onClose,
|
|
2750
|
+
"aria-label": "Close chat",
|
|
2751
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2752
|
+
"svg",
|
|
2753
|
+
{
|
|
2754
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2755
|
+
viewBox: "0 0 24 24",
|
|
2756
|
+
fill: "currentColor",
|
|
2757
|
+
width: "24",
|
|
2758
|
+
height: "24",
|
|
2759
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2760
|
+
}
|
|
2761
|
+
)
|
|
2762
|
+
}
|
|
2763
|
+
)
|
|
2764
|
+
] }),
|
|
2765
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-messages", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-loading", children: [
|
|
2766
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-loading-spinner" }),
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Loading messages..." })
|
|
2768
|
+
] }) : messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "diffsome-chat-empty", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "No messages yet. Start the conversation!" }) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2769
|
+
messages.map((msg) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2770
|
+
ChatMessage,
|
|
2771
|
+
{
|
|
2772
|
+
content: msg.content,
|
|
2773
|
+
senderType: msg.senderType,
|
|
2774
|
+
senderName: msg.senderName,
|
|
2775
|
+
timestamp: formatTime(msg.timestamp),
|
|
2776
|
+
isRead: msg.isRead
|
|
2777
|
+
},
|
|
2778
|
+
msg.id
|
|
2779
|
+
)),
|
|
2780
|
+
typing && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-typing", children: [
|
|
2781
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "diffsome-chat-typing-indicator", children: [
|
|
2782
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2783
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
|
|
2784
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {})
|
|
2785
|
+
] }),
|
|
2786
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Agent is typing..." })
|
|
2787
|
+
] }),
|
|
2788
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: messagesEndRef })
|
|
2789
|
+
] }) }),
|
|
2790
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2791
|
+
ChatInput,
|
|
2792
|
+
{
|
|
2793
|
+
onSend,
|
|
2794
|
+
onTyping,
|
|
2795
|
+
placeholder,
|
|
2796
|
+
disabled: loading
|
|
2797
|
+
}
|
|
2798
|
+
)
|
|
2799
|
+
] });
|
|
2800
|
+
};
|
|
2801
|
+
|
|
2802
|
+
// src/components/chat/ChatBubble.tsx
|
|
2803
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2804
|
+
var ChatBubble = ({
|
|
2805
|
+
client,
|
|
2806
|
+
title = "Chat Support",
|
|
2807
|
+
subtitle = "We typically reply within a few minutes",
|
|
2808
|
+
placeholder = "Type a message...",
|
|
2809
|
+
visitorName,
|
|
2810
|
+
visitorEmail,
|
|
2811
|
+
greeting,
|
|
2812
|
+
primaryColor = "#6366f1",
|
|
2813
|
+
position = "bottom-right",
|
|
2814
|
+
zIndex = 9999,
|
|
2815
|
+
showUnreadBadge = true,
|
|
2816
|
+
className = "",
|
|
2817
|
+
onOpen,
|
|
2818
|
+
onClose
|
|
2819
|
+
}) => {
|
|
2820
|
+
const [isOpen, setIsOpen] = (0, import_react24.useState)(false);
|
|
2821
|
+
const [messages, setMessages] = (0, import_react24.useState)([]);
|
|
2822
|
+
const [conversationId, setConversationId] = (0, import_react24.useState)(null);
|
|
2823
|
+
const [connection, setConnection] = (0, import_react24.useState)(null);
|
|
2824
|
+
const [loading, setLoading] = (0, import_react24.useState)(false);
|
|
2825
|
+
const [typing, setTyping] = (0, import_react24.useState)(false);
|
|
2826
|
+
const [unreadCount, setUnreadCount] = (0, import_react24.useState)(0);
|
|
2827
|
+
const initChat = (0, import_react24.useCallback)(async () => {
|
|
2828
|
+
if (conversationId) return;
|
|
2829
|
+
setLoading(true);
|
|
2830
|
+
try {
|
|
2831
|
+
const result = await client.chat.start({
|
|
2832
|
+
visitor_name: visitorName,
|
|
2833
|
+
visitor_email: visitorEmail,
|
|
2834
|
+
initial_message: greeting
|
|
2835
|
+
});
|
|
2836
|
+
setConversationId(result.conversation_id);
|
|
2837
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2838
|
+
setConnection(conn);
|
|
2839
|
+
const existingMessages = await conn.getMessages();
|
|
2840
|
+
setMessages(existingMessages);
|
|
2841
|
+
conn.onMessage((msg) => {
|
|
2842
|
+
setMessages((prev) => [...prev, msg]);
|
|
2843
|
+
if (!isOpen && msg.senderType !== "visitor") {
|
|
2844
|
+
setUnreadCount((c) => c + 1);
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
conn.onTyping((senderType) => {
|
|
2848
|
+
if (senderType === "agent") {
|
|
2849
|
+
setTyping(true);
|
|
2850
|
+
setTimeout(() => setTyping(false), 3e3);
|
|
2851
|
+
}
|
|
2852
|
+
});
|
|
2853
|
+
} catch (error) {
|
|
2854
|
+
console.error("Failed to initialize chat:", error);
|
|
2855
|
+
} finally {
|
|
2856
|
+
setLoading(false);
|
|
2857
|
+
}
|
|
2858
|
+
}, [client.chat, conversationId, visitorName, visitorEmail, greeting, isOpen]);
|
|
2859
|
+
const handleOpen = () => {
|
|
2860
|
+
setIsOpen(true);
|
|
2861
|
+
setUnreadCount(0);
|
|
2862
|
+
onOpen?.();
|
|
2863
|
+
if (!conversationId) {
|
|
2864
|
+
initChat();
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
const handleClose = () => {
|
|
2868
|
+
setIsOpen(false);
|
|
2869
|
+
onClose?.();
|
|
2870
|
+
};
|
|
2871
|
+
const handleSend = async (content) => {
|
|
2872
|
+
if (!connection) return;
|
|
2873
|
+
const tempMessage = {
|
|
2874
|
+
id: Date.now(),
|
|
2875
|
+
content,
|
|
2876
|
+
senderType: "visitor",
|
|
2877
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2878
|
+
};
|
|
2879
|
+
setMessages((prev) => [...prev, tempMessage]);
|
|
2880
|
+
try {
|
|
2881
|
+
await connection.send(content);
|
|
2882
|
+
} catch (error) {
|
|
2883
|
+
console.error("Failed to send message:", error);
|
|
2884
|
+
}
|
|
2885
|
+
};
|
|
2886
|
+
const handleTyping = () => {
|
|
2887
|
+
connection?.sendTyping();
|
|
2888
|
+
};
|
|
2889
|
+
(0, import_react24.useEffect)(() => {
|
|
2890
|
+
return () => {
|
|
2891
|
+
connection?.disconnect();
|
|
2892
|
+
};
|
|
2893
|
+
}, [connection]);
|
|
2894
|
+
const positionClass = position === "bottom-left" ? "diffsome-chat-bubble-left" : "diffsome-chat-bubble-right";
|
|
2895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2896
|
+
"div",
|
|
2897
|
+
{
|
|
2898
|
+
className: `diffsome-chat-bubble-container ${positionClass} ${className}`,
|
|
2899
|
+
style: { "--diffsome-chat-primary": primaryColor, zIndex },
|
|
2900
|
+
children: [
|
|
2901
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2902
|
+
ChatWidget,
|
|
2903
|
+
{
|
|
2904
|
+
messages,
|
|
2905
|
+
onSend: handleSend,
|
|
2906
|
+
onTyping: handleTyping,
|
|
2907
|
+
onClose: handleClose,
|
|
2908
|
+
title,
|
|
2909
|
+
subtitle,
|
|
2910
|
+
placeholder,
|
|
2911
|
+
loading,
|
|
2912
|
+
typing
|
|
2913
|
+
}
|
|
2914
|
+
),
|
|
2915
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2916
|
+
"button",
|
|
2917
|
+
{
|
|
2918
|
+
className: `diffsome-chat-bubble-button ${isOpen ? "diffsome-chat-bubble-button-open" : ""}`,
|
|
2919
|
+
onClick: isOpen ? handleClose : handleOpen,
|
|
2920
|
+
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
2921
|
+
children: [
|
|
2922
|
+
isOpen ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2923
|
+
"svg",
|
|
2924
|
+
{
|
|
2925
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2926
|
+
viewBox: "0 0 24 24",
|
|
2927
|
+
fill: "currentColor",
|
|
2928
|
+
width: "28",
|
|
2929
|
+
height: "28",
|
|
2930
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2931
|
+
}
|
|
2932
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2933
|
+
"svg",
|
|
2934
|
+
{
|
|
2935
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2936
|
+
viewBox: "0 0 24 24",
|
|
2937
|
+
fill: "currentColor",
|
|
2938
|
+
width: "28",
|
|
2939
|
+
height: "28",
|
|
2940
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" })
|
|
2941
|
+
}
|
|
2942
|
+
),
|
|
2943
|
+
showUnreadBadge && unreadCount > 0 && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "diffsome-chat-bubble-badge", children: unreadCount > 9 ? "9+" : unreadCount })
|
|
2944
|
+
]
|
|
2945
|
+
}
|
|
2946
|
+
)
|
|
2947
|
+
]
|
|
2948
|
+
}
|
|
2949
|
+
);
|
|
2950
|
+
};
|
|
2479
2951
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2480
2952
|
0 && (module.exports = {
|
|
2953
|
+
ChatBubble,
|
|
2954
|
+
ChatInput,
|
|
2955
|
+
ChatMessage,
|
|
2956
|
+
ChatWidget,
|
|
2481
2957
|
DiffsomeContext,
|
|
2482
2958
|
DiffsomeProvider,
|
|
2483
2959
|
RichContent,
|
|
@@ -2497,6 +2973,7 @@ function RichContent({
|
|
|
2497
2973
|
useCanReview,
|
|
2498
2974
|
useCart,
|
|
2499
2975
|
useCategories,
|
|
2976
|
+
useChat,
|
|
2500
2977
|
useClient,
|
|
2501
2978
|
useComments,
|
|
2502
2979
|
useCoupons,
|
package/dist/index.mjs
CHANGED
|
@@ -2323,6 +2323,105 @@ function useTypedEntity(slug) {
|
|
|
2323
2323
|
}), [client, slug]);
|
|
2324
2324
|
}
|
|
2325
2325
|
|
|
2326
|
+
// src/hooks/useChat.ts
|
|
2327
|
+
import { useState as useState20, useEffect as useEffect18, useCallback as useCallback21 } from "react";
|
|
2328
|
+
function useChat(options = {}) {
|
|
2329
|
+
const client = useClient();
|
|
2330
|
+
const [conversation, setConversation] = useState20(null);
|
|
2331
|
+
const [messages, setMessages] = useState20([]);
|
|
2332
|
+
const [loading, setLoading] = useState20(false);
|
|
2333
|
+
const [error, setError] = useState20(null);
|
|
2334
|
+
const [connected, setConnected] = useState20(false);
|
|
2335
|
+
const [agentTyping, setAgentTyping] = useState20(false);
|
|
2336
|
+
const [connection, setConnection] = useState20(null);
|
|
2337
|
+
const start = useCallback21(async (startOptions) => {
|
|
2338
|
+
setLoading(true);
|
|
2339
|
+
setError(null);
|
|
2340
|
+
try {
|
|
2341
|
+
const result = await client.chat.start({
|
|
2342
|
+
visitor_name: startOptions?.visitorName || options.visitorName,
|
|
2343
|
+
visitor_email: startOptions?.visitorEmail || options.visitorEmail,
|
|
2344
|
+
initial_message: startOptions?.greeting || options.greeting
|
|
2345
|
+
});
|
|
2346
|
+
const conv = await client.chat.get(result.conversation_id);
|
|
2347
|
+
setConversation(conv);
|
|
2348
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2349
|
+
setConnection(conn);
|
|
2350
|
+
setConnected(true);
|
|
2351
|
+
const existingMessages = await conn.getMessages();
|
|
2352
|
+
setMessages(existingMessages);
|
|
2353
|
+
const unsubMessage = conn.onMessage((msg) => {
|
|
2354
|
+
setMessages((prev) => {
|
|
2355
|
+
if (prev.some((m) => m.id === msg.id)) return prev;
|
|
2356
|
+
return [...prev, msg];
|
|
2357
|
+
});
|
|
2358
|
+
});
|
|
2359
|
+
const unsubTyping = conn.onTyping((senderType) => {
|
|
2360
|
+
if (senderType === "agent") {
|
|
2361
|
+
setAgentTyping(true);
|
|
2362
|
+
setTimeout(() => setAgentTyping(false), 3e3);
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
conn.onStatusChange((status) => {
|
|
2366
|
+
setConversation((prev) => prev ? { ...prev, status } : null);
|
|
2367
|
+
});
|
|
2368
|
+
} catch (err) {
|
|
2369
|
+
setError(err instanceof Error ? err : new Error("Failed to start chat"));
|
|
2370
|
+
} finally {
|
|
2371
|
+
setLoading(false);
|
|
2372
|
+
}
|
|
2373
|
+
}, [client.chat, options.visitorName, options.visitorEmail, options.greeting]);
|
|
2374
|
+
const send = useCallback21(async (content) => {
|
|
2375
|
+
if (!connection) {
|
|
2376
|
+
throw new Error("Not connected to chat");
|
|
2377
|
+
}
|
|
2378
|
+
try {
|
|
2379
|
+
const message = await connection.send(content);
|
|
2380
|
+
} catch (err) {
|
|
2381
|
+
setError(err instanceof Error ? err : new Error("Failed to send message"));
|
|
2382
|
+
throw err;
|
|
2383
|
+
}
|
|
2384
|
+
}, [connection]);
|
|
2385
|
+
const sendTyping = useCallback21(() => {
|
|
2386
|
+
connection?.sendTyping();
|
|
2387
|
+
}, [connection]);
|
|
2388
|
+
const close = useCallback21(async () => {
|
|
2389
|
+
if (!connection) return;
|
|
2390
|
+
try {
|
|
2391
|
+
await connection.close();
|
|
2392
|
+
setConversation((prev) => prev ? { ...prev, status: "closed" } : null);
|
|
2393
|
+
} catch (err) {
|
|
2394
|
+
setError(err instanceof Error ? err : new Error("Failed to close chat"));
|
|
2395
|
+
}
|
|
2396
|
+
}, [connection]);
|
|
2397
|
+
const disconnect = useCallback21(() => {
|
|
2398
|
+
connection?.disconnect();
|
|
2399
|
+
setConnected(false);
|
|
2400
|
+
setConnection(null);
|
|
2401
|
+
}, [connection]);
|
|
2402
|
+
useEffect18(() => {
|
|
2403
|
+
if (options.autoConnect) {
|
|
2404
|
+
start();
|
|
2405
|
+
}
|
|
2406
|
+
return () => {
|
|
2407
|
+
connection?.disconnect();
|
|
2408
|
+
};
|
|
2409
|
+
}, [options.autoConnect]);
|
|
2410
|
+
return {
|
|
2411
|
+
conversation,
|
|
2412
|
+
messages,
|
|
2413
|
+
loading,
|
|
2414
|
+
error,
|
|
2415
|
+
connected,
|
|
2416
|
+
agentTyping,
|
|
2417
|
+
start,
|
|
2418
|
+
send,
|
|
2419
|
+
sendTyping,
|
|
2420
|
+
close,
|
|
2421
|
+
disconnect
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2326
2425
|
// src/components/RichContent.tsx
|
|
2327
2426
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
2328
2427
|
var quillStyles = `
|
|
@@ -2389,7 +2488,379 @@ function RichContent({
|
|
|
2389
2488
|
)
|
|
2390
2489
|
] });
|
|
2391
2490
|
}
|
|
2491
|
+
|
|
2492
|
+
// src/components/chat/ChatBubble.tsx
|
|
2493
|
+
import { useState as useState22, useEffect as useEffect21, useCallback as useCallback22 } from "react";
|
|
2494
|
+
|
|
2495
|
+
// src/components/chat/ChatWidget.tsx
|
|
2496
|
+
import { useRef as useRef2, useEffect as useEffect20 } from "react";
|
|
2497
|
+
|
|
2498
|
+
// src/components/chat/ChatMessage.tsx
|
|
2499
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2500
|
+
var ChatMessage = ({
|
|
2501
|
+
content,
|
|
2502
|
+
senderType,
|
|
2503
|
+
senderName,
|
|
2504
|
+
timestamp,
|
|
2505
|
+
isRead,
|
|
2506
|
+
className = ""
|
|
2507
|
+
}) => {
|
|
2508
|
+
const isVisitor = senderType === "visitor";
|
|
2509
|
+
const isSystem = senderType === "system";
|
|
2510
|
+
if (isSystem) {
|
|
2511
|
+
return /* @__PURE__ */ jsx3("div", { className: `diffsome-chat-message-system ${className}`, children: /* @__PURE__ */ jsx3("span", { children: content }) });
|
|
2512
|
+
}
|
|
2513
|
+
return /* @__PURE__ */ jsxs2(
|
|
2514
|
+
"div",
|
|
2515
|
+
{
|
|
2516
|
+
className: `diffsome-chat-message ${isVisitor ? "diffsome-chat-message-visitor" : "diffsome-chat-message-agent"} ${className}`,
|
|
2517
|
+
children: [
|
|
2518
|
+
!isVisitor && senderName && /* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-sender", children: senderName }),
|
|
2519
|
+
/* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-bubble", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx3("div", { className: "diffsome-chat-message-content", children: content }),
|
|
2521
|
+
timestamp && /* @__PURE__ */ jsxs2("div", { className: "diffsome-chat-message-time", children: [
|
|
2522
|
+
timestamp,
|
|
2523
|
+
isVisitor && isRead && /* @__PURE__ */ jsx3("span", { className: "diffsome-chat-message-read", children: " \u2713" })
|
|
2524
|
+
] })
|
|
2525
|
+
] })
|
|
2526
|
+
]
|
|
2527
|
+
}
|
|
2528
|
+
);
|
|
2529
|
+
};
|
|
2530
|
+
|
|
2531
|
+
// src/components/chat/ChatInput.tsx
|
|
2532
|
+
import { useState as useState21, useRef, useEffect as useEffect19 } from "react";
|
|
2533
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2534
|
+
var ChatInput = ({
|
|
2535
|
+
onSend,
|
|
2536
|
+
onTyping,
|
|
2537
|
+
placeholder = "Type a message...",
|
|
2538
|
+
disabled = false,
|
|
2539
|
+
className = ""
|
|
2540
|
+
}) => {
|
|
2541
|
+
const [message, setMessage] = useState21("");
|
|
2542
|
+
const inputRef = useRef(null);
|
|
2543
|
+
const typingTimeoutRef = useRef(null);
|
|
2544
|
+
const handleSubmit = (e) => {
|
|
2545
|
+
e.preventDefault();
|
|
2546
|
+
if (message.trim() && !disabled) {
|
|
2547
|
+
onSend(message.trim());
|
|
2548
|
+
setMessage("");
|
|
2549
|
+
inputRef.current?.focus();
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
const handleKeyDown = (e) => {
|
|
2553
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2554
|
+
e.preventDefault();
|
|
2555
|
+
handleSubmit(e);
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
const handleChange = (e) => {
|
|
2559
|
+
setMessage(e.target.value);
|
|
2560
|
+
if (onTyping) {
|
|
2561
|
+
if (typingTimeoutRef.current) {
|
|
2562
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2563
|
+
}
|
|
2564
|
+
onTyping();
|
|
2565
|
+
typingTimeoutRef.current = setTimeout(() => {
|
|
2566
|
+
typingTimeoutRef.current = null;
|
|
2567
|
+
}, 2e3);
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
useEffect19(() => {
|
|
2571
|
+
return () => {
|
|
2572
|
+
if (typingTimeoutRef.current) {
|
|
2573
|
+
clearTimeout(typingTimeoutRef.current);
|
|
2574
|
+
}
|
|
2575
|
+
};
|
|
2576
|
+
}, []);
|
|
2577
|
+
return /* @__PURE__ */ jsxs3(
|
|
2578
|
+
"form",
|
|
2579
|
+
{
|
|
2580
|
+
className: `diffsome-chat-input ${className}`,
|
|
2581
|
+
onSubmit: handleSubmit,
|
|
2582
|
+
children: [
|
|
2583
|
+
/* @__PURE__ */ jsx4(
|
|
2584
|
+
"textarea",
|
|
2585
|
+
{
|
|
2586
|
+
ref: inputRef,
|
|
2587
|
+
value: message,
|
|
2588
|
+
onChange: handleChange,
|
|
2589
|
+
onKeyDown: handleKeyDown,
|
|
2590
|
+
placeholder,
|
|
2591
|
+
disabled,
|
|
2592
|
+
rows: 1,
|
|
2593
|
+
className: "diffsome-chat-input-field"
|
|
2594
|
+
}
|
|
2595
|
+
),
|
|
2596
|
+
/* @__PURE__ */ jsx4(
|
|
2597
|
+
"button",
|
|
2598
|
+
{
|
|
2599
|
+
type: "submit",
|
|
2600
|
+
disabled: disabled || !message.trim(),
|
|
2601
|
+
className: "diffsome-chat-input-button",
|
|
2602
|
+
"aria-label": "Send message",
|
|
2603
|
+
children: /* @__PURE__ */ jsx4(
|
|
2604
|
+
"svg",
|
|
2605
|
+
{
|
|
2606
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2607
|
+
viewBox: "0 0 24 24",
|
|
2608
|
+
fill: "currentColor",
|
|
2609
|
+
width: "20",
|
|
2610
|
+
height: "20",
|
|
2611
|
+
children: /* @__PURE__ */ jsx4("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" })
|
|
2612
|
+
}
|
|
2613
|
+
)
|
|
2614
|
+
}
|
|
2615
|
+
)
|
|
2616
|
+
]
|
|
2617
|
+
}
|
|
2618
|
+
);
|
|
2619
|
+
};
|
|
2620
|
+
|
|
2621
|
+
// src/components/chat/ChatWidget.tsx
|
|
2622
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2623
|
+
var ChatWidget = ({
|
|
2624
|
+
messages,
|
|
2625
|
+
onSend,
|
|
2626
|
+
onTyping,
|
|
2627
|
+
onClose,
|
|
2628
|
+
title = "Chat Support",
|
|
2629
|
+
subtitle = "We typically reply within a few minutes",
|
|
2630
|
+
placeholder = "Type a message...",
|
|
2631
|
+
loading = false,
|
|
2632
|
+
typing = false,
|
|
2633
|
+
className = ""
|
|
2634
|
+
}) => {
|
|
2635
|
+
const messagesEndRef = useRef2(null);
|
|
2636
|
+
const scrollToBottom = () => {
|
|
2637
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2638
|
+
};
|
|
2639
|
+
useEffect20(() => {
|
|
2640
|
+
scrollToBottom();
|
|
2641
|
+
}, [messages, typing]);
|
|
2642
|
+
const formatTime = (timestamp) => {
|
|
2643
|
+
if (!timestamp) return void 0;
|
|
2644
|
+
const date = new Date(timestamp);
|
|
2645
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
2646
|
+
};
|
|
2647
|
+
return /* @__PURE__ */ jsxs4("div", { className: `diffsome-chat-widget ${className}`, children: [
|
|
2648
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-header", children: [
|
|
2649
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-header-info", children: [
|
|
2650
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-header-title", children: title }),
|
|
2651
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-header-subtitle", children: subtitle })
|
|
2652
|
+
] }),
|
|
2653
|
+
onClose && /* @__PURE__ */ jsx5(
|
|
2654
|
+
"button",
|
|
2655
|
+
{
|
|
2656
|
+
className: "diffsome-chat-header-close",
|
|
2657
|
+
onClick: onClose,
|
|
2658
|
+
"aria-label": "Close chat",
|
|
2659
|
+
children: /* @__PURE__ */ jsx5(
|
|
2660
|
+
"svg",
|
|
2661
|
+
{
|
|
2662
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2663
|
+
viewBox: "0 0 24 24",
|
|
2664
|
+
fill: "currentColor",
|
|
2665
|
+
width: "24",
|
|
2666
|
+
height: "24",
|
|
2667
|
+
children: /* @__PURE__ */ jsx5("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2668
|
+
}
|
|
2669
|
+
)
|
|
2670
|
+
}
|
|
2671
|
+
)
|
|
2672
|
+
] }),
|
|
2673
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-messages", children: loading ? /* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-loading", children: [
|
|
2674
|
+
/* @__PURE__ */ jsx5("div", { className: "diffsome-chat-loading-spinner" }),
|
|
2675
|
+
/* @__PURE__ */ jsx5("span", { children: "Loading messages..." })
|
|
2676
|
+
] }) : messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "diffsome-chat-empty", children: /* @__PURE__ */ jsx5("span", { children: "No messages yet. Start the conversation!" }) }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2677
|
+
messages.map((msg) => /* @__PURE__ */ jsx5(
|
|
2678
|
+
ChatMessage,
|
|
2679
|
+
{
|
|
2680
|
+
content: msg.content,
|
|
2681
|
+
senderType: msg.senderType,
|
|
2682
|
+
senderName: msg.senderName,
|
|
2683
|
+
timestamp: formatTime(msg.timestamp),
|
|
2684
|
+
isRead: msg.isRead
|
|
2685
|
+
},
|
|
2686
|
+
msg.id
|
|
2687
|
+
)),
|
|
2688
|
+
typing && /* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-typing", children: [
|
|
2689
|
+
/* @__PURE__ */ jsxs4("div", { className: "diffsome-chat-typing-indicator", children: [
|
|
2690
|
+
/* @__PURE__ */ jsx5("span", {}),
|
|
2691
|
+
/* @__PURE__ */ jsx5("span", {}),
|
|
2692
|
+
/* @__PURE__ */ jsx5("span", {})
|
|
2693
|
+
] }),
|
|
2694
|
+
/* @__PURE__ */ jsx5("span", { children: "Agent is typing..." })
|
|
2695
|
+
] }),
|
|
2696
|
+
/* @__PURE__ */ jsx5("div", { ref: messagesEndRef })
|
|
2697
|
+
] }) }),
|
|
2698
|
+
/* @__PURE__ */ jsx5(
|
|
2699
|
+
ChatInput,
|
|
2700
|
+
{
|
|
2701
|
+
onSend,
|
|
2702
|
+
onTyping,
|
|
2703
|
+
placeholder,
|
|
2704
|
+
disabled: loading
|
|
2705
|
+
}
|
|
2706
|
+
)
|
|
2707
|
+
] });
|
|
2708
|
+
};
|
|
2709
|
+
|
|
2710
|
+
// src/components/chat/ChatBubble.tsx
|
|
2711
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2712
|
+
var ChatBubble = ({
|
|
2713
|
+
client,
|
|
2714
|
+
title = "Chat Support",
|
|
2715
|
+
subtitle = "We typically reply within a few minutes",
|
|
2716
|
+
placeholder = "Type a message...",
|
|
2717
|
+
visitorName,
|
|
2718
|
+
visitorEmail,
|
|
2719
|
+
greeting,
|
|
2720
|
+
primaryColor = "#6366f1",
|
|
2721
|
+
position = "bottom-right",
|
|
2722
|
+
zIndex = 9999,
|
|
2723
|
+
showUnreadBadge = true,
|
|
2724
|
+
className = "",
|
|
2725
|
+
onOpen,
|
|
2726
|
+
onClose
|
|
2727
|
+
}) => {
|
|
2728
|
+
const [isOpen, setIsOpen] = useState22(false);
|
|
2729
|
+
const [messages, setMessages] = useState22([]);
|
|
2730
|
+
const [conversationId, setConversationId] = useState22(null);
|
|
2731
|
+
const [connection, setConnection] = useState22(null);
|
|
2732
|
+
const [loading, setLoading] = useState22(false);
|
|
2733
|
+
const [typing, setTyping] = useState22(false);
|
|
2734
|
+
const [unreadCount, setUnreadCount] = useState22(0);
|
|
2735
|
+
const initChat = useCallback22(async () => {
|
|
2736
|
+
if (conversationId) return;
|
|
2737
|
+
setLoading(true);
|
|
2738
|
+
try {
|
|
2739
|
+
const result = await client.chat.start({
|
|
2740
|
+
visitor_name: visitorName,
|
|
2741
|
+
visitor_email: visitorEmail,
|
|
2742
|
+
initial_message: greeting
|
|
2743
|
+
});
|
|
2744
|
+
setConversationId(result.conversation_id);
|
|
2745
|
+
const conn = client.chat.connect(result.conversation_id);
|
|
2746
|
+
setConnection(conn);
|
|
2747
|
+
const existingMessages = await conn.getMessages();
|
|
2748
|
+
setMessages(existingMessages);
|
|
2749
|
+
conn.onMessage((msg) => {
|
|
2750
|
+
setMessages((prev) => [...prev, msg]);
|
|
2751
|
+
if (!isOpen && msg.senderType !== "visitor") {
|
|
2752
|
+
setUnreadCount((c) => c + 1);
|
|
2753
|
+
}
|
|
2754
|
+
});
|
|
2755
|
+
conn.onTyping((senderType) => {
|
|
2756
|
+
if (senderType === "agent") {
|
|
2757
|
+
setTyping(true);
|
|
2758
|
+
setTimeout(() => setTyping(false), 3e3);
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
} catch (error) {
|
|
2762
|
+
console.error("Failed to initialize chat:", error);
|
|
2763
|
+
} finally {
|
|
2764
|
+
setLoading(false);
|
|
2765
|
+
}
|
|
2766
|
+
}, [client.chat, conversationId, visitorName, visitorEmail, greeting, isOpen]);
|
|
2767
|
+
const handleOpen = () => {
|
|
2768
|
+
setIsOpen(true);
|
|
2769
|
+
setUnreadCount(0);
|
|
2770
|
+
onOpen?.();
|
|
2771
|
+
if (!conversationId) {
|
|
2772
|
+
initChat();
|
|
2773
|
+
}
|
|
2774
|
+
};
|
|
2775
|
+
const handleClose = () => {
|
|
2776
|
+
setIsOpen(false);
|
|
2777
|
+
onClose?.();
|
|
2778
|
+
};
|
|
2779
|
+
const handleSend = async (content) => {
|
|
2780
|
+
if (!connection) return;
|
|
2781
|
+
const tempMessage = {
|
|
2782
|
+
id: Date.now(),
|
|
2783
|
+
content,
|
|
2784
|
+
senderType: "visitor",
|
|
2785
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2786
|
+
};
|
|
2787
|
+
setMessages((prev) => [...prev, tempMessage]);
|
|
2788
|
+
try {
|
|
2789
|
+
await connection.send(content);
|
|
2790
|
+
} catch (error) {
|
|
2791
|
+
console.error("Failed to send message:", error);
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
const handleTyping = () => {
|
|
2795
|
+
connection?.sendTyping();
|
|
2796
|
+
};
|
|
2797
|
+
useEffect21(() => {
|
|
2798
|
+
return () => {
|
|
2799
|
+
connection?.disconnect();
|
|
2800
|
+
};
|
|
2801
|
+
}, [connection]);
|
|
2802
|
+
const positionClass = position === "bottom-left" ? "diffsome-chat-bubble-left" : "diffsome-chat-bubble-right";
|
|
2803
|
+
return /* @__PURE__ */ jsxs5(
|
|
2804
|
+
"div",
|
|
2805
|
+
{
|
|
2806
|
+
className: `diffsome-chat-bubble-container ${positionClass} ${className}`,
|
|
2807
|
+
style: { "--diffsome-chat-primary": primaryColor, zIndex },
|
|
2808
|
+
children: [
|
|
2809
|
+
isOpen && /* @__PURE__ */ jsx6(
|
|
2810
|
+
ChatWidget,
|
|
2811
|
+
{
|
|
2812
|
+
messages,
|
|
2813
|
+
onSend: handleSend,
|
|
2814
|
+
onTyping: handleTyping,
|
|
2815
|
+
onClose: handleClose,
|
|
2816
|
+
title,
|
|
2817
|
+
subtitle,
|
|
2818
|
+
placeholder,
|
|
2819
|
+
loading,
|
|
2820
|
+
typing
|
|
2821
|
+
}
|
|
2822
|
+
),
|
|
2823
|
+
/* @__PURE__ */ jsxs5(
|
|
2824
|
+
"button",
|
|
2825
|
+
{
|
|
2826
|
+
className: `diffsome-chat-bubble-button ${isOpen ? "diffsome-chat-bubble-button-open" : ""}`,
|
|
2827
|
+
onClick: isOpen ? handleClose : handleOpen,
|
|
2828
|
+
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
2829
|
+
children: [
|
|
2830
|
+
isOpen ? /* @__PURE__ */ jsx6(
|
|
2831
|
+
"svg",
|
|
2832
|
+
{
|
|
2833
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2834
|
+
viewBox: "0 0 24 24",
|
|
2835
|
+
fill: "currentColor",
|
|
2836
|
+
width: "28",
|
|
2837
|
+
height: "28",
|
|
2838
|
+
children: /* @__PURE__ */ jsx6("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })
|
|
2839
|
+
}
|
|
2840
|
+
) : /* @__PURE__ */ jsx6(
|
|
2841
|
+
"svg",
|
|
2842
|
+
{
|
|
2843
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2844
|
+
viewBox: "0 0 24 24",
|
|
2845
|
+
fill: "currentColor",
|
|
2846
|
+
width: "28",
|
|
2847
|
+
height: "28",
|
|
2848
|
+
children: /* @__PURE__ */ jsx6("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" })
|
|
2849
|
+
}
|
|
2850
|
+
),
|
|
2851
|
+
showUnreadBadge && unreadCount > 0 && !isOpen && /* @__PURE__ */ jsx6("span", { className: "diffsome-chat-bubble-badge", children: unreadCount > 9 ? "9+" : unreadCount })
|
|
2852
|
+
]
|
|
2853
|
+
}
|
|
2854
|
+
)
|
|
2855
|
+
]
|
|
2856
|
+
}
|
|
2857
|
+
);
|
|
2858
|
+
};
|
|
2392
2859
|
export {
|
|
2860
|
+
ChatBubble,
|
|
2861
|
+
ChatInput,
|
|
2862
|
+
ChatMessage,
|
|
2863
|
+
ChatWidget,
|
|
2393
2864
|
DiffsomeContext,
|
|
2394
2865
|
DiffsomeProvider,
|
|
2395
2866
|
RichContent,
|
|
@@ -2409,6 +2880,7 @@ export {
|
|
|
2409
2880
|
useCanReview,
|
|
2410
2881
|
useCart,
|
|
2411
2882
|
useCategories,
|
|
2883
|
+
useChat,
|
|
2412
2884
|
useClient,
|
|
2413
2885
|
useComments,
|
|
2414
2886
|
useCoupons,
|