app-tutor-ai-consumer 1.18.1 → 1.19.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +1 -1
  3. package/src/config/tests/handlers.ts +12 -0
  4. package/src/development-bootstrap.tsx +5 -2
  5. package/src/index.tsx +3 -0
  6. package/src/lib/components/button/button.tsx +105 -14
  7. package/src/lib/components/button/styles.module.css +9 -0
  8. package/src/lib/components/icons/arrow-up.svg +5 -0
  9. package/src/lib/components/icons/copy.svg +5 -0
  10. package/src/lib/components/icons/gallery.svg +3 -0
  11. package/src/lib/components/icons/icon-names.d.ts +4 -1
  12. package/src/lib/components/icons/interrogation.svg +2 -8
  13. package/src/lib/components/icons/like.svg +5 -0
  14. package/src/modules/messages/components/message-actions/index.ts +2 -0
  15. package/src/modules/messages/components/message-actions/message-actions.tsx +49 -0
  16. package/src/modules/messages/components/message-item/message-item.tsx +21 -5
  17. package/src/modules/messages/components/message-item-error/message-item-error.tsx +16 -9
  18. package/src/modules/messages/components/message-skeleton/message-skeleton.tsx +1 -4
  19. package/src/modules/messages/components/messages-container/index.ts +2 -0
  20. package/src/modules/messages/components/messages-container/messages-container.tsx +91 -0
  21. package/src/modules/messages/components/messages-list/messages-list.tsx +9 -82
  22. package/src/modules/messages/constants.ts +5 -0
  23. package/src/modules/messages/events.ts +12 -4
  24. package/src/modules/messages/hooks/index.ts +1 -0
  25. package/src/modules/messages/hooks/use-all-messages/use-all-messages.tsx +1 -2
  26. package/src/modules/messages/hooks/use-infinite-get-messages/use-infinite-get-messages.spec.tsx +18 -19
  27. package/src/modules/messages/hooks/use-infinite-get-messages/use-infinite-get-messages.tsx +41 -35
  28. package/src/modules/messages/hooks/use-scroller/index.ts +2 -0
  29. package/src/modules/messages/hooks/use-scroller/use-scroller.tsx +50 -0
  30. package/src/modules/messages/hooks/use-send-text-message/use-send-text-message.tsx +31 -2
  31. package/src/modules/messages/hooks/use-subscribe-message-received-event/use-subscribe-message-received-event.tsx +47 -64
  32. package/src/modules/messages/store/index.ts +1 -0
  33. package/src/modules/messages/store/messages-max-count.atom.ts +13 -0
  34. package/src/modules/messages/utils/index.ts +2 -0
  35. package/src/modules/messages/utils/set-messages-cache/index.ts +1 -0
  36. package/src/modules/messages/utils/set-messages-cache/utils.ts +53 -0
  37. package/src/modules/widget/components/chat-page/chat-page.spec.tsx +23 -7
  38. package/src/modules/widget/components/chat-page/chat-page.tsx +70 -14
  39. package/src/modules/widget/components/greetings-card/greetings-card.tsx +19 -15
  40. package/src/modules/widget/components/header/header.tsx +6 -4
  41. package/src/modules/widget/components/information-page/constants.ts +6 -2
  42. package/src/modules/widget/components/information-page/information-card/information-card.tsx +22 -5
  43. package/src/modules/widget/components/information-page/information-page.tsx +16 -3
  44. package/src/modules/widget/components/starter-page/starter-page.spec.tsx +4 -1
  45. package/src/modules/widget/components/starter-page/starter-page.tsx +30 -5
  46. package/src/modules/widget/components/greetings-card/styles.module.css +0 -3
