app-tutor-ai-consumer 1.4.0 → 1.6.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/staging-staging.yml +148 -0
- package/.github/workflows/staging.yml +1 -2
- package/CHANGELOG.md +19 -0
- package/config/rspack/rspack.config.js +5 -1
- package/config/vitest/__mocks__/icons.tsx +3 -0
- package/config/vitest/__mocks__/intersection-observer.ts +10 -0
- package/config/vitest/__mocks__/sparkie.tsx +9 -9
- package/config/vitest/__mocks__/use-init-sparkie.tsx +14 -0
- package/config/vitest/vitest.config.mts +13 -8
- package/environments/.env.test +2 -0
- package/eslint.config.mjs +27 -0
- package/package.json +8 -4
- package/public/index.html +3 -4
- package/src/@types/index.d.ts +5 -2
- package/src/config/styles/global.css +2 -2
- package/src/config/tanstack/query-client.ts +3 -2
- package/src/config/tests/utils.tsx +3 -2
- package/src/config/tests/wrappers.tsx +4 -1
- package/src/development-bootstrap.tsx +15 -15
- package/src/index.tsx +37 -5
- package/src/lib/components/icons/ai-color.svg +17 -0
- package/src/lib/components/icons/arrow-down.svg +5 -0
- package/src/lib/components/icons/chevron-down.svg +4 -0
- package/src/lib/components/icons/icon-names.d.ts +1 -1
- package/src/lib/components/markdownrenderer/markdownrenderer.tsx +7 -9
- package/src/lib/hooks/index.ts +3 -0
- package/src/lib/hooks/use-intersection-observer-reverse-scroll/index.ts +2 -0
- package/src/lib/hooks/use-intersection-observer-reverse-scroll/use-intersection-observer-reverse-scroll.tsx +147 -0
- package/src/lib/hooks/use-ref-client-height/index.ts +2 -0
- package/src/lib/hooks/use-ref-client-height/use-ref-client-height.tsx +38 -0
- package/src/lib/hooks/use-scroll-to-ref/index.ts +2 -0
- package/src/lib/hooks/use-scroll-to-ref/use-scroll-to-ref.tsx +14 -0
- package/src/lib/hooks/use-throttle/index.ts +3 -0
- package/src/lib/hooks/use-throttle/types.ts +13 -0
- package/src/lib/hooks/use-throttle/use-throttle.spec.tsx +296 -0
- package/src/lib/hooks/use-throttle/use-throttle.tsx +91 -0
- package/src/lib/utils/is-text-empty.ts +3 -0
- package/src/main/main.spec.tsx +7 -6
- package/src/modules/cursor/__tests__/icursor-update.builder.ts +42 -0
- package/src/modules/cursor/hooks/index.ts +1 -0
- package/src/modules/cursor/hooks/use-update-cursor/index.ts +2 -0
- package/src/modules/cursor/hooks/use-update-cursor/use-update-cursor.spec.tsx +23 -0
- package/src/modules/cursor/hooks/use-update-cursor/use-update-cursor.ts +11 -0
- package/src/modules/cursor/index.ts +2 -0
- package/src/modules/cursor/service.ts +15 -0
- package/src/modules/cursor/types.ts +9 -0
- package/src/modules/global-providers/index.ts +1 -0
- package/src/modules/messages/__tests__/parsed-message.builder.ts +164 -0
- package/src/modules/messages/components/chat-input/chat-input.spec.tsx +72 -0
- package/src/modules/messages/components/chat-input/chat-input.tsx +52 -6
- package/src/modules/messages/components/index.ts +1 -0
- package/src/modules/messages/components/message-item/message-item.spec.tsx +2 -2
- package/src/modules/messages/components/message-item/message-item.tsx +14 -1
- package/src/modules/messages/components/message-item-end-of-scroll/index.ts +2 -0
- package/src/modules/messages/components/message-item-end-of-scroll/message-item-end-of-scroll.tsx +14 -0
- package/src/modules/messages/components/message-item-error/index.ts +2 -0
- package/src/modules/messages/components/message-item-error/message-item-error.tsx +25 -0
- package/src/modules/messages/components/message-item-loading/index.ts +2 -0
- package/src/modules/messages/components/message-item-loading/message-item-loading.tsx +16 -0
- package/src/modules/messages/components/message-skeleton/index.ts +1 -0
- package/src/modules/messages/components/message-skeleton/message-skeleton.tsx +23 -0
- package/src/modules/messages/components/messages-list/index.ts +1 -1
- package/src/modules/messages/components/messages-list/messages-list.tsx +82 -39
- package/src/modules/messages/constants.ts +1 -0
- package/src/modules/messages/hooks/index.ts +5 -0
- package/src/modules/messages/hooks/use-all-messages/index.ts +2 -0
- package/src/modules/messages/hooks/use-all-messages/use-all-messages.tsx +30 -0
- package/src/modules/messages/hooks/use-infinite-get-messages/index.ts +2 -0
- package/src/modules/messages/hooks/use-infinite-get-messages/use-infinite-get-messages.spec.tsx +65 -0
- package/src/modules/messages/hooks/use-infinite-get-messages/use-infinite-get-messages.tsx +81 -0
- package/src/modules/messages/hooks/use-manage-scroll/index.ts +2 -0
- package/src/modules/messages/hooks/use-manage-scroll/use-manage-scroll.tsx +70 -0
- package/src/modules/messages/hooks/use-send-text-message/index.ts +2 -0
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.spec.tsx +86 -0
- package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.tsx +60 -0
- package/src/modules/messages/hooks/use-skeleton-ref/index.ts +2 -0
- package/src/modules/messages/hooks/use-skeleton-ref/use-skeleton-ref.tsx +34 -0
- package/src/modules/messages/hooks/use-subscribe-message-received-event/index.ts +2 -0
- package/src/modules/messages/hooks/use-subscribe-message-received-event/use-subscribe-message-received-event.tsx +80 -0
- package/src/modules/messages/service.ts +8 -7
- package/src/modules/messages/utils/has-to-update-cursor/has-to-update-cursor.spec.tsx +58 -0
- package/src/modules/messages/utils/has-to-update-cursor/has-to-update-cursor.ts +30 -0
- package/src/modules/messages/utils/has-to-update-cursor/index.ts +2 -0
- package/src/modules/sparkie/__tests__/sparkie.mock.ts +33 -0
- package/src/modules/sparkie/service.ts +182 -35
- package/src/modules/sparkie/types.ts +10 -2
- package/src/modules/widget/__tests__/widget-settings-props.builder.ts +29 -1
- package/src/modules/widget/components/ai-avatar/ai-avatar.tsx +11 -53
- package/src/modules/widget/components/chat-page/chat-page.spec.tsx +28 -0
- package/src/modules/widget/components/chat-page/chat-page.tsx +23 -4
- package/src/modules/widget/components/container/container.tsx +5 -19
- package/src/modules/widget/components/index.ts +1 -0
- package/src/modules/widget/components/scroll-to-bottom-button/index.ts +2 -0
- package/src/modules/widget/components/scroll-to-bottom-button/scroll-to-bottom-button.tsx +32 -0
- package/src/modules/widget/events.ts +4 -0
- package/src/modules/widget/hooks/use-init-sparkie/use-init-sparkie.tsx +8 -6
- package/src/modules/widget/store/index.ts +3 -0
- package/src/modules/widget/store/widget-container-intrinsic-height.atom.ts +13 -0
- package/src/modules/widget/store/widget-loading.atom.ts +11 -0
- package/src/modules/widget/store/widget-scrolling.atom.ts +11 -0
- package/src/modules/widget/store/widget-tabs.atom.ts +2 -1
- package/src/types.ts +4 -1
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
2
|
|
|
3
|
+
import { isTextEmpty } from '@/src/lib/utils/is-text-empty'
|
|
3
4
|
import { ChatInput, MessagesList } from '@/src/modules/messages/components'
|
|
5
|
+
import { useSendTextMessage } from '@/src/modules/messages/hooks'
|
|
6
|
+
import { useWidgetTabsValueAtom } from '../../store'
|
|
4
7
|
|
|
5
8
|
function ChatPage() {
|
|
9
|
+
const widgetTabs = useWidgetTabsValueAtom()
|
|
6
10
|
const chatInputRef = useRef<HTMLInputElement>(null)
|
|
11
|
+
const sendTextMessageMutation = useSendTextMessage()
|
|
12
|
+
|
|
13
|
+
const handleSendMessage = () => {
|
|
14
|
+
const text = chatInputRef.current?.value ?? ''
|
|
15
|
+
|
|
16
|
+
if (!isTextEmpty(text)) return
|
|
17
|
+
|
|
18
|
+
sendTextMessageMutation.mutate(text, {
|
|
19
|
+
onSuccess() {
|
|
20
|
+
if (chatInputRef.current?.value) chatInputRef.current.value = ''
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
}
|
|
7
24
|
|
|
8
25
|
return (
|
|
9
26
|
<>
|
|
10
|
-
<
|
|
11
|
-
<MessagesList />
|
|
12
|
-
</div>
|
|
27
|
+
<MessagesList />
|
|
13
28
|
<div className='border-t border-t-neutral-700 px-5 py-4'>
|
|
14
|
-
<ChatInput
|
|
29
|
+
<ChatInput
|
|
30
|
+
name='new-chat-msg-input'
|
|
31
|
+
ref={chatInputRef}
|
|
32
|
+
onSend={widgetTabs.currentTab === 'chat' ? handleSendMessage : undefined}
|
|
33
|
+
/>
|
|
15
34
|
</div>
|
|
16
35
|
</>
|
|
17
36
|
)
|
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { getInitSparkieQuery } from '../../hooks'
|
|
5
|
-
import { useWidgetSettingsAtom, useWidgetTabsAtom } from '../../store'
|
|
1
|
+
import { useSubscribeMessageReceivedEvent } from '@/src/modules/messages/hooks'
|
|
2
|
+
import { useWidgetTabsValueAtom } from '../../store'
|
|
6
3
|
import { WIDGET_TABS } from '../constants'
|
|
7
4
|
|
|
8
5
|
function WidgetContainer() {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const queryClient = useQueryClient()
|
|
12
|
-
const [widgetTabs] = useWidgetTabsAtom()
|
|
13
|
-
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
if (!initSparkieQuery) return
|
|
16
|
-
void (async () => {
|
|
17
|
-
await queryClient.prefetchQuery(initSparkieQuery)
|
|
18
|
-
})()
|
|
19
|
-
}, [initSparkieQuery, queryClient])
|
|
20
|
-
|
|
21
|
-
if (!settings?.tutorName) return null
|
|
6
|
+
const widgetTabs = useWidgetTabsValueAtom()
|
|
7
|
+
useSubscribeMessageReceivedEvent()
|
|
22
8
|
|
|
23
9
|
return (
|
|
24
|
-
<div className='flex min-h-svh flex-col items-center justify-center
|
|
10
|
+
<div className='flex min-h-svh flex-col items-center justify-center'>
|
|
25
11
|
<div className='grid h-svh w-full grid-rows-[1fr_max-content]'>
|
|
26
12
|
{WIDGET_TABS[widgetTabs.currentTab]}
|
|
27
13
|
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type DetailedHTMLProps, forwardRef } from 'react'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
|
|
4
|
+
import { Icon } from '@/src/lib/components'
|
|
5
|
+
|
|
6
|
+
export interface IScrollToBottomButtonProps
|
|
7
|
+
extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
|
8
|
+
show?: boolean
|
|
9
|
+
top?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ScrollToBottomButton = forwardRef<HTMLButtonElement, IScrollToBottomButtonProps>(
|
|
13
|
+
({ show = false, top = 0, onClick, className, ...props }, ref) => (
|
|
14
|
+
<button
|
|
15
|
+
{...props}
|
|
16
|
+
style={isNaN(Number(top)) ? undefined : { top }}
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={clsx(
|
|
19
|
+
'fixed inset-x-1/2 flex size-7 cursor-pointer flex-col items-center justify-center rounded-full bg-neutral-600 text-sm text-neutral-50 outline-none transition-colors duration-300 ease-in hover:scale-110 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-neutral-500 focus:ring-offset-2',
|
|
20
|
+
{ 'pointer-events-none opacity-0': !show },
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
onClick={onClick}
|
|
24
|
+
aria-label='Scroller Button'>
|
|
25
|
+
<Icon name='arrow-down' className='size-4' aria-label='Scroller Button Icon' />
|
|
26
|
+
</button>
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
ScrollToBottomButton.displayName = 'ScrollToBottomButton'
|
|
31
|
+
|
|
32
|
+
export default ScrollToBottomButton
|
|
@@ -4,15 +4,17 @@ import { SparkieService } from '@/src/modules/sparkie'
|
|
|
4
4
|
import type { WidgetSettingProps } from '@/src/types'
|
|
5
5
|
|
|
6
6
|
export const getInitSparkieQuery = (settings: WidgetSettingProps) => ({
|
|
7
|
-
queryKey: ['SparkieService:initializeSparkie', settings
|
|
7
|
+
queryKey: ['SparkieService:initializeSparkie', settings?.hotmartToken ?? ''],
|
|
8
8
|
queryFn: () =>
|
|
9
9
|
SparkieService.initSparkie({
|
|
10
|
-
token: settings
|
|
10
|
+
token: settings?.hotmartToken,
|
|
11
11
|
skipPresenceSetup: true
|
|
12
|
-
})
|
|
13
|
-
enabled: Boolean(settings?.hotmartToken?.trim())
|
|
12
|
+
})
|
|
14
13
|
})
|
|
15
14
|
|
|
16
|
-
export function useInitSparkie(settings: WidgetSettingProps) {
|
|
17
|
-
return useQuery(
|
|
15
|
+
export function useInitSparkie(settings: WidgetSettingProps | null) {
|
|
16
|
+
return useQuery({
|
|
17
|
+
...getInitSparkieQuery(settings as WidgetSettingProps),
|
|
18
|
+
enabled: Boolean(settings?.hotmartToken?.trim())
|
|
19
|
+
})
|
|
18
20
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { atom, useAtom, useAtomValue } from 'jotai'
|
|
2
|
+
|
|
3
|
+
const intrinsicHeightAtom = atom('100svh')
|
|
4
|
+
const setIntrinsicHeightAtom = atom(
|
|
5
|
+
(get) => get(intrinsicHeightAtom),
|
|
6
|
+
(_, set, value: string) => {
|
|
7
|
+
set(intrinsicHeightAtom, value)
|
|
8
|
+
}
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
export const useIntrinsicHeightAtom = () => useAtom(setIntrinsicHeightAtom)
|
|
12
|
+
|
|
13
|
+
export const useIntrinsicHeightAtomValue = () => useAtomValue(intrinsicHeightAtom)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { atom, useAtom, useAtomValue } from 'jotai'
|
|
2
|
+
|
|
3
|
+
const widgetLoadingAtom = atom<boolean>(false)
|
|
4
|
+
|
|
5
|
+
const setWidgetLoadingAtom = atom(
|
|
6
|
+
(get) => get(widgetLoadingAtom),
|
|
7
|
+
(_, set, isLoading: boolean) => set(widgetLoadingAtom, isLoading)
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
export const useWidgetLoadingAtom = () => useAtom(setWidgetLoadingAtom)
|
|
11
|
+
export const useWidgetLoadingAtomValue = () => useAtomValue(setWidgetLoadingAtom)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { atom, useAtom, useAtomValue } from 'jotai'
|
|
2
|
+
|
|
3
|
+
const widgetScrollingAtom = atom<boolean>(false)
|
|
4
|
+
|
|
5
|
+
const setWidgetScrollingAtom = atom(
|
|
6
|
+
(get) => get(widgetScrollingAtom),
|
|
7
|
+
(_, set, isScrolling: boolean) => set(widgetScrollingAtom, isScrolling)
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
export const useWidgetScrollingAtom = () => useAtom(setWidgetScrollingAtom)
|
|
11
|
+
export const useWidgetScrollingAtomValue = () => useAtomValue(setWidgetScrollingAtom)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { atom, useAtom } from 'jotai'
|
|
1
|
+
import { atom, useAtom, useAtomValue } from 'jotai'
|
|
2
2
|
|
|
3
3
|
import type { CurrentTabKey } from '../components'
|
|
4
4
|
|
|
@@ -50,4 +50,5 @@ export const goBackTabAtom = atom(null, (get, set) => {
|
|
|
50
50
|
|
|
51
51
|
export const useGetWidgetTabsAtom = () => useAtom(widgetTabsAtom)
|
|
52
52
|
export const useWidgetTabsAtom = () => useAtom(setWidgetTabsAtom)
|
|
53
|
+
export const useWidgetTabsValueAtom = () => useAtomValue(setWidgetTabsAtom)
|
|
53
54
|
export const useWidgetGoBackTabAton = () => useAtom(goBackTabAtom)
|
package/src/types.ts
CHANGED
|
@@ -26,10 +26,13 @@ export type WidgetSettingProps = {
|
|
|
26
26
|
namespace?: string
|
|
27
27
|
productId: number
|
|
28
28
|
productName: string
|
|
29
|
-
sessionId
|
|
29
|
+
sessionId: string
|
|
30
30
|
membershipId?: string
|
|
31
31
|
membershipSlug?: string
|
|
32
32
|
userId?: string
|
|
33
33
|
tutorName?: string
|
|
34
34
|
user?: User
|
|
35
|
+
classHashId?: string
|
|
36
|
+
owner_id?: string
|
|
37
|
+
current_media_codes?: string
|
|
35
38
|
}
|