app-tutor-ai-consumer 1.37.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/package.json +1 -1
- package/src/config/datahub/actions.ts +3 -2
- package/src/config/datahub/constants.ts +1 -0
- package/src/config/datahub/entities.ts +2 -1
- package/src/config/datahub/schemas/constants.ts +2 -1
- package/src/config/datahub/schemas/tutor/__tests__/{try-send-tutor-message.spec.ts → try-send-message.spec.ts} +11 -6
- package/src/config/datahub/schemas/tutor/__tests__/{view-tutor-answer-message.spec.ts → view-answer-message.spec.ts} +9 -4
- package/src/config/datahub/schemas/tutor/__tests__/view-chat.spec.ts +38 -0
- package/src/config/datahub/schemas/tutor/index.ts +2 -2
- package/src/config/datahub/schemas/tutor/{try-send-tutor-message.ts → try-send-message.ts} +22 -12
- package/src/config/datahub/schemas/tutor/{view-tutor-answer-message.ts → view-answer-message.ts} +20 -7
- package/src/config/datahub/schemas/tutor/view-chat.ts +56 -0
- package/src/config/datahub/types.ts +5 -0
- package/src/config/styles/global.css +3 -0
- package/src/config/tests/handlers.ts +3 -3
- package/src/modules/messages/__tests__/{signed-urls.builder.ts → files-signed-urls.builder.ts} +3 -3
- package/src/modules/messages/components/chat-file-preview/chat-file-preview.tsx +0 -1
- package/src/modules/messages/components/chat-file-preview/components/document-preview/document-preview.tsx +4 -3
- package/src/modules/messages/components/chat-file-preview/components/document-preview/types.ts +0 -3
- package/src/modules/messages/components/chat-file-preview/utils.ts +17 -0
- package/src/modules/messages/components/chat-file-uploader/chat-file-uploader.builder.ts +4 -7
- package/src/modules/messages/components/chat-file-uploader/chat-file-uploader.spec.tsx +0 -20
- package/src/modules/messages/components/chat-file-uploader/chat-file-uploader.tsx +16 -14
- package/src/modules/messages/components/chat-file-uploader-wrapper/chat-file-uploader-wrapper.tsx +34 -0
- package/src/modules/messages/components/chat-file-uploader-wrapper/index.ts +1 -0
- package/src/modules/messages/components/message-item/message-item.tsx +10 -0
- package/src/modules/messages/constants.ts +1 -1
- package/src/{lib → modules/messages}/hooks/use-chat-file-upload/constants.ts +2 -0
- package/src/modules/messages/hooks/use-chat-file-upload/use-chat-file-upload.spec.ts +19 -0
- package/src/modules/messages/hooks/use-chat-file-upload/use-chat-file-upload.ts +102 -0
- package/src/modules/messages/hooks/use-get-files-signed-urls/index.ts +1 -0
- package/src/modules/messages/hooks/{use-get-signed-urls/use-get-signed-urls.spec.tsx → use-get-files-signed-urls/use-get-files-signed-urls.spec.ts} +7 -7
- package/src/modules/messages/hooks/use-get-files-signed-urls/use-get-files-signed-urls.ts +25 -0
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.spec.tsx +1 -1
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.tsx +31 -19
- package/src/modules/messages/hooks/use-subscribe-message-received-event/use-subscribe-message-received-event.tsx +9 -5
- package/src/modules/messages/hooks/use-upload-file/index.ts +1 -0
- package/src/modules/messages/hooks/use-upload-file/use-upload-file.ts +15 -0
- package/src/modules/messages/service.direct.ts +27 -10
- package/src/modules/messages/store/attached-file.atom.ts +7 -0
- package/src/modules/messages/types.ts +30 -2
- package/src/modules/widget/components/chat-page/chat-page.tsx +26 -11
- package/src/modules/widget/hooks/index.ts +1 -0
- package/src/modules/widget/hooks/use-send-view-chat-event/index.ts +1 -0
- package/src/modules/widget/hooks/use-send-view-chat-event/use-send-view-chat-event.tsx +28 -0
- package/src/lib/hooks/use-chat-file-upload/types.ts +0 -14
- package/src/lib/hooks/use-chat-file-upload/use-chat-file-upload.spec.ts +0 -59
- package/src/lib/hooks/use-chat-file-upload/use-chat-file-upload.ts +0 -28
- package/src/modules/messages/components/chat-file-uploader/types.ts +0 -4
- package/src/modules/messages/hooks/use-get-signed-urls/index.ts +0 -1
- package/src/modules/messages/hooks/use-get-signed-urls/use-get-signed-urls.tsx +0 -38
- /package/src/{lib → modules/messages}/hooks/use-chat-file-upload/index.ts +0 -0
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
1
|
+
import { Fragment, useCallback, useEffect, useMemo, useRef } from 'react'
|
|
2
2
|
import { useInfiniteQuery } from '@tanstack/react-query'
|
|
3
3
|
|
|
4
4
|
import { useMediaQuery } from '@/src/lib/hooks'
|
|
5
5
|
import { isTextEmpty } from '@/src/lib/utils/is-text-empty'
|
|
6
6
|
import { ChatInput, MessagesList, useChatInputValueAtom } from '@/src/modules/messages/components'
|
|
7
|
+
import { ChatFileUploaderWrapper } from '@/src/modules/messages/components/chat-file-uploader-wrapper'
|
|
7
8
|
import { MessagesContainer } from '@/src/modules/messages/components/messages-container'
|
|
8
9
|
import { getAllMessagesQuery, useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
9
10
|
import { useMessagesMaxCount } from '@/src/modules/messages/store'
|
|
11
|
+
import { useAttachedFileAtom } from '@/src/modules/messages/store/attached-file.atom'
|
|
10
12
|
import { useGetProfile } from '@/src/modules/profile'
|
|
11
13
|
import { TutorWidgetEvents } from '../../events'
|
|
14
|
+
import { useSendViewChatEvent } from '../../hooks'
|
|
12
15
|
import { useSendViewTutorEvent } from '../../hooks/use-send-view-tutor-event'
|
|
13
16
|
import {
|
|
14
17
|
useWidgetLoadingAtom,
|
|
@@ -24,6 +27,7 @@ function ChatPage() {
|
|
|
24
27
|
const chatInputRef = useRef<HTMLTextAreaElement>(null)
|
|
25
28
|
const scrollerRef = useRef<HTMLDivElement>(null)
|
|
26
29
|
const settings = useWidgetSettingsAtomValue()
|
|
30
|
+
const [attachedFileAtom] = useAttachedFileAtom()
|
|
27
31
|
const profileQuery = useGetProfile()
|
|
28
32
|
const widgetTabs = useWidgetTabsValueAtom()
|
|
29
33
|
const sendTextMessageMutation = useSendTextMessage()
|
|
@@ -45,11 +49,11 @@ function ChatPage() {
|
|
|
45
49
|
}),
|
|
46
50
|
[conversationId, limit, profileId]
|
|
47
51
|
)
|
|
52
|
+
useSendViewTutorEvent()
|
|
53
|
+
useSendViewChatEvent()
|
|
48
54
|
|
|
49
55
|
const messagesQuery = useInfiniteQuery(messagesQueryConfig)
|
|
50
56
|
|
|
51
|
-
useSendViewTutorEvent()
|
|
52
|
-
|
|
53
57
|
const handleSendMessage = () => {
|
|
54
58
|
const text = chatInputRef.current?.value ?? ''
|
|
55
59
|
|
|
@@ -100,18 +104,29 @@ function ChatPage() {
|
|
|
100
104
|
}
|
|
101
105
|
}, [messagesQuery.isError, setWidgetLoading])
|
|
102
106
|
|
|
107
|
+
const ChatInputWrapper = settings?.config?.metadata?.showFileUpload
|
|
108
|
+
? ChatFileUploaderWrapper
|
|
109
|
+
: Fragment
|
|
110
|
+
|
|
103
111
|
return (
|
|
104
112
|
<PageLayout
|
|
105
113
|
asideChild={
|
|
106
114
|
<>
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
<ChatInputWrapper>
|
|
116
|
+
<ChatInput
|
|
117
|
+
name='new-chat-msg-input'
|
|
118
|
+
ref={chatInputRef}
|
|
119
|
+
onSend={widgetTabs.currentTab === 'chat' ? handleSendMessage : undefined}
|
|
120
|
+
loading={sendTextMessageMutation.isPending}
|
|
121
|
+
inputDisabled={messagesQuery?.isLoading}
|
|
122
|
+
buttonDisabled={
|
|
123
|
+
widgetLoading ||
|
|
124
|
+
messagesQuery?.isLoading ||
|
|
125
|
+
!value.trim() ||
|
|
126
|
+
(Boolean(attachedFileAtom) && !attachedFileAtom?.downloadUrl)
|
|
127
|
+
}
|
|
128
|
+
/>
|
|
129
|
+
</ChatInputWrapper>
|
|
115
130
|
|
|
116
131
|
<div className='mx-auto w-fit'>
|
|
117
132
|
<AIDisclaimer />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as useSendViewChatEvent } from './use-send-view-chat-event'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { AgentType, ComponentSource, DataHubEntities, DataHubService } from '@/src/config/datahub'
|
|
4
|
+
import ViewChatSchema from '@/src/config/datahub/schemas/tutor/view-chat'
|
|
5
|
+
import { useIsAgentParentAtomValue, useWidgetSettingsAtomValue } from '../../store'
|
|
6
|
+
|
|
7
|
+
function useSendViewChatEvent() {
|
|
8
|
+
const isAgentMode = useIsAgentParentAtomValue()
|
|
9
|
+
const settings = useWidgetSettingsAtomValue()
|
|
10
|
+
|
|
11
|
+
const sent = useRef(false)
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (sent.current) return
|
|
15
|
+
|
|
16
|
+
const schema = new ViewChatSchema({
|
|
17
|
+
componentSource: isAgentMode ? ComponentSource.PRODUCT_AGENT : ComponentSource.HOTMART_TUTOR,
|
|
18
|
+
agent: isAgentMode ? AgentType.PRODUCT_AGENT : AgentType.HOTMART_TUTOR,
|
|
19
|
+
conversationId: settings?.conversationId,
|
|
20
|
+
entity: DataHubEntities.CONVERSATIONAL_AGENT
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
DataHubService.sendEvent({ schema })
|
|
24
|
+
sent.current = true
|
|
25
|
+
}, [isAgentMode, settings?.conversationId])
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default useSendViewChatEvent
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type FileType = 'document' | 'image'
|
|
2
|
-
|
|
3
|
-
export type SelectedFile = {
|
|
4
|
-
file: File
|
|
5
|
-
type: FileType
|
|
6
|
-
name: string
|
|
7
|
-
size: number
|
|
8
|
-
previewUrl?: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type UseFileUploadReturn = {
|
|
12
|
-
selectedFile: SelectedFile | null
|
|
13
|
-
handleSelectFile: (file: File, type: FileType) => void
|
|
14
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from '@/src/config/tests'
|
|
2
|
-
|
|
3
|
-
import { useChatFileUpload } from './use-chat-file-upload'
|
|
4
|
-
|
|
5
|
-
describe('useChatFileUpload', () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
global.URL.createObjectURL = vi.fn(() => 'blob:mock-url')
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
vi.clearAllMocks()
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('should initialize with default values', () => {
|
|
15
|
-
const { result } = renderHook(() => useChatFileUpload())
|
|
16
|
-
|
|
17
|
-
expect(result.current.selectedFile).toBeNull()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
describe('when selecting a document file', () => {
|
|
21
|
-
it('should store the file with correct properties', () => {
|
|
22
|
-
const { result } = renderHook(() => useChatFileUpload())
|
|
23
|
-
|
|
24
|
-
const mockFile = new File(['content'], 'document.pdf', { type: 'application/pdf' })
|
|
25
|
-
|
|
26
|
-
act(() => {
|
|
27
|
-
result.current.handleSelectFile(mockFile, 'document')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
expect(result.current.selectedFile).toEqual({
|
|
31
|
-
file: mockFile,
|
|
32
|
-
type: 'document',
|
|
33
|
-
name: 'document.pdf',
|
|
34
|
-
size: mockFile.size
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
describe('when selecting an image file', () => {
|
|
40
|
-
it('should create a preview URL', () => {
|
|
41
|
-
const { result } = renderHook(() => useChatFileUpload())
|
|
42
|
-
|
|
43
|
-
const mockImage = new File(['image'], 'photo.jpg', { type: 'image/jpeg' })
|
|
44
|
-
|
|
45
|
-
act(() => {
|
|
46
|
-
result.current.handleSelectFile(mockImage, 'image')
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
expect(result.current.selectedFile).toEqual({
|
|
50
|
-
file: mockImage,
|
|
51
|
-
type: 'image',
|
|
52
|
-
name: 'photo.jpg',
|
|
53
|
-
size: mockImage.size,
|
|
54
|
-
previewUrl: 'blob:mock-url'
|
|
55
|
-
})
|
|
56
|
-
expect(global.URL.createObjectURL).toHaveBeenCalledWith(mockImage)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
|
|
3
|
-
import { FILE_TYPES_KEYS } from './constants'
|
|
4
|
-
import type { FileType, SelectedFile, UseFileUploadReturn } from './types'
|
|
5
|
-
|
|
6
|
-
export function useChatFileUpload(): UseFileUploadReturn {
|
|
7
|
-
const [selectedFile, setSelectedFile] = useState<SelectedFile | null>(null)
|
|
8
|
-
|
|
9
|
-
const handleSelectFile = (file: File, type: FileType) => {
|
|
10
|
-
const newFile: SelectedFile = {
|
|
11
|
-
file,
|
|
12
|
-
type,
|
|
13
|
-
name: file.name,
|
|
14
|
-
size: file.size
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (type === FILE_TYPES_KEYS.IMAGE) {
|
|
18
|
-
newFile.previewUrl = URL.createObjectURL(file)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
setSelectedFile(newFile)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
selectedFile,
|
|
26
|
-
handleSelectFile
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './use-get-signed-urls'
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useQuery } from '@tanstack/react-query'
|
|
2
|
-
|
|
3
|
-
import { MessagesEndpoints } from '../../constants'
|
|
4
|
-
import DirectMessagesService from '../../service.direct'
|
|
5
|
-
|
|
6
|
-
export type UseGetSignedUrlsProps = {
|
|
7
|
-
chatId: string
|
|
8
|
-
fileExtension: string
|
|
9
|
-
fileNameWithExtension: string
|
|
10
|
-
productId: number
|
|
11
|
-
enabled?: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function useGetSignedUrls({
|
|
15
|
-
chatId,
|
|
16
|
-
fileExtension,
|
|
17
|
-
fileNameWithExtension,
|
|
18
|
-
productId,
|
|
19
|
-
enabled
|
|
20
|
-
}: UseGetSignedUrlsProps) {
|
|
21
|
-
return useQuery({
|
|
22
|
-
queryKey: [
|
|
23
|
-
MessagesEndpoints.getSignedUrls(),
|
|
24
|
-
chatId,
|
|
25
|
-
fileExtension,
|
|
26
|
-
fileNameWithExtension,
|
|
27
|
-
productId
|
|
28
|
-
],
|
|
29
|
-
queryFn: () =>
|
|
30
|
-
DirectMessagesService.getSignedUrls({
|
|
31
|
-
chatId,
|
|
32
|
-
fileExtension,
|
|
33
|
-
fileNameWithExtension,
|
|
34
|
-
productId
|
|
35
|
-
}),
|
|
36
|
-
enabled
|
|
37
|
-
})
|
|
38
|
-
}
|
|
File without changes
|