@@ -0,0 +1,53 @@
1
+ import type { Message } from '@hotmart/sparkie/dist/MessageService'
2
+ import type { InfiniteData, QueryClient } from '@tanstack/react-query'
3
+ import { produce } from 'immer'
4
+
5
+ import type { FetchMessagesResponse, IMessageWithSenderData } from '../../types'
6
+
7
+ const placeholderID = 'remove::placeholder::id'
8
+
9
+ export type SetMessageCacheParams = {
10
+ queryKey: readonly unknown[]
11
+ queryClient: QueryClient
12
+ data: Partial<Message>
13
+ sending?: boolean
14
+ }
15
+
16
+ export const setMessagesCache =
17
+ ({ queryClient, queryKey, data, sending }: SetMessageCacheParams) =>
18
+ () => {
19
+ queryClient.setQueryData<InfiniteData<FetchMessagesResponse>>(queryKey, (oldData) => {
20
+ return produce(oldData, (draft) => {
21
+ const lastPageMessages = draft?.pages?.at(-1)?.messages
22
+ const lastMessage = lastPageMessages?.at?.(-1)
23
+
24
+ const placeholderMsgIndex = Number(
25
+ lastPageMessages?.findIndex((msg) => msg.id === placeholderID)
26
+ )
27
+
28
+ const msgIndex = Number(
29
+ !isNaN(placeholderMsgIndex) && placeholderMsgIndex !== -1
30
+ ? placeholderMsgIndex
31
+ : lastPageMessages?.length
32
+ )
33
+
34
+ if (isNaN(msgIndex)) return draft
35
+
36
+ const newMessage = {
37
+ ...lastMessage,
38
+ sentAt: Date.now(),
39
+ updatedAt: Date.now(),
40
+ metadata: {
41
+ ...lastMessage?.metadata,
42
+ author: 'user'
43
+ },
44
+ ...data,
45
+ ...(sending ? { id: placeholderID } : {})
46
+ } as IMessageWithSenderData
47
+
48
+ lastPageMessages?.splice(msgIndex, 1, newMessage)
49
+
50
+ return draft
51
+ })
52
+ })
53
+ }
@@ -1,27 +1,43 @@
1
- import { render, screen, waitFor } from '@/src/config/tests'
2
- import type { IMessageWithSenderData } from '@/src/modules/messages'
3
- import IMessageWithSenderDataMock from '@/src/modules/messages/__tests__/imessage-with-sender-data.mock'
1
+ import { createRef } from 'react'
2
+
3
+ import { chance, render, screen, waitFor } from '@/src/config/tests'
4
+ import { useScroller } from '@/src/modules/messages/hooks/use-scroller'
5
+ import { useGetProfile } from '@/src/modules/profile'
4
6
  import WidgetSettingPropsBuilder from '../../__tests__/widget-settings-props.builder'
5
7
  import * as Store from '../../store'
6
8
 
7
9
  import ChatPage from './chat-page'
8
10
 
