app-tutor-ai-consumer 1.24.3 → 1.25.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,13 @@
1
+ # [1.25.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.24.3...v1.25.0) (2025-08-12)
2
+
3
+ ### Bug Fixes
4
+
5
+ - cr issues ([ec25121](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/ec25121f4271f305c4b288586fcba125fa4f77e6))
6
+
7
+ ### Features
8
+
9
+ - add Tutor voice messages support ([3024d7c](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/3024d7c74bb8e07593f28d4b5b554f0d5d6495d1))
10
+
1
11
  ## [1.24.3](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.24.2...v1.24.3) (2025-08-12)
2
12
 
3
13
  ### 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.0",
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>
@@ -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}>