app-tutor-ai-consumer 1.35.1 → 1.37.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 +14 -0
- package/config/rspack/rspack.config.js +8 -2
- package/package.json +2 -1
- package/postcss.config.js +38 -1
- package/src/lib/components/errors/generic/generic-error.tsx +2 -8
- 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,17 @@
|
|
|
1
|
+
# [1.37.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.36.0...v1.37.0) (2025-11-10)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- add postcss prefix ([d008da3](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/d008da3e5d587d134d5faff4b96159f7ee685b7f))
|
|
6
|
+
- adding app prefix ([b093214](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/b0932143ab524321fe477ba8b32bd3050476916f))
|
|
7
|
+
|
|
8
|
+
# [1.36.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.35.1...v1.36.0) (2025-11-07)
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
- remove retry last message ([40a18b1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/40a18b18df3c9dfb03a61fb137471aeeee6e0152))
|
|
13
|
+
- send agent initial message ([f3fec26](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/f3fec260654eefdb609040b4500d44a0a7b56687))
|
|
14
|
+
|
|
1
15
|
## [1.35.1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.35.0...v1.35.1) (2025-11-05)
|
|
2
16
|
|
|
3
17
|
# [1.35.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.34.0...v1.35.0) (2025-11-05)
|
|
@@ -115,8 +115,14 @@ module.exports = async function (env) {
|
|
|
115
115
|
{
|
|
116
116
|
loader: 'postcss-loader',
|
|
117
117
|
options: {
|
|
118
|
-
postcssOptions: {
|
|
119
|
-
config
|
|
118
|
+
postcssOptions: (loaderContext) => {
|
|
119
|
+
const config = require(path.resolve(paths.ROOT, 'postcss.config.js'))
|
|
120
|
+
return typeof config === 'function'
|
|
121
|
+
? config({
|
|
122
|
+
file: loaderContext.resourcePath,
|
|
123
|
+
resourcePath: loaderContext.resourcePath
|
|
124
|
+
})
|
|
125
|
+
: config
|
|
120
126
|
}
|
|
121
127
|
}
|
|
122
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "app-tutor-ai-consumer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.37.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "rspack serve --env=development --config config/rspack/rspack.config.js",
|
|
@@ -119,6 +119,7 @@
|
|
|
119
119
|
"immer": "~10.1.1",
|
|
120
120
|
"jotai": "~2.12.5",
|
|
121
121
|
"linkify-it": "~5.0.0",
|
|
122
|
+
"postcss-prefix-selector": "^2.1.1",
|
|
122
123
|
"prism-react-renderer": "~2.4.1",
|
|
123
124
|
"react": "~19.1.0",
|
|
124
125
|
"react-dom": "~19.1.0",
|
package/postcss.config.js
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
const prefixer = require('postcss-prefix-selector')
|
|
2
|
+
|
|
3
|
+
const postcssConfigWithPrefix = {
|
|
4
|
+
plugins: [
|
|
5
|
+
require('postcss-import'),
|
|
6
|
+
require('tailwindcss'),
|
|
7
|
+
require('autoprefixer'),
|
|
8
|
+
prefixer({
|
|
9
|
+
prefix: '#app-tutor-ai-consumer',
|
|
10
|
+
transform: (prefix, selector, prefixedSelector) => {
|
|
11
|
+
if (
|
|
12
|
+
selector.startsWith(':root') ||
|
|
13
|
+
selector.startsWith('html') ||
|
|
14
|
+
selector.startsWith('body')
|
|
15
|
+
) {
|
|
16
|
+
return selector
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (selector.startsWith('#app-tutor-ai-consumer')) {
|
|
20
|
+
return selector
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return prefixedSelector
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const postcssConfigWithoutPrefix = {
|
|
2
30
|
plugins: [require('postcss-import'), require('tailwindcss'), require('autoprefixer')]
|
|
3
31
|
}
|
|
32
|
+
|
|
33
|
+
module.exports = (ctx) => {
|
|
34
|
+
const filePath = ctx?.file || ctx?.resourcePath || ''
|
|
35
|
+
if (filePath.includes('.module.css')) {
|
|
36
|
+
return postcssConfigWithoutPrefix
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return postcssConfigWithPrefix
|
|
40
|
+
}
|
|
@@ -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>
|
|
@@ -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
|