11
+ vi.mock('@/src/modules/profile', () => ({ useGetProfile: vi.fn() }))
12
+
13
+ vi.mock('@/src/modules/messages/hooks/use-scroller', () => ({
14
+ useScroller: vi.fn()
15
+ }))
16
+
9
17
  describe('ChatPage', () => {
10
18
  const defaultSettings = new WidgetSettingPropsBuilder()
11
- const getMessagesMock = new IMessageWithSenderDataMock().getMany(10) as IMessageWithSenderData[]
19
+ const scrollerRef = createRef<HTMLDivElement>()
20
+ const scrollToButtonRef = createRef<HTMLButtonElement>()
21
+
22
+ const useScrollerMock = {
23
+ scrollerRef,
24
+ scrollToButtonRef,
25
+ scrollToBottom: vi.fn(),
26
+ showScrollButton: false
27
+ }
12
28
 
13
29
  const renderComponent = () => render(<ChatPage />)
14
30
 
15
31
  beforeEach(() => {
16
32
  vi.spyOn(Store, 'useWidgetSettingsAtomValue').mockReturnValue(defaultSettings)
33
+ vi.mocked(useGetProfile).mockReturnValue({ data: { id: chance.guid() } } as never)
34
+ vi.mocked(useScroller).mockReturnValue(useScrollerMock)
17
35
  })
18
36
 
19
37
  it('should render each fetched message item from API', async () => {
20
38
  renderComponent()
21
39
 
22
- await waitFor(() =>
23
- expect(screen.getAllByTestId('messages-item')).toHaveLength(getMessagesMock.length)
24
- )
40
+ await waitFor(() => expect(screen.getAllByTestId('messages-item')).toHaveLength(2))
25
41
 
26
42
  expect(screen.getByPlaceholderText(/send_message.field.placeholder/)).toBeInTheDocument()
27
43
  })
@@ -1,24 +1,55 @@
1
- import { useRef } from 'react'
1
+ import { lazy, useEffect, useMemo, useRef } from 'react'
2
+ import { useInfiniteQuery } from '@tanstack/react-query'
2
3
 
3
4
  import { isTextEmpty } from '@/src/lib/utils/is-text-empty'
4
5
  import { ChatInput, MessagesList, useChatInputValueAtom } from '@/src/modules/messages/components'
5
- import { useAllMessages, useSendTextMessage } from '@/src/modules/messages/hooks'
6
+ import { MessagesContainer } from '@/src/modules/messages/components/messages-container'
7
+ import { getAllMessagesQuery, useSendTextMessage } from '@/src/modules/messages/hooks'
8
+ import { useMessagesMaxCount } from '@/src/modules/messages/store'
9
+ import { useGetProfile } from '@/src/modules/profile'
6
10
  import {
7
- useWidgetLoadingAtomValue,
11
+ useWidgetLoadingAtom,
8
12
  useWidgetSettingsAtomValue,
9
13
  useWidgetTabsValueAtom
10
14
  } from '../../store'
11
15
  import { WidgetHeader } from '../header'
12
16
  import { PageLayout } from '../page-layout'
13
17
 
18
+ const MessageItemError = lazy(
19
+ () => import('@/src/modules/messages/components/message-item-error/message-item-error')
20
+ )
21
+
22
+ const MessageItemEndOfScroll = lazy(
23
+ () =>
24
+ import(
25
+ '@/src/modules/messages/components/message-item-end-of-scroll/message-item-end-of-scroll'
26
+ )
27
+ )
28
+
14
29
  function ChatPage() {
15
- const widgetTabs = useWidgetTabsValueAtom()
16
30
  const chatInputRef = useRef<HTMLTextAreaElement>(null)
31
+ const scrollerRef = useRef<HTMLDivElement>(null)
32
+ const settings = useWidgetSettingsAtomValue()
33
+ const profileQuery = useGetProfile()
34
+ const widgetTabs = useWidgetTabsValueAtom()
17
35
  const sendTextMessageMutation = useSendTextMessage()
18
- const { messagesQuery } = useAllMessages()
19
- const widgetLoading = useWidgetLoadingAtomValue()
36
+ const limit = useMessagesMaxCount()
20
37
  const [value, setValue] = useChatInputValueAtom()
21
- const settings = useWidgetSettingsAtomValue()
38
+ const [, setWidgetLoading] = useWidgetLoadingAtom()
39
+
40
+ const conversationId = useMemo(() => settings?.conversationId, [settings?.conversationId])
41
+ const profileId = useMemo(() => profileQuery.data?.id, [profileQuery.data?.id])
42
+ const messagesQueryConfig = useMemo(
43
+ () =>
44
+ getAllMessagesQuery({
45
+ conversationId,
46
+ profileId,
47
+ limit
48
+ }),
49
+ [conversationId, limit, profileId]
50
+ )
51
+
52
+ const messagesQuery = useInfiniteQuery(messagesQueryConfig)
22
53
 
23
54
  const handleSendMessage = () => {
24
55
  const text = chatInputRef.current?.value ?? ''
@@ -33,6 +64,12 @@ function ChatPage() {
33
64
  })
34
65
  }
35
66
 
67
+ useEffect(() => {
68
+ if (messagesQuery.isError) {
69
+ setWidgetLoading(false)
70
+ }
71
+ }, [messagesQuery.isError, setWidgetLoading])
72
+
36
73
  return (
37
74
  <PageLayout
38
75
  asideChild={
@@ -40,18 +77,37 @@ function ChatPage() {
40
77
  name='new-chat-msg-input'
41
78
  ref={chatInputRef}
42
79
  onSend={widgetTabs.currentTab === 'chat' ? handleSendMessage : undefined}
43
- loading={widgetLoading || sendTextMessageMutation.isPending}
80
+ loading={sendTextMessageMutation.isPending}
44
81
  inputDisabled={messagesQuery?.isLoading}
45
82
  buttonDisabled={messagesQuery?.isLoading || !value.trim()}
46
83
  />
47
84
  }>
48
- <>
49
- <div className='mt-4 px-6 py-4'>
50
- <WidgetHeader enabledButtons={['info', 'close']} tutorName={settings?.tutorName} />
51
- </div>
52
- <MessagesList />
53
- </>
85
+ <div className='mt-4 px-6 py-4'>
86
+ <WidgetHeader enabledButtons={['info', 'close']} tutorName={settings?.tutorName} />
87
+ </div>
88
+ <MessagesContainer
89
+ ref={scrollerRef}
90
+ handleShowMore={async () => {
91
+ await messagesQuery.fetchNextPage()
92
+ }}
93
+ showButton={messagesQuery.hasNextPage}
94
+ loading={messagesQuery.isFetchingNextPage}>
95
+ <MessageItemEndOfScroll
96
+ show={
97
+ !messagesQuery.isFetching &&
98
+ !messagesQuery.hasNextPage &&
99
+ Number(messagesQuery.data?.size) > 0
100
+ }
101
+ />
102
+ {messagesQuery.data && <MessagesList messagesMap={messagesQuery.data} />}
103
+ <MessageItemError
104
+ show={messagesQuery.isError}
105
+ message={`❌ Error loading messages: ${messagesQuery.error?.message ?? ''}`}
106
+ retry={() => void messagesQuery.refetch()}
107
+ />
108
+ </MessagesContainer>
54
109
  </PageLayout>
55
110
  )
56
111
  }
112
+
57
113
  export default ChatPage
@@ -1,13 +1,9 @@
1
1
  import clsx from 'clsx'
2
2
  import { useTranslation } from 'react-i18next'
3
3
 
4
- import { AIAvatar } from '../ai-avatar'
5
-
6
- import styles from './styles.module.css'
7
-
8
4
  export type GreetingsCardProps = {
9
5
  tutorName: string
10
- author: string
6
+ author?: string
11
7
  isDarkTheme?: boolean
12
8
  }
13
9
 
@@ -15,23 +11,31 @@ function GreetingsCard({ author, tutorName, isDarkTheme = false }: GreetingsCard
15
11
  const { t } = useTranslation()
16
12
 
17
13
  return (
18
- <div className='flex flex-col items-center justify-center text-neutral-900'>
14
+ <div className='flex flex-col items-center justify-center'>
19
15
  <div className='flex flex-col items-center justify-center gap-4 text-center'>
20
- <AIAvatar
21
- className={clsx('rounded-full border-4 border-neutral-100', {
22
- 'bg-[#E7EDF2]/80': !isDarkTheme,
23
- 'bg-neutral-200': isDarkTheme
24
- })}
25
- />
26
16
  <div className='flex flex-col gap-2'>
27
- <span className='text-base font-light'>
17
+ <span
18
+ className={clsx('text-base font-light', {
19
+ 'text-white': isDarkTheme,
20
+ 'text-gray-900': !isDarkTheme
21
+ })}>
28
22
  {t('general.greetings.hello', { name: author })}
29
23
  </span>
30
- <h3 className={clsx('text-xl', styles.faceTxt)}>
24
+ <h3
25
+ className={clsx('text-xl font-bold', {
26
+ 'text-white': isDarkTheme,
27
+ 'text-gray-900': !isDarkTheme
28
+ })}>
31
29
  {t('general.greetings.firstMessage', { tutorName })}
32
30
  </h3>
33
31
  </div>
34
- <p className='text-sm font-normal text-neutral-600'>{t('general.greetings.description')}</p>
32
+ <p
33
+ className={clsx('text-sm font-normal', {
34
+ 'text-gray-400': isDarkTheme,
35
+ 'text-neutral-600': !isDarkTheme
36
+ })}>
37
+ {t('general.greetings.description')}
38
+ </p>
35
39
  </div>
36
40
  </div>
37
41
  )
@@ -1,3 +1,5 @@
1
+ import { useTranslation } from 'react-i18next'
2
+
1
3
  import { Button, Icon } from '@/src/lib/components'
2
4
  import { TutorWidgetEvents } from '../../events'
3
5
  import { useWidgetTabsAtom } from '../../store'
@@ -35,7 +37,9 @@ function WidgetHeader({
35
37
  showContentWithoutMeta,
36
38
  showContent = true
37
39
  }: WidgetHeaderProps) {
40
+ const { t } = useTranslation()
38
41
  const [, setTab] = useWidgetTabsAtom()
42
+ const name = tutorName ?? t('general.name')
39
43
 
40
44
  const handleClickArchive = () => {
41
45
  setTab('chat')
@@ -48,10 +52,8 @@ function WidgetHeader({
48
52
  return (
49
53
  <div className='grid-areas-[a_b] mt-0.5 grid grid-cols-[1fr_auto] items-center text-neutral-1000'>
50
54
  <div className='grid-area-[a]'>
51
- {showContent && !showContentWithoutMeta && <WidgetHeaderContent tutorName={tutorName} />}
52
- {showContentWithoutMeta && !showContent && (
53
- <WidgetHeaderContentWithoutMeta name={tutorName} />
54
- )}
55
+ {showContent && !showContentWithoutMeta && <WidgetHeaderContent tutorName={name} />}
56
+ {showContentWithoutMeta && !showContent && <WidgetHeaderContentWithoutMeta name={name} />}
55
57
  </div>
56
58
  <div className='shrink-0'>
57
59
  <div className='grid-area-[b] ml-auto flex max-w-max gap-3 text-neutral-700'>
@@ -12,6 +12,10 @@ export const infoItems: InfoItem[] = [
12
12
  titleKey: 'info.what_it_does_question',
13
13
  descKey: 'info.what_it_does_answer'
14
14
  },
15
- { icon: 'book', titleKey: 'info.how_it_learns_question', descKey: 'info.how_it_learns_answer' },
16
- { icon: 'warning', titleKey: 'info.limitations_question', descKey: 'info.limitations_answer' }
15
+ {
16
+ icon: 'gallery',
17
+ titleKey: 'info.how_it_learns_question',
18
+ descKey: 'info.how_it_learns_answer'
19
+ },
20
+ { icon: 'info', titleKey: 'info.limitations_question', descKey: 'info.limitations_answer' }
17
21
  ]
@@ -1,3 +1,5 @@
1
+ import clsx from 'clsx'
2
+
1
3
  import { Icon } from '@/src/lib/components'
2
4
  import type { ValidIconNames } from '@/src/lib/components/icons/icon-names'
3
5
 
@@ -5,18 +7,33 @@ export type InformationCardProps = {
5
7
  icon: ValidIconNames
6
8
  title: string
7
9
  description: string
10
+ isDarkMode: boolean
8
11
  }
9
12
 
10
- function InformationCard({ icon, title, description }: InformationCardProps) {
13
+ function InformationCard({ icon, title, description, isDarkMode }: InformationCardProps) {
11
14
  return (
12
- <div className='flex gap-3 border-b border-white/10 pb-5 last:border-none'>
13
- <div className='flex h-5 w-5 items-start justify-center'>
15
+ <div
16
+ className={clsx('flex justify-center gap-3 border-b pb-5 last:border-none', {
17
+ 'border-white/10': isDarkMode,
18
+ 'border-black/10': !isDarkMode
19
+ })}>
20
+ <div
21
+ className={clsx('flex h-5 w-5 items-start justify-center', {
22
+ 'text-white': isDarkMode,
23
+ 'text-neutral-900': !isDarkMode
24
+ })}>
14
25
  <Icon name={icon} width={16} height={16} />
15
26
  </div>
16
27
 
17
28
  <div className='flex flex-col gap-1'>
18
- <p className='text-sm font-bold'>{title}</p>
19
- <p className='text-xs text-gray-300'>{description}</p>
29
+ <p className='text-sm font-bold text-neutral-900'>{title}</p>
30
+ <p
31
+ className={clsx('text-xs', {
32
+ 'text-gray-300': isDarkMode,
33
+ 'text-gray-500': !isDarkMode
34
+ })}>
35
+ {description}
36
+ </p>
20
37
  </div>
21
38
  </div>
22
39
  )
@@ -1,3 +1,4 @@
1
+ import clsx from 'clsx'
1
2
  import { useTranslation } from 'react-i18next'
2
3
 
3
4
  import { Icon } from '@/src/lib/components'
@@ -12,10 +13,15 @@ function WidgetInformationPage() {
12
13
  const { t } = useTranslation()
13
14
  const [, setWidgetTabs] = useWidgetTabsAtom()
14
15
  const [settings] = useWidgetSettingsAtom()
16
+ const isDarkMode = settings?.config?.theme === 'dark'
15
17
 
16
18
  return (
17
19
  <PageLayout className='p-5 text-white'>
18
- <div className='relative mb-8 flex h-12 items-center justify-center'>
20
+ <div
21
+ className={clsx('relative mb-8 flex h-12 items-center justify-center', {
22
+ 'text-white': isDarkMode,
23
+ 'text-neutral-700': !isDarkMode
24
+ })}>
19
25
  <button
20
26
  className='absolute left-0'
21
27
  aria-label='Return Button'
@@ -25,11 +31,17 @@ function WidgetInformationPage() {
25
31
  <h1 className='mx-auto font-bold'>{t('info.title')}</h1>
26
32
  </div>
27
33
 
28
- <div className='mb-8 flex justify-center'>
34
+ <div className='mb-10 flex justify-center'>
29
35
  <div className='flex flex-col items-center gap-2'>
30
36
  <AIAvatar />
31
37
 
32
- <h3 className='font-bold'>{settings?.tutorName ?? ''}</h3>
38
+ <h3
39
+ className={clsx('font-bold', {
40
+ 'text-white': isDarkMode,
41
+ 'text-neutral-700': !isDarkMode
42
+ })}>
43
+ {settings?.tutorName ?? t('general.name')}
44
+ </h3>
33
45
  </div>
34
46
  </div>
35
47
 
@@ -40,6 +52,7 @@ function WidgetInformationPage() {
40
52
  icon={item.icon}
41
53
  title={t(item.titleKey)}
42
54
  description={t(item.descKey)}
55
+ isDarkMode={isDarkMode}
43
56
  />
44
57
  ))}
45
58
  </div>
@@ -3,7 +3,10 @@ import { useSendTextMessage } from '@/src/modules/messages/hooks'
3
3
 
4
4
  import WidgetStarterPage from './starter-page'
5
5
 
6
- vi.mock('@/src/modules/messages/hooks', () => ({ useSendTextMessage: vi.fn() }))
6
+ vi.mock('@/src/modules/messages/hooks', () => ({
7
+ getAllMessagesQuery: vi.fn(() => ({ pages: [], queryKey: ['any'] })),
8
+ useSendTextMessage: vi.fn()
9
+ }))
7
10
 
8
11
  describe('WidgetStarterPage', () => {
9
12
  const useSendTextMessageMock = { mutate: vi.fn() }
@@ -1,4 +1,5 @@
1
- import { useRef } from 'react'
1
+ import { useEffect, useMemo, useRef } from 'react'
2
+ import { useQueryClient } from '@tanstack/react-query'
2
3
  import clsx from 'clsx'
3
4
  import type { MouseEventHandler } from 'react'
4
5
  import { useTranslation } from 'react-i18next'
@@ -6,7 +7,9 @@ import { useTranslation } from 'react-i18next'
6
7
  import { Button } from '@/src/lib/components'
7
8
  import { useRefEventListener } from '@/src/lib/hooks'
8
9
  import { ChatInput, useChatInputValueAtom } from '@/src/modules/messages/components'
9
- import { useSendTextMessage } from '@/src/modules/messages/hooks'
10
+ import { getAllMessagesQuery, useSendTextMessage } from '@/src/modules/messages/hooks'
11
+ import { useMessagesMaxCount } from '@/src/modules/messages/store'
12
+ import { useGetProfile } from '@/src/modules/profile'
10
13
  import { useWidgetSettingsAtom, useWidgetTabsAtom } from '../../store'
11
14
  import { GreetingsCard } from '../greetings-card'
12
15
  import { WidgetHeader } from '../header'
@@ -21,6 +24,10 @@ function WidgetStarterPage() {
21
24
  const [chatInputValue, setChatInputValue] = useChatInputValueAtom()
22
25
  const [, setWidgetTabs] = useWidgetTabsAtom()
23
26
  const sendTextMessageMutation = useSendTextMessage()
27
+ const profileQuery = useGetProfile()
28
+ const limit = useMessagesMaxCount()
29
+ const queryClient = useQueryClient()
30
+ const name = settings?.tutorName ?? t('general.name')
24
31
 
25
32
  useRefEventListener<HTMLTextAreaElement>({
26
33
  config: {
@@ -53,6 +60,24 @@ function WidgetStarterPage() {
53
60
  sendText(chatInputRef.current?.value)
54
61
  }
55
62
 
63
+ const conversationId = useMemo(() => settings?.conversationId, [settings?.conversationId])
64
+
65
+ const profileId = useMemo(() => profileQuery.data?.id, [profileQuery.data?.id])
66
+
67
+ const messagesQueryConfig = useMemo(
68
+ () =>
69
+ getAllMessagesQuery({
70
+ conversationId,
71
+ profileId,
72
+ limit
73
+ }),
74
+ [conversationId, limit, profileId]
75
+ )
76
+
77
+ useEffect(() => {
78
+ void queryClient.prefetchInfiniteQuery(messagesQueryConfig)
79
+ }, [messagesQueryConfig, queryClient])
80
+
56
81
  return (
57
82
  <PageLayout
58
83
  asideChild={
@@ -70,14 +95,14 @@ function WidgetStarterPage() {
70
95
  })}>
71
96
  <WidgetHeader
72
97
  enabledButtons={['archive', 'info', 'close']}
73
- tutorName={settings?.tutorName}
98
+ tutorName={name}
74
99
  showContent={false}
75
100
  />
76
101
 
77
102
  <div className='my-auto'>
78
103
  <GreetingsCard
79
- author={settings?.author ?? ''}
80
- tutorName={settings?.tutorName ?? ''}
104
+ author={settings?.user?.name}
105
+ tutorName={name}
81
106
  isDarkTheme={settings?.config?.theme === 'dark'}
82
107
  />
83
108
  </div>
@@ -1,3 +0,0 @@
1
- .faceTxt {
2
- composes: gradientText from '../../../../config/styles/utilities/text-utilities.module.css';
3
- }