app-tutor-ai-consumer 1.6.0 → 1.8.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/.github/workflows/production.yml +2 -2
- package/.github/workflows/rollback.yml +2 -2
- package/.github/workflows/staging.yml +63 -8
- package/CHANGELOG.md +12 -0
- package/package.json +2 -1
- package/src/config/styles/global.css +3 -2
- package/src/lib/components/icons/icon-names.d.ts +1 -1
- package/src/lib/components/icons/stop.svg +4 -0
- package/src/modules/messages/components/chat-input/chat-input.spec.tsx +11 -7
- package/src/modules/messages/components/chat-input/chat-input.tsx +87 -56
- package/src/modules/messages/components/chat-input/styles.module.css +3 -0
- package/src/modules/messages/components/chat-input/types.ts +3 -0
- package/src/modules/widget/components/chat-page/chat-page.tsx +11 -4
- package/src/modules/widget/components/starter-page/starter-page.tsx +3 -3
|
@@ -95,7 +95,7 @@ jobs:
|
|
|
95
95
|
uses: newrelic/deployment-marker-action@v2.5.1
|
|
96
96
|
env:
|
|
97
97
|
VERSION: ${{ env.VERSION }}
|
|
98
|
-
NEW_RELIC_API_KEY:
|
|
98
|
+
NEW_RELIC_API_KEY: ${{ secrets.NEW_RELIC_API_KEY }}
|
|
99
99
|
NEW_RELIC_DEPLOYMENT_ENTITY_GUID: Mjc1MDN8QVBNfEFQUExJQ0FUSU9OfDEwOTUyNjI4MTc
|
|
100
100
|
with:
|
|
101
101
|
apiKey: ${{ env.NEW_RELIC_API_KEY }}
|
|
@@ -139,7 +139,7 @@ jobs:
|
|
|
139
139
|
"textButton": {
|
|
140
140
|
"onClick": {
|
|
141
141
|
"openLink": {
|
|
142
|
-
"url": "https://github.com/Hotmart-Org/app-
|
|
142
|
+
"url": "https://github.com/Hotmart-Org/app-tutor-ai-consumer/actions/runs/${{ github.run_id }}"
|
|
143
143
|
}
|
|
144
144
|
},
|
|
145
145
|
"text": "Follow this deploy"
|
|
@@ -57,7 +57,7 @@ jobs:
|
|
|
57
57
|
uses: newrelic/deployment-marker-action@v2.5.1
|
|
58
58
|
env:
|
|
59
59
|
ROLLBACK_VERSION: ${{ github.event.inputs.rollbackVersion }}
|
|
60
|
-
NEW_RELIC_API_KEY:
|
|
60
|
+
NEW_RELIC_API_KEY: ${{ secrets.NEW_RELIC_API_KEY }}
|
|
61
61
|
NEW_RELIC_DEPLOYMENT_ENTITY_GUID: Mjc1MDN8QVBNfEFQUExJQ0FUSU9OfDEwOTE1MDMzMTE
|
|
62
62
|
with:
|
|
63
63
|
apiKey: ${{ env.NEW_RELIC_API_KEY }}
|
|
@@ -104,7 +104,7 @@ jobs:
|
|
|
104
104
|
uses: newrelic/deployment-marker-action@v2.5.1
|
|
105
105
|
env:
|
|
106
106
|
ROLLBACK_VERSION: ${{ github.event.inputs.rollbackVersion }}
|
|
107
|
-
NEW_RELIC_API_KEY:
|
|
107
|
+
NEW_RELIC_API_KEY: ${{ secrets.NEW_RELIC_API_KEY }}
|
|
108
108
|
NEW_RELIC_DEPLOYMENT_ENTITY_GUID: Mjc1MDN8QVBNfEFQUExJQ0FUSU9OfDEwOTUyNjI4MTc
|
|
109
109
|
with:
|
|
110
110
|
apiKey: ${{ env.NEW_RELIC_API_KEY }}
|
|
@@ -123,12 +123,17 @@ jobs:
|
|
|
123
123
|
cdn-url: ${{ env.CLOUDFRONT_URL }}
|
|
124
124
|
|
|
125
125
|
staging-notification:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
name: 'Staging Notification'
|
|
127
|
+
runs-on: [buildstaging-iac]
|
|
128
|
+
needs: ['deploy-staging']
|
|
129
|
+
steps:
|
|
130
130
|
- name: Checkout
|
|
131
131
|
uses: actions/checkout@v4
|
|
132
|
+
with:
|
|
133
|
+
token: ${{ secrets.CI_GH_TOKEN }}
|
|
134
|
+
fetch-depth: 0
|
|
135
|
+
ref: ${{ env.BRANCH_REF }}
|
|
136
|
+
fetch-tags: true
|
|
132
137
|
|
|
133
138
|
- name: Extract version from package.json
|
|
134
139
|
run: |
|
|
@@ -146,7 +151,57 @@ jobs:
|
|
|
146
151
|
apiKey: ${{ env.NEW_RELIC_API_KEY }}
|
|
147
152
|
guid: ${{ env.NEW_RELIC_DEPLOYMENT_ENTITY_GUID }}
|
|
148
153
|
version: ${{ env.VERSION }}
|
|
149
|
-
user:
|
|
150
|
-
changelog:
|
|
151
|
-
commit:
|
|
152
|
-
description:
|
|
154
|
+
user: "${{ github.actor }}"
|
|
155
|
+
changelog: "https://github.com/${{ github.repository }}/blob/master/CHANGELOG.md"
|
|
156
|
+
commit: "${{ github.sha }}"
|
|
157
|
+
description: "Deploy: ${{env.APP_NAME}} v${{ env.VERSION }} - ${{ github.ref_name }}"
|
|
158
|
+
|
|
159
|
+
- name: Notify Google Chat
|
|
160
|
+
uses: Hotmart-Org/actions/notification@master
|
|
161
|
+
env:
|
|
162
|
+
VERSION: ${{ env.VERSION }}
|
|
163
|
+
with:
|
|
164
|
+
type: 'Original'
|
|
165
|
+
author: true
|
|
166
|
+
webhook-chat: 'https://chat.googleapis.com/v1/spaces/AAAA1nvOyjo/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=uuL7DA8zTxUkJjQa39HIM0TYVZV0DvneZ0mklNhEr5M'
|
|
167
|
+
body: |
|
|
168
|
+
{
|
|
169
|
+
"text": "📦 *[STAGING] app-tutor-ai-consumer v${{ env.VERSION }}*: staging deploy: ${{ github.ref_name }}",
|
|
170
|
+
"cards": [
|
|
171
|
+
{
|
|
172
|
+
"header": {
|
|
173
|
+
"title": "Started by ${{ github.actor }}"
|
|
174
|
+
},
|
|
175
|
+
"sections": [
|
|
176
|
+
{
|
|
177
|
+
"widgets": [
|
|
178
|
+
{
|
|
179
|
+
"buttons": [
|
|
180
|
+
{
|
|
181
|
+
"textButton": {
|
|
182
|
+
"onClick": {
|
|
183
|
+
"openLink": {
|
|
184
|
+
"url": "${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"text": "View commit"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"textButton": {
|
|
192
|
+
"onClick": {
|
|
193
|
+
"openLink": {
|
|
194
|
+
"url": "https://github.com/Hotmart-Org/app-tutor-ai-consumer/actions/runs/${{ github.run_id }}"
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"text": "Follow this deploy"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [1.8.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.7.0...v1.8.0) (2025-07-14)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- changing notifications and keys ([57312bc](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/57312bc069bc1f9ba0fefde00f252f615e52efa4))
|
|
6
|
+
|
|
7
|
+
# [1.7.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.6.0...v1.7.0) (2025-07-11)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- add send text message validation ([4f242ca](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/4f242caf92ec3cdab2ae5866d67abd6f1b5d864f))
|
|
12
|
+
|
|
1
13
|
# [1.6.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.5.0...v1.6.0) (2025-07-11)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "app-tutor-ai-consumer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "rspack serve --env=development --config config/rspack/rspack.config.js",
|
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
"react-dom": "~19.1.0",
|
|
122
122
|
"react-i18next": "~15.5.2",
|
|
123
123
|
"react-markdown": "~10.1.0",
|
|
124
|
+
"react-textarea-autosize": "~8.5.9",
|
|
124
125
|
"rehype-raw": "~7.0.0",
|
|
125
126
|
"rehype-sanitize": "~6.0.0",
|
|
126
127
|
"remark-breaks": "~4.0.0",
|
|
@@ -79,14 +79,15 @@
|
|
|
79
79
|
--ai-color-chat-response: #1e1926;
|
|
80
80
|
|
|
81
81
|
/* Size */
|
|
82
|
+
--hc-size-spacing-1: 0.25rem;
|
|
82
83
|
--hc-size-spacing-2: 0.5rem;
|
|
83
84
|
--hc-size-border-medium: 0.5rem;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
#hotmart-app-tutor-ai-consumer-root {
|
|
87
88
|
& *::-webkit-scrollbar {
|
|
88
|
-
width: var(--hc-size-spacing-2);
|
|
89
|
-
height: var(--hc-size-spacing-2);
|
|
89
|
+
width: var(--custom-scrollbar-width, var(--hc-size-spacing-2));
|
|
90
|
+
height: var(--custom-scrollbar-width, var(--hc-size-spacing-2));
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
& *::-webkit-scrollbar-track {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated file - DO NOT EDIT
|
|
2
|
-
export type ValidIconNames = 'ai-color' | 'arrow-down' | 'chevron-down' | 'send'
|
|
2
|
+
export type ValidIconNames = 'ai-color' | 'arrow-down' | 'chevron-down' | 'send' | 'stop'
|
|
@@ -8,7 +8,7 @@ import { useChatInputValueAtom } from './chat-input.atom'
|
|
|
8
8
|
vi.mock('./chat-input.atom', () => ({ useChatInputValueAtom: vi.fn() }))
|
|
9
9
|
|
|
10
10
|
describe('ChatInput', () => {
|
|
11
|
-
const ref = createRef<
|
|
11
|
+
const ref = createRef<HTMLTextAreaElement>()
|
|
12
12
|
const chatInputValueAtomMock = { val: '', setVal: vi.fn() }
|
|
13
13
|
const defaultProps = { name: chance.name() }
|
|
14
14
|
|
|
@@ -53,20 +53,24 @@ describe('ChatInput', () => {
|
|
|
53
53
|
expect(onSend).toHaveBeenCalledTimes(1)
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it('should disable the button when
|
|
57
|
-
renderComponent()
|
|
56
|
+
it('should disable the button when buttonDisabled prop is true', () => {
|
|
57
|
+
renderComponent({ buttonDisabled: true } as never)
|
|
58
58
|
|
|
59
59
|
expect(screen.getByRole('button', { name: /Submit Button/i })).toBeDisabled()
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
it('should the button
|
|
62
|
+
it('should enable the button when buttonDisabled prop is falsy', () => {
|
|
63
|
+
renderComponent()
|
|
64
|
+
|
|
65
|
+
expect(screen.getByRole('button', { name: /Submit Button/i })).toBeEnabled()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should set textarea value correctly', () => {
|
|
63
69
|
const name = chance.name()
|
|
64
70
|
vi.mocked(useChatInputValueAtom).mockReturnValue([name, vi.fn()])
|
|
65
71
|
|
|
66
72
|
renderComponent()
|
|
67
73
|
|
|
68
|
-
expect(ref.current?.
|
|
69
|
-
|
|
70
|
-
expect(screen.getByRole('button', { name: /Submit Button/i })).toBeEnabled()
|
|
74
|
+
expect(ref.current?.value).toBe(name)
|
|
71
75
|
})
|
|
72
76
|
})
|
|
@@ -2,77 +2,108 @@ import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'
|
|
|
2
2
|
import clsx from 'clsx'
|
|
3
3
|
import type { ChangeEvent, KeyboardEvent } from 'react'
|
|
4
4
|
import { useTranslation } from 'react-i18next'
|
|
5
|
+
import TextareaAutosize from 'react-textarea-autosize'
|
|
5
6
|
|
|
6
|
-
import { Icon } from '@/src/lib/components'
|
|
7
|
+
import { Icon, Spinner } from '@/src/lib/components'
|
|
7
8
|
|
|
8
9
|
import { useChatInputValueAtom } from './chat-input.atom'
|
|
9
10
|
import type { ChatInputProps } from './types'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
const { t } = useTranslation()
|
|
13
|
-
const [value, setValue] = useChatInputValueAtom()
|
|
14
|
-
const ref = useRef<HTMLInputElement>(null)
|
|
12
|
+
import styles from './styles.module.css'
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
const ChatInput = forwardRef<HTMLTextAreaElement, ChatInputProps>(
|
|
15
|
+
(
|
|
16
|
+
{ name, onSend, loading = false, inputDisabled = false, buttonDisabled = false },
|
|
17
|
+
forwardedRef
|
|
18
|
+
) => {
|
|
19
|
+
const { t } = useTranslation()
|
|
20
|
+
const [value, setValue] = useChatInputValueAtom()
|
|
21
|
+
const ref = useRef<HTMLTextAreaElement>(null)
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
setValue(e.target.value?.trim())
|
|
20
|
-
}
|
|
23
|
+
useImperativeHandle(forwardedRef, () => ref?.current as HTMLTextAreaElement)
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const isShiftKey = e.shiftKey
|
|
25
|
+
const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
|
26
|
+
if (inputDisabled) return
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
e.preventDefault()
|
|
28
|
-
onSend?.()
|
|
28
|
+
setValue(e.target.value)
|
|
29
29
|
}
|
|
30
|
-
}
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
32
|
+
if (loading || buttonDisabled) return
|
|
33
|
+
|
|
34
|
+
const isEnterKey = e.code === 'Enter'
|
|
35
|
+
const isShiftKey = e.shiftKey
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
if (isEnterKey && !isShiftKey) {
|
|
38
|
+
e.preventDefault()
|
|
39
|
+
onSend?.()
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
onClick={onSend}
|
|
55
|
-
disabled={!value}
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (inputDisabled) return
|
|
45
|
+
|
|
46
|
+
const input = ref?.current
|
|
47
|
+
|
|
48
|
+
if (input) {
|
|
49
|
+
input.focus()
|
|
50
|
+
|
|
51
|
+
const position = input.textLength ?? 0
|
|
52
|
+
input.setSelectionRange(position, position)
|
|
53
|
+
}
|
|
54
|
+
}, [inputDisabled])
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
56
58
|
className={clsx(
|
|
57
|
-
'flex
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'
|
|
70
|
-
|
|
59
|
+
'flex items-center rounded-full border border-neutral-800 bg-neutral-900 px-4 py-2',
|
|
60
|
+
{ 'cursor-not-allowed opacity-40': inputDisabled }
|
|
61
|
+
)}>
|
|
62
|
+
<TextareaAutosize
|
|
63
|
+
id={name}
|
|
64
|
+
name={name}
|
|
65
|
+
ref={ref}
|
|
66
|
+
className={clsx(
|
|
67
|
+
clsx(
|
|
68
|
+
'max-h-12 w-full resize-none border-none bg-transparent text-neutral-100 outline-none outline-0 placeholder:text-neutral-400',
|
|
69
|
+
styles.textArea
|
|
70
|
+
),
|
|
71
|
+
{ 'cursor-not-allowed': inputDisabled, 'opacity-40': inputDisabled || loading }
|
|
72
|
+
)}
|
|
73
|
+
placeholder={t('send_message.field.placeholder')}
|
|
74
|
+
value={value}
|
|
75
|
+
onChange={handleChange}
|
|
76
|
+
onKeyDown={handleKeyDown}
|
|
77
|
+
disabled={inputDisabled}
|
|
71
78
|
/>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
<button
|
|
80
|
+
onClick={onSend}
|
|
81
|
+
disabled={buttonDisabled || loading}
|
|
82
|
+
className={clsx(
|
|
83
|
+
'flex size-8 flex-col items-center justify-center rounded-full outline-none transition-colors duration-300 ease-in',
|
|
84
|
+
{
|
|
85
|
+
'cursor-pointer hover:scale-110 hover:bg-neutral-600 focus:bg-neutral-700 focus:outline-none focus:ring-1 focus:ring-neutral-500 focus:ring-offset-2':
|
|
86
|
+
!buttonDisabled,
|
|
87
|
+
'cursor-not-allowed': buttonDisabled
|
|
88
|
+
}
|
|
89
|
+
)}
|
|
90
|
+
aria-label='Submit Button'>
|
|
91
|
+
{loading ? (
|
|
92
|
+
<Spinner className='h-5 w-5 text-neutral-500' />
|
|
93
|
+
) : (
|
|
94
|
+
<Icon
|
|
95
|
+
name='send'
|
|
96
|
+
className={clsx('h-4 w-4 pr-0.5 pt-0.5 transition-colors duration-150', {
|
|
97
|
+
'text-neutral-50': !buttonDisabled,
|
|
98
|
+
'text-neutral-500': buttonDisabled
|
|
99
|
+
})}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
)
|
|
76
107
|
|
|
77
108
|
ChatInput.displayName = 'ChatInput'
|
|
78
109
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
2
|
|
|
3
3
|
import { isTextEmpty } from '@/src/lib/utils/is-text-empty'
|
|
4
|
-
import { ChatInput, MessagesList } from '@/src/modules/messages/components'
|
|
5
|
-
import { useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
6
|
-
import { useWidgetTabsValueAtom } from '../../store'
|
|
4
|
+
import { ChatInput, MessagesList, useChatInputValueAtom } from '@/src/modules/messages/components'
|
|
5
|
+
import { useAllMessages, useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
6
|
+
import { useWidgetLoadingAtomValue, useWidgetTabsValueAtom } from '../../store'
|
|
7
7
|
|
|
8
8
|
function ChatPage() {
|
|
9
9
|
const widgetTabs = useWidgetTabsValueAtom()
|
|
10
|
-
const chatInputRef = useRef<
|
|
10
|
+
const chatInputRef = useRef<HTMLTextAreaElement>(null)
|
|
11
11
|
const sendTextMessageMutation = useSendTextMessage()
|
|
12
|
+
const { messagesQuery } = useAllMessages()
|
|
13
|
+
const widgetLoading = useWidgetLoadingAtomValue()
|
|
14
|
+
const [value, setValue] = useChatInputValueAtom()
|
|
12
15
|
|
|
13
16
|
const handleSendMessage = () => {
|
|
14
17
|
const text = chatInputRef.current?.value ?? ''
|
|
@@ -18,6 +21,7 @@ function ChatPage() {
|
|
|
18
21
|
sendTextMessageMutation.mutate(text, {
|
|
19
22
|
onSuccess() {
|
|
20
23
|
if (chatInputRef.current?.value) chatInputRef.current.value = ''
|
|
24
|
+
setValue('')
|
|
21
25
|
}
|
|
22
26
|
})
|
|
23
27
|
}
|
|
@@ -30,6 +34,9 @@ function ChatPage() {
|
|
|
30
34
|
name='new-chat-msg-input'
|
|
31
35
|
ref={chatInputRef}
|
|
32
36
|
onSend={widgetTabs.currentTab === 'chat' ? handleSendMessage : undefined}
|
|
37
|
+
loading={widgetLoading || sendTextMessageMutation.isPending}
|
|
38
|
+
inputDisabled={messagesQuery?.isLoading}
|
|
39
|
+
buttonDisabled={messagesQuery?.isLoading || !value.trim()}
|
|
33
40
|
/>
|
|
34
41
|
</div>
|
|
35
42
|
</>
|
|
@@ -7,16 +7,16 @@ import { GreetingsCard } from '../greetings-card'
|
|
|
7
7
|
|
|
8
8
|
function WidgetStarterPage() {
|
|
9
9
|
const [settings] = useWidgetSettingsAtom()
|
|
10
|
-
const chatInputRef = useRef<
|
|
10
|
+
const chatInputRef = useRef<HTMLTextAreaElement>(null)
|
|
11
11
|
const [, setChatInputValue] = useChatInputValueAtom()
|
|
12
12
|
const [, setWidgetTabs] = useWidgetTabsAtom()
|
|
13
13
|
|
|
14
|
-
useRefEventListener<
|
|
14
|
+
useRefEventListener<HTMLTextAreaElement>({
|
|
15
15
|
config: {
|
|
16
16
|
ref: chatInputRef,
|
|
17
17
|
eventTypes: ['input', 'change'],
|
|
18
18
|
handler: (e) => {
|
|
19
|
-
const target = e.target as
|
|
19
|
+
const target = e.target as HTMLTextAreaElement
|
|
20
20
|
setChatInputValue(target.value)
|
|
21
21
|
}
|
|
22
22
|
}
|