app-tutor-ai-consumer 1.24.3 → 1.25.1

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,19 @@
1
+ ## [1.25.1](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.25.0...v1.25.1) (2025-08-12)
2
+
3
+ ### Bug Fixes
4
+
5
+ - qa issues part 2 ([203cb3c](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/203cb3c87d0abbdc6024e53c27ff3f91294a0bdb))
6
+
7
+ # [1.25.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.24.3...v1.25.0) (2025-08-12)
8
+
9
+ ### Bug Fixes
10
+
11
+ - cr issues ([ec25121](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/ec25121f4271f305c4b288586fcba125fa4f77e6))
12
+
13
+ ### Features
14
+
15
+ - add Tutor voice messages support ([3024d7c](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/3024d7c74bb8e07593f28d4b5b554f0d5d6495d1))
16
+
1
17
  ## [1.24.3](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.24.2...v1.24.3) (2025-08-12)
2
18
 
3
19
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "app-tutor-ai-consumer",
3
- "version": "1.24.3",
3
+ "version": "1.25.1",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "dev": "rspack serve --env=development --config config/rspack/rspack.config.js",
@@ -24,3 +24,4 @@ export type ValidIconNames =
24
24
  | 'sparkle-tutor'
25
25
  | 'stop'
26
26
  | 'warning'
27
+ | 'waveforms'
@@ -0,0 +1,6 @@
1
+ <svg aria-hidden="true" focusable="false"
2
+ role="img" xmlns="http://www.w3.org/2000/svg"
3
+ viewBox="0 0 640 512">
4
+ <path fill="currentColor"
5
+ d="M328 0h-16a16 16 0 0 0-16 16v480a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16V16a16 16 0 0 0-16-16zm-96 96h-16a16 16 0 0 0-16 16v288a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16V112a16 16 0 0 0-16-16zm192 32h-16a16 16 0 0 0-16 16v224a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16V144a16 16 0 0 0-16-16zm96-64h-16a16 16 0 0 0-16 16v352a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zM136 192h-16a16 16 0 0 0-16 16v96a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16v-96a16 16 0 0 0-16-16zm-96 32H24a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm576 0h-16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h16a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"></path>
6
+ </svg>
@@ -21,12 +21,6 @@ describe('ChatInput', () => {
21
21
  ])
22
22
  })
23
23
 
