app-tutor-ai-consumer 1.35.1 → 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 CHANGED
@@ -1,3 +1,10 @@
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
+
1
8
  ## [1.35.1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.35.0...v1.35.1) (2025-11-05)
2
9
 
3
10
  # [1.35.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.34.0...v1.35.0) (2025-11-05)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app-tutor-ai-consumer",
3
- "version": "1.35.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",
@@ -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={onRetry ? () => onRetry() : () => window.location.reload()}
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 || !lexTutorInitialMessageFF.enabled) return
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
- setValue(testQuestionRegex(message))
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
- }, [lexTutorInitialMessageFF.enabled, sendTextMessageMutation, setValue])
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'} onRetry={handleRetry} />
7
+ return <GenericError isDarkMode={settings?.config?.theme === 'dark'} />
10
8
  }
11
9
 
12
10
  export default WidgetErrorPage
@@ -1,4 +1,3 @@
1
1
  export * from './use-listen-to-theme-change-event'
2
2
  export * from './use-listen-to-visibility-events'
3
- export * from './use-retry-last-message'
4
3
  export * from './use-send-view-tutor-event'
@@ -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