app-tutor-ai-consumer 1.22.2 → 1.23.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 +9 -0
- package/package.json +1 -1
- package/src/lib/components/horizontal-draggable-scroll/horizontal-draggable-scroll.tsx +1 -0
- package/src/lib/components/icons/expand.svg +5 -0
- package/src/lib/components/icons/icon-names.d.ts +1 -0
- package/src/lib/components/tooltip/styles.module.css +3 -3
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.tsx +6 -1
- package/src/modules/widget/components/chat-page/chat-page.tsx +7 -1
- package/src/modules/widget/components/header/index.ts +1 -2
- package/src/modules/widget/components/header/{header.spec.tsx → widget-header.spec.tsx} +3 -3
- package/src/modules/widget/components/header/widget-header.tsx +150 -0
- package/src/modules/widget/components/information-page/information-page.tsx +26 -27
- package/src/modules/widget/components/page-layout/page-layout.tsx +3 -1
- package/src/modules/widget/components/starter-page/starter-page.tsx +3 -2
- package/src/modules/widget/events.ts +20 -2
- package/src/types.ts +8 -0
- package/src/modules/widget/components/header/header.tsx +0 -118
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
# [1.23.0](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.22.3...v1.23.0) (2025-08-11)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- add metadata properties to widget settings and component IDs to customize on agent page ([04c244d](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/04c244dcb4170665f6a216ce69c119e358118ef5))
|
|
6
|
+
- adding component id ([82b25ce](https://github.com/Hotmart-Org/app-tutor-ai-consumer/commit/82b25ce4a4974d3739dae09dc21928d5b3b78544))
|
|
7
|
+
|
|
8
|
+
## [1.22.3](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.22.2...v1.22.3) (2025-08-08)
|
|
9
|
+
|
|
1
10
|
## [1.22.2](https://github.com/Hotmart-Org/app-tutor-ai-consumer/compare/v1.22.1...v1.22.2) (2025-08-07)
|
|
2
11
|
|
|
3
12
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path
|
|
3
|
+
d="M11.3016 1.60522H8.62451V0.112061H13.8506V5.33813H12.3574V2.66105L9.15242 5.86604L8.0966 4.81022L11.3016 1.60522ZM0.412109 8.32446H1.90527V11.0016L5.11027 7.79655L6.16609 8.85237L2.9611 12.0574H5.63818V13.5505H0.412109V8.32446Z"
|
|
4
|
+
fill="currentColor" />
|
|
5
|
+
</svg>
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
.right:before {
|
|
24
24
|
top: 50%;
|
|
25
|
-
right:
|
|
25
|
+
right: 96%;
|
|
26
26
|
transform: translateY(-50%) rotateZ(-90deg);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
|
|
35
35
|
.left:before {
|
|
36
36
|
top: 50%;
|
|
37
|
-
left:
|
|
37
|
+
left: 96%;
|
|
38
38
|
transform: translateY(-50%) rotateZ(90deg);
|
|
39
|
-
}
|
|
39
|
+
}
|
|
@@ -71,7 +71,12 @@ function useSendTextMessage() {
|
|
|
71
71
|
router: questionParam ? 'summary' : undefined,
|
|
72
72
|
osVersion: browserInfo.version,
|
|
73
73
|
platformDetail: browserInfo.name,
|
|
74
|
-
ucode: settings.user?.ucode
|
|
74
|
+
ucode: settings.user?.ucode,
|
|
75
|
+
agentProductId: settings.config?.metadata?.agentProductId,
|
|
76
|
+
agentName: settings.config?.metadata?.agentName,
|
|
77
|
+
courseName: settings.config?.metadata?.courseName,
|
|
78
|
+
source: settings.config?.metadata?.source,
|
|
79
|
+
prompt: settings.config?.metadata?.promptId
|
|
75
80
|
},
|
|
76
81
|
externalId: v4(),
|
|
77
82
|
namespace: settings.namespace,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react'
|
|
2
2
|
import { useInfiniteQuery } from '@tanstack/react-query'
|
|
3
3
|
|
|
4
|
+
import { useMediaQuery } from '@/src/lib/hooks'
|
|
4
5
|
import { isTextEmpty } from '@/src/lib/utils/is-text-empty'
|
|
5
6
|
import { ChatInput, MessagesList, useChatInputValueAtom } from '@/src/modules/messages/components'
|
|
6
7
|
import { MessagesContainer } from '@/src/modules/messages/components/messages-container'
|
|
@@ -25,6 +26,7 @@ function ChatPage() {
|
|
|
25
26
|
const limit = useMessagesMaxCount()
|
|
26
27
|
const [value, setValue] = useChatInputValueAtom()
|
|
27
28
|
const [, setWidgetLoading] = useWidgetLoadingAtom()
|
|
29
|
+
const isMobile = useMediaQuery({ maxSize: 'md' })
|
|
28
30
|
|
|
29
31
|
const conversationId = useMemo(() => settings?.conversationId, [settings?.conversationId])
|
|
30
32
|
const profileId = useMemo(() => profileQuery.data?.id, [profileQuery.data?.id])
|
|
@@ -72,7 +74,11 @@ function ChatPage() {
|
|
|
72
74
|
/>
|
|
73
75
|
}>
|
|
74
76
|
<div className='max-md:px-[1.125rem] max-md:pt-[1.125rem] md:px-5 md:pt-5'>
|
|
75
|
-
<WidgetHeader
|
|
77
|
+
<WidgetHeader
|
|
78
|
+
enabledButtons={['info', 'close', 'arrow-left']}
|
|
79
|
+
tutorName={settings?.tutorName}
|
|
80
|
+
showContentWithoutMeta={!isMobile}
|
|
81
|
+
/>
|
|
76
82
|
</div>
|
|
77
83
|
<MessagesContainer
|
|
78
84
|
ref={scrollerRef}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { default as WidgetHeader } from './header'
|
|
1
|
+
export { default as WidgetHeader } from './widget-header'
|
|
@@ -2,7 +2,7 @@ import { render, screen } from '@/src/config/tests'
|
|
|
2
2
|
import * as Hooks from '@/src/lib/hooks'
|
|
3
3
|
|
|
4
4
|
import WidgetHeaderPropsBuilder from './__tests__/widget-header-props.builder'
|
|
5
|
-
import WidgetHeader from './header'
|
|
5
|
+
import WidgetHeader from './widget-header'
|
|
6
6
|
|
|
7
7
|
describe('<WidgetHeader />', () => {
|
|
8
8
|
const defaultProps = new WidgetHeaderPropsBuilder()
|
|
@@ -29,10 +29,10 @@ describe('<WidgetHeader />', () => {
|
|
|
29
29
|
expect(screen.queryByRole('button', { name: /Arrow Left Icon/i })).not.toBeInTheDocument()
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
it('should render WidgetHeaderContentWithoutMeta when prop showContentWithoutMeta is true
|
|
32
|
+
it('should render WidgetHeaderContentWithoutMeta when prop showContentWithoutMeta is true', () => {
|
|
33
33
|
const props = new WidgetHeaderPropsBuilder()
|
|
34
|
+
.withEnabledButtons(['close', 'arrow-left'])
|
|
34
35
|
.withShowContentWithoutMeta(true)
|
|
35
|
-
.withShowContent(false)
|
|
36
36
|
|
|
37
37
|
renderComponent(props)
|
|
38
38
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import { useTranslation } from 'react-i18next'
|
|
4
|
+
|
|
5
|
+
import { DataHubService } from '@/src/config/datahub'
|
|
6
|
+
import { ClickTutorMinimizeSchema } from '@/src/config/datahub/schemas/tutor'
|
|
7
|
+
import { Button, Icon, Tooltip } from '@/src/lib/components'
|
|
8
|
+
import { useMediaQuery } from '@/src/lib/hooks'
|
|
9
|
+
import { TutorWidgetEvents } from '../../events'
|
|
10
|
+
import { useWidgetGoBackTabAtom, useWidgetTabsAtom } from '../../store'
|
|
11
|
+
import { AIAvatar } from '../ai-avatar'
|
|
12
|
+
|
|
13
|
+
import type { WidgetHeaderProps } from './types'
|
|
14
|
+
|
|
15
|
+
import styles from './styles.module.css'
|
|
16
|
+
|
|
17
|
+
function WidgetHeaderActions({
|
|
18
|
+
actionButtons
|
|
19
|
+
}: {
|
|
20
|
+
actionButtons: ('archive' | 'expand' | 'info')[]
|
|
21
|
+
}) {
|
|
22
|
+
const { t } = useTranslation()
|
|
23
|
+
const [, setTab] = useWidgetTabsAtom()
|
|
24
|
+
const isMobile = useMediaQuery({ maxSize: 'md' })
|
|
25
|
+
|
|
26
|
+
const handleClickArchive = () => {
|
|
27
|
+
setTab('chat')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const handleClickInfo = () => {
|
|
31
|
+
setTab('information')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handleClickExpand = () => {
|
|
35
|
+
TutorWidgetEvents['tutor-app-widget-expand'].dispatch()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!(Number(actionButtons?.length) > 0)) return null
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<div
|
|
43
|
+
className={clsx('flex max-w-max items-center gap-3 text-neutral-700', styles.btnContainer)}>
|
|
44
|
+
{actionButtons.includes('archive') && (
|
|
45
|
+
<Tooltip show={!isMobile} content={t('general.buttons.archive')}>
|
|
46
|
+
<Button
|
|
47
|
+
show={actionButtons.includes('archive')}
|
|
48
|
+
onClick={handleClickArchive}
|
|
49
|
+
aria-label={t('general.buttons.archive') + ' Icon'}>
|
|
50
|
+
<Icon name='archive' className='h-4 w-4' aria-hidden />
|
|
51
|
+
</Button>
|
|
52
|
+
</Tooltip>
|
|
53
|
+
)}
|
|
54
|
+
{actionButtons.includes('info') && (
|
|
55
|
+
<Tooltip show={!isMobile} content={t('general.buttons.info')} position='left'>
|
|
56
|
+
<Button
|
|
57
|
+
show={actionButtons.includes('info')}
|
|
58
|
+
onClick={handleClickInfo}
|
|
59
|
+
aria-label={t('general.buttons.info') + ' Icon'}>
|
|
60
|
+
<Icon name='info' className='h-4 w-4' aria-hidden />
|
|
61
|
+
</Button>
|
|
62
|
+
</Tooltip>
|
|
63
|
+
)}
|
|
64
|
+
{actionButtons.includes('expand') && (
|
|
65
|
+
<Tooltip show={!isMobile} content={t('general.buttons.expand')} position='left'>
|
|
66
|
+
<Button
|
|
67
|
+
show={actionButtons.includes('expand')}
|
|
68
|
+
onClick={handleClickExpand}
|
|
69
|
+
aria-label={t('general.buttons.expand') + ' Icon'}>
|
|
70
|
+
<Icon name='expand' className='h-3.5 w-3.5' aria-hidden />
|
|
71
|
+
</Button>
|
|
72
|
+
</Tooltip>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
</>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function WidgetHeader({
|
|
80
|
+
enabledButtons = [],
|
|
81
|
+
tutorName,
|
|
82
|
+
showContentWithoutMeta,
|
|
83
|
+
showContent = true
|
|
84
|
+
}: WidgetHeaderProps) {
|
|
85
|
+
const { t } = useTranslation()
|
|
86
|
+
const [, goBack] = useWidgetGoBackTabAtom()
|
|
87
|
+
const name = tutorName ?? t('general.name')
|
|
88
|
+
|
|
89
|
+
const handleHideWidget = () => {
|
|
90
|
+
TutorWidgetEvents['c3po-app-widget-hide'].dispatch()
|
|
91
|
+
DataHubService.sendEvent({ schema: new ClickTutorMinimizeSchema() })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const actionButtons = useMemo(
|
|
95
|
+
() => enabledButtons.filter((btn) => btn === 'archive' || btn === 'info' || btn === 'expand'),
|
|
96
|
+
[enabledButtons]
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const hasToShowActions = useMemo(() => Number(actionButtons?.length) > 0, [actionButtons?.length])
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
id='tutor-ai-consumer-widget-header'
|
|
104
|
+
className='mb-4 mt-0.5 flex flex-col gap-2 text-neutral-900'>
|
|
105
|
+
<div className='flex justify-end'>
|
|
106
|
+
<div className={styles.closeContainer}>
|
|
107
|
+
<Button
|
|
108
|
+
className='text-neutral-500'
|
|
109
|
+
show={enabledButtons.includes('close')}
|
|
110
|
+
onClick={handleHideWidget}
|
|
111
|
+
aria-label='Close Icon'>
|
|
112
|
+
<Icon name='close' className='h-3 w-3' aria-hidden />
|
|
113
|
+
</Button>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
<div
|
|
117
|
+
className={clsx('grid items-center max-md:gap-2 md:gap-4', styles.btnContainer, {
|
|
118
|
+
'grid-cols-[auto_1fr_auto]': enabledButtons.includes('arrow-left'),
|
|
119
|
+
'grid-cols-[1fr_auto]': !enabledButtons.includes('arrow-left') && hasToShowActions,
|
|
120
|
+
'grid-cols-[1fr]': !enabledButtons.includes('arrow-left') && !hasToShowActions
|
|
121
|
+
})}>
|
|
122
|
+
{enabledButtons.includes('arrow-left') && (
|
|
123
|
+
<div>
|
|
124
|
+
<Button aria-label='Arrow Left Icon' onClick={goBack}>
|
|
125
|
+
<Icon name='arrow-left' className='h-3.5 w-3.5' aria-hidden />
|
|
126
|
+
</Button>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
<div
|
|
130
|
+
className={clsx('flex w-full items-center gap-2', {
|
|
131
|
+
'justify-center': showContentWithoutMeta
|
|
132
|
+
})}>
|
|
133
|
+
{showContent && (
|
|
134
|
+
<>
|
|
135
|
+
{!showContentWithoutMeta && <AIAvatar />}
|
|
136
|
+
{name && <h4 className='text-sm/loose font-bold'>{name}</h4>}
|
|
137
|
+
</>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
{hasToShowActions ? (
|
|
141
|
+
<WidgetHeaderActions actionButtons={actionButtons} />
|
|
142
|
+
) : (
|
|
143
|
+
<div className='h-6 w-6' />
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default WidgetHeader
|
|
@@ -16,40 +16,39 @@ function WidgetInformationPage() {
|
|
|
16
16
|
const tutorName = settings?.tutorName ?? t('general.name')
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<PageLayout className='flex min-h-0 flex-col text-neutral-900
|
|
20
|
-
<div className='
|
|
19
|
+
<PageLayout className='flex min-h-0 flex-col text-neutral-900'>
|
|
20
|
+
<div className='max-md:px-[1.125rem] max-md:py-[1.125rem] md:px-5 md:py-5'>
|
|
21
21
|
<WidgetHeader
|
|
22
|
-
enabledButtons={['close']}
|
|
23
|
-
showContent={false}
|
|
22
|
+
enabledButtons={['close', 'arrow-left']}
|
|
24
23
|
showContentWithoutMeta
|
|
25
24
|
tutorName={t('info.title')}
|
|
26
25
|
/>
|
|
27
|
-
</div>
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
<div className='my-8 flex justify-center'>
|
|
28
|
+
<div className='flex flex-col items-center gap-2'>
|
|
29
|
+
<AIAvatar size='lg' />
|
|
30
|
+
|
|
31
|
+
<h3
|
|
32
|
+
className={clsx('font-bold', {
|
|
33
|
+
'text-white': isDarkMode,
|
|
34
|
+
'text-neutral-700': !isDarkMode
|
|
35
|
+
})}>
|
|
36
|
+
{tutorName}
|
|
37
|
+
</h3>
|
|
38
|
+
</div>
|
|
40
39
|
</div>
|
|
41
|
-
</div>
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
<div className='flex flex-col gap-5'>
|
|
42
|
+
{infoItems({ tutorName: t('general.name') }).map((item) => (
|
|
43
|
+
<InformationCard
|
|
44
|
+
key={item.titleKey}
|
|
45
|
+
icon={item.icon}
|
|
46
|
+
title={t(item.titleKey)}
|
|
47
|
+
description={t(item.descKey)}
|
|
48
|
+
isDarkMode={isDarkMode}
|
|
49
|
+
/>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
53
52
|
</div>
|
|
54
53
|
</PageLayout>
|
|
55
54
|
)
|
|
@@ -23,7 +23,9 @@ function PageLayout({ asideChild, children, className }: PageLayoutProps) {
|
|
|
23
23
|
{children}
|
|
24
24
|
</div>
|
|
25
25
|
{asideChild && (
|
|
26
|
-
<div
|
|
26
|
+
<div
|
|
27
|
+
id='tutor-ai-consumer-page-layout-aside'
|
|
28
|
+
className='grid-area-[aside] flex-shrink-0 border-t border-t-neutral-300 px-5 py-4'>
|
|
27
29
|
{asideChild}
|
|
28
30
|
</div>
|
|
29
31
|
)}
|
|
@@ -4,7 +4,7 @@ import type { CSSProperties, MouseEventHandler } from 'react'
|
|
|
4
4
|
import { useTranslation } from 'react-i18next'
|
|
5
5
|
|
|
6
6
|
import { Button, HorizontalDraggableScroll } from '@/src/lib/components'
|
|
7
|
-
import { useRefEventListener } from '@/src/lib/hooks'
|
|
7
|
+
import { useMediaQuery, useRefEventListener } from '@/src/lib/hooks'
|
|
8
8
|
import { ChatInput, useChatInputValueAtom } from '@/src/modules/messages/components'
|
|
9
9
|
import { getAllMessagesQuery, useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
10
10
|
import { useMessagesMaxCount } from '@/src/modules/messages/store'
|
|
@@ -28,6 +28,7 @@ function WidgetStarterPage() {
|
|
|
28
28
|
const name = settings?.tutorName ?? t('general.name')
|
|
29
29
|
const isDarkTheme = settings?.config?.theme === 'dark'
|
|
30
30
|
const isSparkieReady = useInitSparkie()
|
|
31
|
+
const isMobile = useMediaQuery({ maxSize: 'md' })
|
|
31
32
|
|
|
32
33
|
useRefEventListener<HTMLTextAreaElement>({
|
|
33
34
|
config: {
|
|
@@ -104,7 +105,7 @@ function WidgetStarterPage() {
|
|
|
104
105
|
<div className='grid-area-[a] flex min-h-0 flex-col max-md:px-[1.125rem] max-md:pt-[1.125rem] md:px-5 md:pt-5'>
|
|
105
106
|
<WidgetHeader
|
|
106
107
|
enabledButtons={isSparkieReady ? ['close', 'archive', 'info'] : ['close', 'info']}
|
|
107
|
-
showContent={
|
|
108
|
+
showContent={isMobile}
|
|
108
109
|
tutorName={name}
|
|
109
110
|
/>
|
|
110
111
|
|
|
@@ -7,7 +7,8 @@ export const TutorWidgetEventTypes = {
|
|
|
7
7
|
CLOSE: 'c3po-app-widget-close',
|
|
8
8
|
HIDE: 'c3po-app-widget-hide',
|
|
9
9
|
LOADED: 'tutor-app-widget-loaded',
|
|
10
|
-
THEME_CHANGE: 'c3po-app-widget-theme-change'
|
|
10
|
+
THEME_CHANGE: 'c3po-app-widget-theme-change',
|
|
11
|
+
EXPAND: 'tutor-app-widget-expand'
|
|
11
12
|
} as const
|
|
12
13
|
|
|
13
14
|
export const TutorWidgetEvents = {
|
|
@@ -94,7 +95,24 @@ export const TutorWidgetEvents = {
|
|
|
94
95
|
dispatch: (payload) => {
|
|
95
96
|
window.dispatchEvent(new CustomEvent(TutorWidgetEventTypes.THEME_CHANGE, payload))
|
|
96
97
|
}
|
|
97
|
-
} as ITutorWidgetEvent<{ theme: Theme }
|
|
98
|
+
} as ITutorWidgetEvent<{ theme: Theme }>,
|
|
99
|
+
|
|
100
|
+
[TutorWidgetEventTypes.EXPAND]: {
|
|
101
|
+
name: TutorWidgetEventTypes.EXPAND,
|
|
102
|
+
handler: (callback: () => void) => {
|
|
103
|
+
const listener: EventListener = () => {
|
|
104
|
+
callback()
|
|
105
|
+
}
|
|
106
|
+
window.addEventListener(TutorWidgetEventTypes.EXPAND, listener)
|
|
107
|
+
|
|
108
|
+
return () => {
|
|
109
|
+
window.removeEventListener(TutorWidgetEventTypes.EXPAND, listener)
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
dispatch: (payload) => {
|
|
113
|
+
window.dispatchEvent(new CustomEvent(TutorWidgetEventTypes.EXPAND, payload))
|
|
114
|
+
}
|
|
115
|
+
} as ITutorWidgetEvent<void>
|
|
98
116
|
} as const
|
|
99
117
|
|
|
100
118
|
export const ACTION_EVENTS = {
|
package/src/types.ts
CHANGED
|
@@ -51,6 +51,14 @@ export type WidgetSettingProps = {
|
|
|
51
51
|
classType?: ClassTypes
|
|
52
52
|
config?: {
|
|
53
53
|
theme?: Theme
|
|
54
|
+
metadata?: {
|
|
55
|
+
parent?: 'AGENT' | 'TUTOR'
|
|
56
|
+
agentProductId?: number
|
|
57
|
+
agentName?: string
|
|
58
|
+
courseName?: string
|
|
59
|
+
source?: string
|
|
60
|
+
promptId?: string
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx'
|
|
2
|
-
import { useTranslation } from 'react-i18next'
|
|
3
|
-
|
|
4
|
-
import { DataHubService } from '@/src/config/datahub'
|
|
5
|
-
import { ClickTutorMinimizeSchema } from '@/src/config/datahub/schemas/tutor'
|
|
6
|
-
import { Button, Icon, Tooltip } from '@/src/lib/components'
|
|
7
|
-
import { useMediaQuery } from '@/src/lib/hooks'
|
|
8
|
-
import { TutorWidgetEvents } from '../../events'
|
|
9
|
-
import { useWidgetGoBackTabAtom, useWidgetTabsAtom } from '../../store'
|
|
10
|
-
import { AIAvatar } from '../ai-avatar'
|
|
11
|
-
|
|
12
|
-
import type { WidgetHeaderContentProps, WidgetHeaderProps } from './types'
|
|
13
|
-
|
|
14
|
-
import styles from './styles.module.css'
|
|
15
|
-
|
|
16
|
-
export function WidgetHeaderContent({ tutorName }: WidgetHeaderContentProps) {
|
|
17
|
-
return (
|
|
18
|
-
<div className='flex w-full gap-2'>
|
|
19
|
-
<AIAvatar />
|
|
20
|
-
<div className='flex flex-col justify-center'>
|
|
21
|
-
{tutorName && <h4 className='text-sm/loose font-bold'>{tutorName}</h4>}
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function WidgetHeaderContentWithoutMeta({ name }: { name?: string }) {
|
|
28
|
-
const { t } = useTranslation()
|
|
29
|
-
const [, goBack] = useWidgetGoBackTabAtom()
|
|
30
|
-
const tutorName = name ?? t('general.name')
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<div
|
|
34
|
-
className={clsx(
|
|
35
|
-
'grid-areas-[a_b] grid grid-cols-[auto_1fr] items-center gap-1',
|
|
36
|
-
styles.withoutMetaContainer
|
|
37
|
-
)}>
|
|
38
|
-
<Button className='grid-area-[a]' aria-label='Arrow Left Icon' onClick={goBack}>
|
|
39
|
-
<Icon name='arrow-left' className='h-3.5 w-3.5' aria-hidden />
|
|
40
|
-
</Button>
|
|
41
|
-
<div className='grid-area-[b] flex min-h-6 justify-center text-center'>
|
|
42
|
-
<span className='absolute bottom-0 left-1/2 -translate-x-1/2 text-base font-bold'>
|
|
43
|
-
{tutorName}
|
|
44
|
-
</span>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function WidgetHeader({
|
|
51
|
-
enabledButtons = [],
|
|
52
|
-
tutorName,
|
|
53
|
-
showContentWithoutMeta,
|
|
54
|
-
showContent = true
|
|
55
|
-
}: WidgetHeaderProps) {
|
|
56
|
-
const { t } = useTranslation()
|
|
57
|
-
const [, setTab] = useWidgetTabsAtom()
|
|
58
|
-
const name = tutorName ?? t('general.name')
|
|
59
|
-
const isMobile = useMediaQuery({ maxSize: 'md' })
|
|
60
|
-
|
|
61
|
-
const handleClickArchive = () => {
|
|
62
|
-
setTab('chat')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const handleClickInfo = () => {
|
|
66
|
-
setTab('information')
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const handleHideWidget = () => {
|
|
70
|
-
TutorWidgetEvents['c3po-app-widget-hide'].dispatch()
|
|
71
|
-
DataHubService.sendEvent({ schema: new ClickTutorMinimizeSchema() })
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
<div className='mt-0.5 flex flex-col gap-2 text-neutral-900'>
|
|
76
|
-
<div className='flex justify-end'>
|
|
77
|
-
<div className={styles.closeContainer}>
|
|
78
|
-
<Button
|
|
79
|
-
className='text-neutral-500'
|
|
80
|
-
show={enabledButtons.includes('close')}
|
|
81
|
-
onClick={handleHideWidget}
|
|
82
|
-
aria-label='Close Icon'>
|
|
83
|
-
<Icon name='close' className='h-3 w-3' aria-hidden />
|
|
84
|
-
</Button>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
<div className='grid-areas-[a_b] grid grid-cols-[1fr_auto] items-center pb-4'>
|
|
88
|
-
<div className='grid-area-[a] relative'>
|
|
89
|
-
{showContent && !showContentWithoutMeta && <WidgetHeaderContent tutorName={name} />}
|
|
90
|
-
{showContentWithoutMeta && !showContent && <WidgetHeaderContentWithoutMeta name={name} />}
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
<div className='grid-area-[b] ml-auto shrink-0'>
|
|
94
|
-
<div className={clsx('flex max-w-max gap-3 text-neutral-700', styles.btnContainer)}>
|
|
95
|
-
<Tooltip show={!isMobile} content={t('general.buttons.archive')}>
|
|
96
|
-
<Button
|
|
97
|
-
show={enabledButtons.includes('archive')}
|
|
98
|
-
onClick={handleClickArchive}
|
|
99
|
-
aria-label={t('general.buttons.archive') + ' Icon'}>
|
|
100
|
-
<Icon name='archive' className='h-4 w-4' aria-hidden />
|
|
101
|
-
</Button>
|
|
102
|
-
</Tooltip>
|
|
103
|
-
<Tooltip show={!isMobile} content={t('general.buttons.info')} position='left'>
|
|
104
|
-
<Button
|
|
105
|
-
show={enabledButtons.includes('info')}
|
|
106
|
-
onClick={handleClickInfo}
|
|
107
|
-
aria-label={t('general.buttons.info') + ' Icon'}>
|
|
108
|
-
<Icon name='info' className='h-4 w-4' aria-hidden />
|
|
109
|
-
</Button>
|
|
110
|
-
</Tooltip>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export default WidgetHeader
|