24
- it('should call focus when rendering the input', () => {
25
- renderComponent()
26
-
27
- expect(ref.current).toHaveFocus()
28
- })
29
-
30
24
  it('should call setValue when ref change event is called', () => {
31
25
  renderComponent()
32
26
 
@@ -1,4 +1,4 @@
1
- import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef } from 'react'
1
+ import { forwardRef, 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'
@@ -40,25 +40,6 @@ const ChatInput = forwardRef<HTMLTextAreaElement, ChatInputProps>(
40
40
  }
41
41
  }
42
42
 
43
- const setInputFocus = useCallback(() => {
44
- if (inputDisabled) return
45
-
46
- const input = ref?.current
47
-
48
- if (input === document.activeElement) return
49
-
50
- if (input) {
51
- input.focus()
52
-
53
- const position = input.textLength ?? 0
54
- input.setSelectionRange(position, position)
55
- }
56
- }, [inputDisabled])
57
-
58
- useEffect(() => {
59
- setInputFocus()
60
- }, [setInputFocus])
61
-
62
43
  return (
63
44
  <div
64
45
  className={clsx(
@@ -0,0 +1,2 @@
1
+ export * from './message-content-type-renderer'
2
+ export { default as MessageContentTypeRenderer } from './message-content-type-renderer'
@@ -0,0 +1,47 @@
1
+ import { useTranslation } from 'react-i18next'
2
+ import type { Components } from 'react-markdown'
3
+
4
+ import { Icon, MarkdownRenderer } from '@/src/lib/components'
5
+ import type { ParsedMessage } from '../../types'
6
+ import { MessageImg } from '../message-img'
7
+
8
+ export const imgComponent: Components['img'] = ({ src }) => {
9
+ return <MessageImg message={{ thumbnails: {}, url: src, dimensions: {} } as ParsedMessage} />
10
+ }
11
+
12
+ export function MediaVoiceMessage() {
13
+ const { t } = useTranslation()
14
+ return (
15
+ <div className='flex items-center gap-2 py-3 text-xs/normal'>
16
+ <Icon name='waveforms' className='inline-flex h-4 w-4 shrink-0' />
17
+ <span>{t('chat_page.messages.audio')}</span>
18
+ </div>
19
+ )
20
+ }
21
+
22
+ export function TextMessage({ message }: { message: ParsedMessage }) {
23
+ return (
24
+ <MarkdownRenderer
25
+ content={message?.text ?? message?.name}
26
+ imgComponent={imgComponent}
27
+ className='w-full'
28
+ />
29
+ )
30
+ }
31
+
32
+ function MessageContentTypeRenderer({ message }: { message: ParsedMessage }) {
33
+ const messageFromAi = message.metadata.author === 'ai'
34
+ const messageType = message.type
35
+ const isMediaVoice = messageType === 'media/voice'
36
+
37
+ if (messageFromAi && isMediaVoice) return null
38
+
39
+ switch (message.type) {
40
+ case 'media/voice':
41
+ return <MediaVoiceMessage />
42
+ default:
43
+ return <TextMessage message={message} />
44
+ }
45
+ }
46
+
47
+ export default MessageContentTypeRenderer
@@ -1,18 +1,13 @@
1
1
  import clsx from 'clsx'
2
- import type { Components } from 'react-markdown'
3
2
 
4
- import { MarkdownRenderer } from '@/src/lib/components'
5
3
  import type { ParsedMessage } from '../../types'
6
4
  import { MessageActions } from '../message-actions'
7
- import { MessageImg } from '../message-img'
8
-
9
- const imgComponent: Components['img'] = ({ src }) => {
10
- return <MessageImg message={{ thumbnails: {}, url: src, dimensions: {} } as ParsedMessage} />
11
- }
5
+ import { MessageContentTypeRenderer } from '../message-content-type-renderer'
12
6
 
13
7
  function MessageItem({ message }: { message: ParsedMessage }) {
14
8
  const messageFromUser = message.metadata.author === 'user'
15
9
  const messageFromAi = message.metadata.author === 'ai'
10
+ const isMediaVoice = message.type === 'media/voice'
16
11
 
17
12
  return (
18
13
  <div
@@ -28,19 +23,17 @@ function MessageItem({ message }: { message: ParsedMessage }) {
28
23
  'max-w-max bg-[rgb(from_var(--hc-color-neutral-300)_r_g_b_/_0.8)]': messageFromUser,
29
24
  'bg-neutral-200': messageFromAi
30
25
  })}>
31
- <MarkdownRenderer
32
- content={message?.text ?? message?.name}
33
- imgComponent={imgComponent}
34
- className='w-full'
35
- />
26
+ <MessageContentTypeRenderer message={message} />
36
27
  </div>
37
- <MessageActions
38
- className={clsx('flex items-center justify-between gap-2', {
39
- 'w-full': messageFromAi
40
- })}
41
- message={message}
42
- showActions={messageFromAi}
43
- />
28
+ {messageFromAi && isMediaVoice ? null : (
29
+ <MessageActions
30
+ className={clsx('flex items-center justify-between gap-2', {
31
+ 'w-full': messageFromAi
32
+ })}
33
+ message={message}
34
+ showActions={messageFromAi}
35
+ />
36
+ )}
44
37
  </div>
45
38
  )
46
39
  }
@@ -66,7 +66,7 @@ const MessagesContainer = forwardRef<HTMLDivElement, MessagesContainerProps>(
66
66
  className='flex h-full flex-col gap-2 overflow-auto max-md:p-[1.125rem] md:p-5'>
67
67
  <div className='mb-auto flex-1 self-center'>
68
68
  <Button
69
- className='max-w-max rounded-full border border-neutral-300 bg-neutral-200 px-2 py-1 text-xs/normal tracking-wide text-neutral-900'
69
+ className='max-w-max rounded-full border border-neutral-300 bg-neutral-200 px-2 py-1 text-xs/normal tracking-wide text-neutral-900 hover:text-neutral-900 focus:text-neutral-900 active:text-neutral-900'
70
70
  onClick={handleClickShowMore}
71
71
  loading={loading}
72
72
  show={showButton}>