app-tutor-ai-consumer 1.35.0 → 1.36.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 +9 -0
- package/package.json +1 -3
- package/src/config/tanstack/query-client.ts +0 -5
- package/src/config/tanstack/query-provider.tsx +4 -13
- package/src/lib/components/errors/generic/generic-error.tsx +2 -8
- package/src/modules/messages/hooks/use-infinite-get-messages/use-infinite-get-messages.tsx +0 -3
- package/src/modules/widget/components/chat-page/chat-page.tsx +21 -71
- package/src/modules/widget/components/error-page/error-page.tsx +1 -3
- package/src/modules/widget/hooks/index.ts +0 -1
- package/src/modules/widget/hooks/use-retry-last-message/index.ts +0 -1
- package/src/modules/widget/hooks/use-retry-last-message/use-retry-last-message.tsx +0 -37
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
# [1.36.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.35.1...v1.36.0) (2025-11-07)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- remove retry last message ([40a18b1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/40a18b18df3c9dfb03a61fb137471aeeee6e0152))
|
|
6
|
+
- send agent initial message ([f3fec26](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/f3fec260654eefdb609040b4500d44a0a7b56687))
|
|
7
|
+
|
|
8
|
+
## [1.35.1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.35.0...v1.35.1) (2025-11-05)
|
|
9
|
+
|
|
1
10
|
# [1.35.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.34.0...v1.35.0) (2025-11-05)
|
|
2
11
|
|
|
3
12
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "app-tutor-ai-consumer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "rspack serve --env=development --config config/rspack/rspack.config.js",
|
|
@@ -111,9 +111,7 @@
|
|
|
111
111
|
"@hotmart-org-ca/sparkie": "~5.1.4",
|
|
112
112
|
"@hotmart/event-agent-js": "~1.1.2",
|
|
113
113
|
"@optimizely/react-sdk": "~3.2.4",
|
|
114
|
-
"@tanstack/query-sync-storage-persister": "~5.80.7",
|
|
115
114
|
"@tanstack/react-query": "~5.80.6",
|
|
116
|
-
"@tanstack/react-query-persist-client": "~5.80.7",
|
|
117
115
|
"clsx": "~2.1.1",
|
|
118
116
|
"dayjs": "~1.11.13",
|
|
119
117
|
"i18next": "~25.2.1",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
|
|
2
1
|
import { QueryClient } from '@tanstack/react-query'
|
|
3
2
|
|
|
4
3
|
import { DEFAULT_STALE_TIME, HttpCodes } from '@/src/lib/utils'
|
|
@@ -26,7 +25,3 @@ export const queryClient = new QueryClient({
|
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
})
|
|
29
|
-
|
|
30
|
-
export const persister = createSyncStoragePersister({
|
|
31
|
-
storage: window.localStorage
|
|
32
|
-
})
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { QueryClient } from '@tanstack/react-query'
|
|
2
|
+
import { QueryClientProvider } from '@tanstack/react-query'
|
|
2
3
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
|
3
|
-
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
|
|
4
4
|
import type { PropsWithChildren } from 'react'
|
|
5
5
|
|
|
6
|
-
import { persister } from './query-client'
|
|
7
|
-
|
|
8
6
|
export type QueryProviderProps = PropsWithChildren<{
|
|
9
7
|
showDevTools?: boolean
|
|
10
8
|
queryClient: QueryClient
|
|
@@ -12,17 +10,10 @@ export type QueryProviderProps = PropsWithChildren<{
|
|
|
12
10
|
|
|
13
11
|
function QueryProvider({ children, queryClient, showDevTools = true }: QueryProviderProps) {
|
|
14
12
|
return (
|
|
15
|
-
<
|
|
16
|
-
client={queryClient}
|
|
17
|
-
persistOptions={
|
|
18
|
-
{
|
|
19
|
-
persister,
|
|
20
|
-
shouldPersistQuery: (query: Query) => query.meta?.persist !== false
|
|
21
|
-
} as Parameters<typeof PersistQueryClientProvider>[0]['persistOptions']
|
|
22
|
-
}>
|
|
13
|
+
<QueryClientProvider client={queryClient}>
|
|
23
14
|
{children}
|
|
24
15
|
{showDevTools && <ReactQueryDevtools buttonPosition='top-right' />}
|
|
25
|
-
</
|
|
16
|
+
</QueryClientProvider>
|
|
26
17
|
)
|
|
27
18
|
}
|
|
28
19
|
|
|
@@ -6,13 +6,7 @@ import { Button } from '@/src/lib/components'
|
|
|
6
6
|
import { PageLayout, TutorWidgetEvents, useIsAgentParentAtomValue } from '@/src/modules/widget'
|
|
7
7
|
import { WidgetHeader } from '@/src/modules/widget/components/header'
|
|
8
8
|
|
|
9
|
-
function GenericError({
|
|
10
|
-
isDarkMode = false,
|
|
11
|
-
onRetry
|
|
12
|
-
}: {
|
|
13
|
-
isDarkMode?: boolean
|
|
14
|
-
onRetry?: () => void
|
|
15
|
-
}) {
|
|
9
|
+
function GenericError({ isDarkMode = false }: { isDarkMode?: boolean }) {
|
|
16
10
|
const { t } = useTranslation()
|
|
17
11
|
const isAgentMode = useIsAgentParentAtomValue()
|
|
18
12
|
|
|
@@ -38,7 +32,7 @@ function GenericError({
|
|
|
38
32
|
<Button
|
|
39
33
|
variant='brand'
|
|
40
34
|
className='mx-auto w-full max-w-max rounded-lg !px-9 py-2 !font-light'
|
|
41
|
-
onClick={
|
|
35
|
+
onClick={() => window.location.reload()}
|
|
42
36
|
aria-label='Retry Button'>
|
|
43
37
|
{t('general.buttons.try_again')}
|
|
44
38
|
</Button>
|
|
@@ -44,9 +44,6 @@ export const getAllMessagesQuery = ({
|
|
|
44
44
|
return minSentAt
|
|
45
45
|
},
|
|
46
46
|
enabled: Boolean(conversationId && profileId) && limit > 0,
|
|
47
|
-
meta: {
|
|
48
|
-
persist: false
|
|
49
|
-
},
|
|
50
47
|
select(data) {
|
|
51
48
|
const messages = data.pages?.flatMap((page) => page.messages) ?? []
|
|
52
49
|
return messagesParser({ messages, profileId: profileId as string }).reduce(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo, useRef } from 'react'
|
|
2
|
-
import { useDecision } from '@optimizely/react-sdk'
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
3
2
|
import { useInfiniteQuery } from '@tanstack/react-query'
|
|
4
3
|
|
|
5
4
|
import { useMediaQuery } from '@/src/lib/hooks'
|
|
@@ -12,10 +11,8 @@ import { useGetProfile } from '@/src/modules/profile'
|
|
|
12
11
|
import { TutorWidgetEvents } from '../../events'
|
|
13
12
|
import { useSendViewTutorEvent } from '../../hooks/use-send-view-tutor-event'
|
|
14
13
|
import {
|
|
15
|
-
useWidgetLastUserMessageAtom,
|
|
16
14
|
useWidgetLoadingAtom,
|
|
17
15
|
useWidgetSettingsAtomValue,
|
|
18
|
-
useWidgetTabsAtom,
|
|
19
16
|
useWidgetTabsValueAtom
|
|
20
17
|
} from '../../store'
|
|
21
18
|
import { testQuestionRegex } from '../../utils'
|
|
@@ -26,19 +23,16 @@ import { PageLayout } from '../page-layout'
|
|
|
26
23
|
function ChatPage() {
|
|
27
24
|
const chatInputRef = useRef<HTMLTextAreaElement>(null)
|
|
28
25
|
const scrollerRef = useRef<HTMLDivElement>(null)
|
|
29
|
-
const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
|
30
26
|
const settings = useWidgetSettingsAtomValue()
|
|
31
27
|
const profileQuery = useGetProfile()
|
|
32
28
|
const widgetTabs = useWidgetTabsValueAtom()
|
|
33
|
-
const [, setTab] = useWidgetTabsAtom()
|
|
34
29
|
const sendTextMessageMutation = useSendTextMessage()
|
|
30
|
+
const sendInitialMessageMutation = useSendTextMessage()
|
|
35
31
|
const limit = useMessagesMaxCount()
|
|
36
32
|
const [value, setValue] = useChatInputValueAtom()
|
|
37
33
|
const [widgetLoading, setWidgetLoading] = useWidgetLoadingAtom()
|
|
38
|
-
const [, setLastUserMessage] = useWidgetLastUserMessageAtom()
|
|
39
34
|
const isMobile = useMediaQuery({ maxSize: 'md' })
|
|
40
35
|
const hasSentInitialMessage = useRef(false)
|
|
41
|
-
const [lexTutorInitialMessageFF] = useDecision('lex_tutor_new_widget_initial_message')
|
|
42
36
|
|
|
43
37
|
const conversationId = useMemo(() => settings?.conversationId, [settings?.conversationId])
|
|
44
38
|
const profileId = useMemo(() => profileQuery.data?.id, [profileQuery.data?.id])
|
|
@@ -54,36 +48,6 @@ function ChatPage() {
|
|
|
54
48
|
|
|
55
49
|
const messagesQuery = useInfiniteQuery(messagesQueryConfig)
|
|
56
50
|
|
|
57
|
-
const isAgentMode = useMemo(
|
|
58
|
-
() => settings?.config?.metadata?.parent === 'AGENT',
|
|
59
|
-
[settings?.config?.metadata?.parent]
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
const msgCount = useMemo(() => {
|
|
63
|
-
if (!messagesQuery.data) return 0
|
|
64
|
-
return Array.from(messagesQuery.data.values()).reduce(
|
|
65
|
-
(total: number, messages) => total + messages.length,
|
|
66
|
-
0
|
|
67
|
-
)
|
|
68
|
-
}, [messagesQuery.data])
|
|
69
|
-
|
|
70
|
-
const hasUserMessageWithoutResponse = useMemo(() => {
|
|
71
|
-
if (!isAgentMode || !messagesQuery.data || msgCount === 0) return false
|
|
72
|
-
|
|
73
|
-
const allMessages = Array.from(messagesQuery.data.values()).flat()
|
|
74
|
-
const userMessages = allMessages.filter((msg) => msg?.metadata?.author === 'user')
|
|
75
|
-
const aiMessages = allMessages.filter((msg) => msg?.metadata?.author !== 'user')
|
|
76
|
-
|
|
77
|
-
if (userMessages.length > aiMessages.length && aiMessages.length === 0) {
|
|
78
|
-
const lastUserMsg = userMessages[userMessages.length - 1]
|
|
79
|
-
if (lastUserMsg?.text) {
|
|
80
|
-
setLastUserMessage(lastUserMsg.text)
|
|
81
|
-
}
|
|
82
|
-
return true
|
|
83
|
-
}
|
|
84
|
-
return false
|
|
85
|
-
}, [isAgentMode, messagesQuery.data, msgCount, setLastUserMessage])
|
|
86
|
-
|
|
87
51
|
useSendViewTutorEvent()
|
|
88
52
|
|
|
89
53
|
const handleSendMessage = () => {
|
|
@@ -99,19 +63,28 @@ function ChatPage() {
|
|
|
99
63
|
})
|
|
100
64
|
}
|
|
101
65
|
|
|
66
|
+
const handleSendInitialMessage = useCallback(
|
|
67
|
+
(initialMessage: string) => {
|
|
68
|
+
if (!isTextEmpty(initialMessage)) return
|
|
69
|
+
|
|
70
|
+
sendInitialMessageMutation.mutate(initialMessage)
|
|
71
|
+
},
|
|
72
|
+
[sendInitialMessageMutation]
|
|
73
|
+
)
|
|
74
|
+
|
|
102
75
|
useEffect(() => {
|
|
103
|
-
if (hasSentInitialMessage.current
|
|
76
|
+
if (hasSentInitialMessage.current) return
|
|
77
|
+
|
|
78
|
+
if (settings?.initialMessage) {
|
|
79
|
+
handleSendInitialMessage(testQuestionRegex(settings?.initialMessage))
|
|
80
|
+
hasSentInitialMessage.current = true
|
|
81
|
+
return
|
|
82
|
+
}
|
|
104
83
|
|
|
105
84
|
const clear = TutorWidgetEvents['tutor-initial-message'].handler(({ message }) => {
|
|
106
85
|
if (message && !hasSentInitialMessage.current) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
sendTextMessageMutation.mutate(message, {
|
|
110
|
-
onSuccess() {
|
|
111
|
-
setValue('')
|
|
112
|
-
hasSentInitialMessage.current = true
|
|
113
|
-
}
|
|
114
|
-
})
|
|
86
|
+
handleSendInitialMessage(testQuestionRegex(message))
|
|
87
|
+
hasSentInitialMessage.current = true
|
|
115
88
|
}
|
|
116
89
|
})
|
|
117
90
|
|
|
@@ -119,7 +92,7 @@ function ChatPage() {
|
|
|
119
92
|
clear?.()
|
|
120
93
|
hasSentInitialMessage.current = false
|
|
121
94
|
}
|
|
122
|
-
}, [
|
|
95
|
+
}, [settings?.initialMessage, handleSendInitialMessage])
|
|
123
96
|
|
|
124
97
|
useEffect(() => {
|
|
125
98
|
if (messagesQuery.isError) {
|
|
@@ -127,29 +100,6 @@ function ChatPage() {
|
|
|
127
100
|
}
|
|
128
101
|
}, [messagesQuery.isError, setWidgetLoading])
|
|
129
102
|
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (hasUserMessageWithoutResponse) {
|
|
132
|
-
setWidgetLoading(true)
|
|
133
|
-
|
|
134
|
-
loadingTimeoutRef.current = setTimeout(() => {
|
|
135
|
-
setWidgetLoading(false)
|
|
136
|
-
setTab('error')
|
|
137
|
-
}, 60000)
|
|
138
|
-
} else {
|
|
139
|
-
if (loadingTimeoutRef.current) {
|
|
140
|
-
clearTimeout(loadingTimeoutRef.current)
|
|
141
|
-
loadingTimeoutRef.current = null
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return () => {
|
|
146
|
-
if (loadingTimeoutRef.current) {
|
|
147
|
-
clearTimeout(loadingTimeoutRef.current)
|
|
148
|
-
loadingTimeoutRef.current = null
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}, [hasUserMessageWithoutResponse, setWidgetLoading, setTab])
|
|
152
|
-
|
|
153
103
|
return (
|
|
154
104
|
<PageLayout
|
|
155
105
|
asideChild={
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { GenericError } from '@/src/lib/components'
|
|
2
|
-
import { useRetryLastMessage } from '../../hooks'
|
|
3
2
|
import { useWidgetSettingsAtomValue } from '../../store'
|
|
4
3
|
|
|
5
4
|
function WidgetErrorPage() {
|
|
6
5
|
const settings = useWidgetSettingsAtomValue()
|
|
7
|
-
const handleRetry = useRetryLastMessage()
|
|
8
6
|
|
|
9
|
-
return <GenericError isDarkMode={settings?.config?.theme === 'dark'}
|
|
7
|
+
return <GenericError isDarkMode={settings?.config?.theme === 'dark'} />
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
export default WidgetErrorPage
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as useRetryLastMessage } from './use-retry-last-message'
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
2
|
-
|
|
3
|
-
import { useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
4
|
-
import {
|
|
5
|
-
useWidgetLastUserMessageAtom,
|
|
6
|
-
useWidgetLastUserMessageAtomValue,
|
|
7
|
-
useWidgetSettingsAtomValue,
|
|
8
|
-
useWidgetTabsAtom
|
|
9
|
-
} from '../../store'
|
|
10
|
-
|
|
11
|
-
function useRetryLastMessage() {
|
|
12
|
-
const settings = useWidgetSettingsAtomValue()
|
|
13
|
-
const lastUserMessage = useWidgetLastUserMessageAtomValue()
|
|
14
|
-
const [, setLastUserMessage] = useWidgetLastUserMessageAtom()
|
|
15
|
-
const [, setTab] = useWidgetTabsAtom()
|
|
16
|
-
const sendTextMessageMutation = useSendTextMessage()
|
|
17
|
-
|
|
18
|
-
const isAgentMode = useMemo(
|
|
19
|
-
() => settings?.config?.metadata?.parent === 'AGENT',
|
|
20
|
-
[settings?.config?.metadata?.parent]
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
const retryLastMessage = () => {
|
|
24
|
-
if (isAgentMode && lastUserMessage) {
|
|
25
|
-
sendTextMessageMutation.mutate(lastUserMessage, {
|
|
26
|
-
onSuccess() {
|
|
27
|
-
setLastUserMessage('')
|
|
28
|
-
setTab('chat')
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return retryLastMessage
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default useRetryLastMessage
|