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 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: path.resolve(paths.ROOT, 'postcss.config.js')
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.35.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
- module.exports = {
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={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