app-tutor-ai-consumer 1.52.1 → 1.54.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 +17 -0
- package/package.json +1 -1
- package/src/config/datahub/actions.ts +2 -1
- package/src/config/datahub/schemas/agent/tryCreateThreadSchema.ts +60 -0
- package/src/config/datahub/schemas/base-try-schema.ts +4 -1
- package/src/modules/messages/hooks/use-send-first-message/use-send-first-message.spec.tsx +68 -19
- package/src/modules/messages/hooks/use-send-first-message/use-send-first-message.tsx +38 -4
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.spec.tsx +2 -1
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.tsx +1 -0
- package/src/modules/widget/components/scroll-to-bottom-button/scroll-to-bottom-button.tsx +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# [1.54.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.53.0...v1.54.0) (2026-01-28)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- code review issues ([6d0a17a](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/6d0a17a8874001b7d30d889152a432fbf5046467))
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- add create thread datahub event ([3f8fa1e](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/3f8fa1e5e98f9bef7201a7835a56252943a35122))
|
|
10
|
+
|
|
11
|
+
# [1.53.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.52.1...v1.53.0) (2026-01-27)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- send message tsx ([db84786](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/db84786c6d67bef222476e2afdc2c5460495da4c))
|
|
16
|
+
- send user_name ([4ee8dfc](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/4ee8dfcca0cebfec8855bfc4e9df18ce22479912))
|
|
17
|
+
|
|
1
18
|
## [1.52.1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.52.0...v1.52.1) (2026-01-20)
|
|
2
19
|
|
|
3
20
|
# [1.52.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.51.0...v1.52.0) (2026-01-19)
|
package/package.json
CHANGED
|
@@ -23,5 +23,6 @@ export const ActionNames = {
|
|
|
23
23
|
CLOSE_TUTOR_ONBOARDING: `${DataHubActions.CLOSE}_tutor_onboarding`,
|
|
24
24
|
VIEW_PRODUCT_TUTOR: `${DataHubActions.VIEW}_product_tutor`,
|
|
25
25
|
VIEW_ANSWER_MESSAGE: `${DataHubActions.VIEW}_answer_message`,
|
|
26
|
-
VIEW_CHAT: `${DataHubActions.VIEW}_chat
|
|
26
|
+
VIEW_CHAT: `${DataHubActions.VIEW}_chat`,
|
|
27
|
+
TRY_CREATE_THREAD: `${DataHubActions.TRY}_create_thread`
|
|
27
28
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import HttpCodes from '@/src/lib/utils/http-codes'
|
|
2
|
+
import { ActionNames } from '../../actions'
|
|
3
|
+
import { DataHubEntities } from '../../entities'
|
|
4
|
+
import type { ActionNamesType, DataHubEntityTypes } from '../../types'
|
|
5
|
+
import BaseTrySchema from '../base-try-schema'
|
|
6
|
+
import { ProductCategories } from '../constants'
|
|
7
|
+
|
|
8
|
+
type Result = 'SUCCESSFUL' | 'FAILURE'
|
|
9
|
+
|
|
10
|
+
type ConstructorParams = {
|
|
11
|
+
title: string
|
|
12
|
+
componentName: string
|
|
13
|
+
conversationId: string
|
|
14
|
+
entity?: DataHubEntityTypes
|
|
15
|
+
result?: Result
|
|
16
|
+
statusCode?: number
|
|
17
|
+
failureDescription?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class TryCreateThreadSchema extends BaseTrySchema {
|
|
21
|
+
action: ActionNamesType
|
|
22
|
+
|
|
23
|
+
private agent: 'HOTMART_TUTOR' | 'PRODUCT_AGENT'
|
|
24
|
+
private conversationId: string
|
|
25
|
+
private title: string
|
|
26
|
+
|
|
27
|
+
constructor({
|
|
28
|
+
title,
|
|
29
|
+
componentName,
|
|
30
|
+
conversationId,
|
|
31
|
+
entity = DataHubEntities.CONVERSATIONAL_AGENT,
|
|
32
|
+
result = 'SUCCESSFUL',
|
|
33
|
+
statusCode = HttpCodes.OK,
|
|
34
|
+
failureDescription = 'NOT_FAILURE_RESULT_EVENT'
|
|
35
|
+
}: ConstructorParams) {
|
|
36
|
+
super({
|
|
37
|
+
result,
|
|
38
|
+
componentName,
|
|
39
|
+
statusCode,
|
|
40
|
+
failureDescription,
|
|
41
|
+
componentSource: 'CONTENT_LESSON',
|
|
42
|
+
productType: ProductCategories.ConversationalAgent
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
this.entity = entity
|
|
46
|
+
this.action = ActionNames.TRY_CREATE_THREAD
|
|
47
|
+
this.agent = 'PRODUCT_AGENT'
|
|
48
|
+
this.conversationId = conversationId
|
|
49
|
+
this.title = title
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getDataHubEventData(): Record<string, unknown> {
|
|
53
|
+
return {
|
|
54
|
+
...super.prepare(),
|
|
55
|
+
agent: this.agent,
|
|
56
|
+
conversationId: this.conversationId,
|
|
57
|
+
title: this.title
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -4,6 +4,7 @@ import { DataHubEntities } from '../entities'
|
|
|
4
4
|
import type { DataHubEntityTypes, ResultType, ScreenNamesType } from '../types'
|
|
5
5
|
|
|
6
6
|
import BaseProductSchema from './base-product-schema'
|
|
7
|
+
import type { ProductCategoriesType } from './types'
|
|
7
8
|
|
|
8
9
|
export type BaseTrySchemaConstructorArgs = {
|
|
9
10
|
componentName: string
|
|
@@ -14,6 +15,7 @@ export type BaseTrySchemaConstructorArgs = {
|
|
|
14
15
|
statusCode?: number
|
|
15
16
|
failureDescription?: string
|
|
16
17
|
screenName?: ScreenNamesType
|
|
18
|
+
productType?: ProductCategoriesType
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
abstract class BaseTrySchema extends BaseProductSchema {
|
|
@@ -31,6 +33,7 @@ abstract class BaseTrySchema extends BaseProductSchema {
|
|
|
31
33
|
const {
|
|
32
34
|
componentName,
|
|
33
35
|
componentSource,
|
|
36
|
+
productType,
|
|
34
37
|
entity = DataHubEntities.HOME,
|
|
35
38
|
failureDescription = Result.FAILURE_DESCRIPTION,
|
|
36
39
|
isLogged = true,
|
|
@@ -39,7 +42,7 @@ abstract class BaseTrySchema extends BaseProductSchema {
|
|
|
39
42
|
screenName = ScreenNames.HOME_CONSUMER
|
|
40
43
|
} = args
|
|
41
44
|
|
|
42
|
-
super()
|
|
45
|
+
super({ productType })
|
|
43
46
|
|
|
44
47
|
this.componentName = componentName
|
|
45
48
|
this.componentSource = componentSource
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { DataHubService } from '@/src/config/datahub'
|
|
2
|
+
import { TryCreateThreadSchema } from '@/src/config/datahub/schemas/agent/tryCreateThreadSchema'
|
|
1
3
|
import { renderHook } from '@/src/config/tests'
|
|
4
|
+
import HttpCodes from '@/src/lib/utils/http-codes'
|
|
2
5
|
import { useUpdateConversationTitle } from '@/src/modules/conversation/hooks/update-conversation-title'
|
|
3
|
-
import { useWidgetSettingsAtomValue } from '@/src/modules/widget/store'
|
|
6
|
+
import { useIsAgentParentAtomValue, useWidgetSettingsAtomValue } from '@/src/modules/widget/store'
|
|
4
7
|
import { useMessagesCountAtomValue } from '../../store/messages-count.atom'
|
|
5
8
|
import { useSendTextMessage } from '../use-send-text-message'
|
|
6
9
|
|
|
@@ -11,7 +14,8 @@ vi.mock('@/src/modules/conversation/hooks/update-conversation-title', () => ({
|
|
|
11
14
|
}))
|
|
12
15
|
|
|
13
16
|
vi.mock('@/src/modules/widget/store', () => ({
|
|
14
|
-
useWidgetSettingsAtomValue: vi.fn()
|
|
17
|
+
useWidgetSettingsAtomValue: vi.fn(),
|
|
18
|
+
useIsAgentParentAtomValue: vi.fn()
|
|
15
19
|
}))
|
|
16
20
|
|
|
17
21
|
vi.mock('../../store/messages-count.atom', () => ({
|
|
@@ -25,6 +29,19 @@ vi.mock('../use-send-text-message', () => ({
|
|
|
25
29
|
describe('useSendFirstMessage', () => {
|
|
26
30
|
const mockSendMessage = vi.fn()
|
|
27
31
|
const mockUpdateTitle = vi.fn()
|
|
32
|
+
const mockMessage = { id: 'msg-1', content: 'Hello' }
|
|
33
|
+
const mockSettings = {
|
|
34
|
+
conversationId: 'conv-123',
|
|
35
|
+
productId: 'prod-456',
|
|
36
|
+
config: {
|
|
37
|
+
metadata: {
|
|
38
|
+
agentProductId: 'agent-prod-42',
|
|
39
|
+
agentName: 'Agent Name',
|
|
40
|
+
courseName: 'Course Name',
|
|
41
|
+
source: 'Source'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
28
45
|
|
|
29
46
|
beforeEach(() => {
|
|
30
47
|
vi.clearAllMocks()
|
|
@@ -47,35 +64,55 @@ describe('useSendFirstMessage', () => {
|
|
|
47
64
|
} as never)
|
|
48
65
|
|
|
49
66
|
vi.mocked(useMessagesCountAtomValue).mockReturnValue(0)
|
|
67
|
+
|
|
68
|
+
vi.mocked(useIsAgentParentAtomValue).mockReturnValue(true)
|
|
50
69
|
})
|
|
51
70
|
|
|
52
71
|
describe('when sending first message', () => {
|
|
53
|
-
it('should
|
|
54
|
-
vi.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
config: {
|
|
58
|
-
metadata: {
|
|
59
|
-
agentProductId: 'agent-prod-42',
|
|
60
|
-
agentName: 'Agent Name',
|
|
61
|
-
courseName: 'Course Name',
|
|
62
|
-
source: 'Source'
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
} as never)
|
|
66
|
-
const mockMessage = { id: 'msg-1', content: 'Hello' }
|
|
72
|
+
it('should not dispatch create thread event when in Tutor Mode', async () => {
|
|
73
|
+
vi.spyOn(DataHubService, 'sendEvent').mockImplementationOnce(() => null)
|
|
74
|
+
vi.mocked(useIsAgentParentAtomValue).mockReturnValue(false)
|
|
75
|
+
vi.mocked(useWidgetSettingsAtomValue).mockReturnValue(mockSettings as never)
|
|
67
76
|
mockSendMessage.mockResolvedValue(mockMessage)
|
|
68
77
|
mockUpdateTitle.mockResolvedValue({})
|
|
69
78
|
|
|
79
|
+
const expectedResult = {
|
|
80
|
+
conversationId: 'conv-123',
|
|
81
|
+
productId: 'agent-prod-42',
|
|
82
|
+
subject: 'Hello world'
|
|
83
|
+
}
|
|
84
|
+
|
|
70
85
|
const { result } = renderHook(() => useSendFirstMessage())
|
|
71
86
|
|
|
72
|
-
await result.current.sendFirstMessage(
|
|
87
|
+
await result.current.sendFirstMessage(expectedResult.subject)
|
|
73
88
|
|
|
74
|
-
expect(
|
|
75
|
-
|
|
89
|
+
expect(DataHubService.sendEvent).not.toHaveBeenCalled()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('should send message and update conversation title', async () => {
|
|
93
|
+
vi.spyOn(DataHubService, 'sendEvent').mockImplementation(() => null)
|
|
94
|
+
vi.mocked(useWidgetSettingsAtomValue).mockReturnValue(mockSettings as never)
|
|
95
|
+
mockSendMessage.mockResolvedValue(mockMessage)
|
|
96
|
+
mockUpdateTitle.mockResolvedValue({})
|
|
97
|
+
|
|
98
|
+
const expectedResult = {
|
|
76
99
|
conversationId: 'conv-123',
|
|
77
100
|
productId: 'agent-prod-42',
|
|
78
101
|
subject: 'Hello world'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const { result } = renderHook(() => useSendFirstMessage())
|
|
105
|
+
|
|
106
|
+
await result.current.sendFirstMessage(expectedResult.subject)
|
|
107
|
+
|
|
108
|
+
expect(mockSendMessage).toHaveBeenCalledWith(expectedResult.subject, undefined)
|
|
109
|
+
expect(mockUpdateTitle).toHaveBeenCalledWith(expectedResult)
|
|
110
|
+
expect(DataHubService.sendEvent).toHaveBeenCalledExactlyOnceWith({
|
|
111
|
+
schema: new TryCreateThreadSchema({
|
|
112
|
+
title: expectedResult.subject,
|
|
113
|
+
componentName: 'AGENT_CREATE_THREAD',
|
|
114
|
+
conversationId: expectedResult.conversationId
|
|
115
|
+
})
|
|
79
116
|
})
|
|
80
117
|
})
|
|
81
118
|
})
|
|
@@ -112,6 +149,7 @@ describe('useSendFirstMessage', () => {
|
|
|
112
149
|
|
|
113
150
|
describe('error handling', () => {
|
|
114
151
|
it('should throw error when send message fails', async () => {
|
|
152
|
+
vi.mocked(useWidgetSettingsAtomValue).mockReturnValue(mockSettings as never)
|
|
115
153
|
vi.spyOn(console, 'error').mockImplementationOnce(() => {})
|
|
116
154
|
const error = new Error('Send failed')
|
|
117
155
|
mockSendMessage.mockRejectedValue(error)
|
|
@@ -119,6 +157,17 @@ describe('useSendFirstMessage', () => {
|
|
|
119
157
|
const { result } = renderHook(() => useSendFirstMessage())
|
|
120
158
|
|
|
121
159
|
await expect(result.current.sendFirstMessage('Hello')).rejects.toThrow('Send failed')
|
|
160
|
+
|
|
161
|
+
expect(DataHubService.sendEvent).toHaveBeenCalledExactlyOnceWith({
|
|
162
|
+
schema: new TryCreateThreadSchema({
|
|
163
|
+
title: mockMessage.content,
|
|
164
|
+
componentName: 'AGENT_CREATE_THREAD',
|
|
165
|
+
conversationId: mockSettings.conversationId,
|
|
166
|
+
result: 'FAILURE',
|
|
167
|
+
statusCode: HttpCodes.BAD_REQUEST,
|
|
168
|
+
failureDescription: 'Send failed'
|
|
169
|
+
})
|
|
170
|
+
})
|
|
122
171
|
})
|
|
123
172
|
})
|
|
124
173
|
|
|
@@ -2,8 +2,11 @@ import { useCallback } from 'react'
|
|
|
2
2
|
import type { Message } from '@hotmart-org-ca/sparkie/dist/MessageService'
|
|
3
3
|
import type { MutateOptions } from '@tanstack/react-query'
|
|
4
4
|
|
|
5
|
+
import { DataHubService } from '@/src/config/datahub'
|
|
6
|
+
import { TryCreateThreadSchema } from '@/src/config/datahub/schemas/agent/tryCreateThreadSchema'
|
|
7
|
+
import HttpCodes from '@/src/lib/utils/http-codes'
|
|
5
8
|
import { useUpdateConversationTitle } from '@/src/modules/conversation/hooks/update-conversation-title'
|
|
6
|
-
import { useWidgetSettingsAtomValue } from '@/src/modules/widget/store'
|
|
9
|
+
import { useIsAgentParentAtomValue, useWidgetSettingsAtomValue } from '@/src/modules/widget/store'
|
|
7
10
|
import { useMessagesCountAtomValue } from '../../store/messages-count.atom'
|
|
8
11
|
import { excerptMessage } from '../../utils'
|
|
9
12
|
import { useSendTextMessage } from '../use-send-text-message'
|
|
@@ -13,10 +16,12 @@ function useSendFirstMessage() {
|
|
|
13
16
|
const sendMessageMutation = useSendTextMessage()
|
|
14
17
|
const updateTitleMutation = useUpdateConversationTitle()
|
|
15
18
|
const settings = useWidgetSettingsAtomValue()
|
|
19
|
+
const isAgent = useIsAgentParentAtomValue()
|
|
16
20
|
|
|
17
21
|
const sendFirstMessage = useCallback(
|
|
18
22
|
async (message: string, options?: MutateOptions<Message, Error, string, void>) => {
|
|
19
23
|
const isFirstMessage = messagesCount === 0
|
|
24
|
+
const subject = excerptMessage({ message })
|
|
20
25
|
|
|
21
26
|
try {
|
|
22
27
|
const messageResult = await sendMessageMutation.mutateAsync(message, options)
|
|
@@ -29,17 +34,46 @@ function useSendFirstMessage() {
|
|
|
29
34
|
await updateTitleMutation.mutateAsync({
|
|
30
35
|
conversationId: settings.conversationId,
|
|
31
36
|
productId: settings?.config?.metadata?.agentProductId,
|
|
32
|
-
subject
|
|
37
|
+
subject
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (isAgent) {
|
|
42
|
+
DataHubService.sendEvent({
|
|
43
|
+
schema: new TryCreateThreadSchema({
|
|
44
|
+
title: subject,
|
|
45
|
+
componentName: 'AGENT_CREATE_THREAD',
|
|
46
|
+
conversationId: settings?.conversationId || ''
|
|
47
|
+
})
|
|
33
48
|
})
|
|
34
49
|
}
|
|
35
50
|
|
|
36
51
|
return messageResult
|
|
37
52
|
} catch (error) {
|
|
38
|
-
|
|
53
|
+
if (isAgent) {
|
|
54
|
+
DataHubService.sendEvent({
|
|
55
|
+
schema: new TryCreateThreadSchema({
|
|
56
|
+
title: subject,
|
|
57
|
+
componentName: 'AGENT_CREATE_THREAD',
|
|
58
|
+
conversationId: settings?.conversationId || '',
|
|
59
|
+
result: 'FAILURE',
|
|
60
|
+
statusCode: HttpCodes.BAD_REQUEST,
|
|
61
|
+
failureDescription: error instanceof Error ? error?.message : String(error)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
39
66
|
throw error
|
|
40
67
|
}
|
|
41
68
|
},
|
|
42
|
-
[
|
|
69
|
+
[
|
|
70
|
+
messagesCount,
|
|
71
|
+
sendMessageMutation,
|
|
72
|
+
settings?.conversationId,
|
|
73
|
+
settings?.config?.metadata?.agentProductId,
|
|
74
|
+
isAgent,
|
|
75
|
+
updateTitleMutation
|
|
76
|
+
]
|
|
43
77
|
)
|
|
44
78
|
|
|
45
79
|
return {
|
|
@@ -25,7 +25,7 @@ vi.mock('ua-parser-js', () => ({ UAParser: vi.fn() }))
|
|
|
25
25
|
|
|
26
26
|
describe('useSendTextMessage', () => {
|
|
27
27
|
const message = chance.animal()
|
|
28
|
-
const getProfileMock = { data: { userId: chance.integer() } }
|
|
28
|
+
const getProfileMock = { data: { userId: chance.integer(), name: chance.name() } }
|
|
29
29
|
const defaultSettings = new WidgetSettingPropsBuilder()
|
|
30
30
|
.withClassHashId(chance.guid())
|
|
31
31
|
.withOwner_id(chance.guid())
|
|
@@ -116,6 +116,7 @@ describe('useSendTextMessage', () => {
|
|
|
116
116
|
osVersion: UAParserMock.browser.version,
|
|
117
117
|
platformDetail: UAParserMock.browser.name,
|
|
118
118
|
ucode: defaultSettings.user?.ucode,
|
|
119
|
+
user_name: getProfileMock.data.name || defaultSettings.user?.name,
|
|
119
120
|
appVersion: APP_VERSION,
|
|
120
121
|
membershipId: defaultSettings.membershipId,
|
|
121
122
|
membershipSlug: defaultSettings.membershipSlug,
|
|
@@ -94,6 +94,7 @@ function useSendTextMessage() {
|
|
|
94
94
|
platform: PLATFORM.WEB,
|
|
95
95
|
platformDetail: browserInfo.name,
|
|
96
96
|
ucode: settings.user?.ucode,
|
|
97
|
+
user_name: profileQuery.data?.name || settings.user?.name,
|
|
97
98
|
agentProductId: settings.config?.metadata?.agentProductId,
|
|
98
99
|
agentName: settings.config?.metadata?.agentName,
|
|
99
100
|
courseName: settings.config?.metadata?.courseName,
|
|
@@ -3,8 +3,10 @@ import clsx from 'clsx'
|
|
|
3
3
|
|
|
4
4
|
import { Icon } from '@/src/lib/components'
|
|
5
5
|
|
|
6
|
-
export interface IScrollToBottomButtonProps
|
|
7
|
-
|
|
6
|
+
export interface IScrollToBottomButtonProps extends DetailedHTMLProps<
|
|
7
|
+
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
8
|
+
HTMLButtonElement
|
|
9
|
+
> {
|
|
8
10
|
show?: boolean
|
|
9
11
|
top?: number
|
|
10
12
|
}
|