@taruvi/navkit 0.0.47 → 0.0.48-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taruvi/navkit",
3
- "version": "0.0.47",
3
+ "version": "0.0.48-beta.1",
4
4
  "main": "src/App.tsx",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/App.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import AppBar from "@mui/material/AppBar"
2
2
  import Toolbar from "@mui/material/Toolbar"
3
3
  import IconButton from "@mui/material/IconButton"
4
+ import { SvgIcon } from "@mui/material"
4
5
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
5
6
  import { useState } from "react"
6
7
  import { AppLauncher, Profile, ProfileMenu, Shortcuts, ShortcutsMenu, MattermostChat } from "./components"
@@ -12,8 +13,14 @@ import taruviLogo from "./assets/logo.svg";
12
13
  import taruviLogoWhite from "./assets/taruvi-logo-white.png";
13
14
  import type { Client } from "@taruvi/sdk"
14
15
 
16
+ const ChatIcon = ({ color }: { color?: string }) => (
17
+ <SvgIcon viewBox="-2 -2 24 24" sx={{ fontSize: 23, display: 'block', position: 'relative', top: 2 }}>
18
+ <path d="M18 0H2C0.9 0 0 0.9 0 2V20L4 16H18C19.1 16 20 15.1 20 14V2C20 0.9 19.1 0 18 0Z" fill={color || "#9DE5FD"} />
19
+ </SvgIcon>
20
+ )
21
+
15
22
  const NavkitContent = () => {
16
- const { isUserAuthenticated, siteSettings, appSettings, appSettingsLoaded, appName, userData, jwtToken, themeMode, navbarColor, iconColor } = useNavigation();
23
+ const { isUserAuthenticated, appSettings, appSettingsLoaded, appName, userData, appsList, chatUrl, themeMode, navbarColor, iconColor } = useNavigation();
17
24
  const resolvedAppName = appName || appSettings?.displayName
18
25
  const showTaruviLogo = appSettingsLoaded && !resolvedAppName && !appSettings?.icon
19
26
  const styles = getAppStyles(themeMode)
@@ -52,7 +59,12 @@ const NavkitContent = () => {
52
59
  ) : null}
53
60
  </Box>
54
61
  <Box component={"div"} sx={styles.rightSection}>
55
- <Shortcuts showChat={setShowChat} onMenuToggle={() => setShowShortcutsMenu(!showShortcutsMenu)} iconColor={iconColor} />
62
+ <Shortcuts onMenuToggle={() => setShowShortcutsMenu(!showShortcutsMenu)} iconColor={iconColor} />
63
+ {isUserAuthenticated && appsList.some(a => a.id === 'chat') && chatUrl && (
64
+ <Box onClick={() => setShowChat(true)} sx={{ ...styles.appLauncherContainer, cursor: 'pointer' }}>
65
+ <ChatIcon color={iconColor} />
66
+ </Box>
67
+ )}
56
68
  <Box
57
69
  onClick={() => {
58
70
  if (isUserAuthenticated) {
@@ -99,18 +111,18 @@ const NavkitContent = () => {
99
111
 
100
112
  {showShortcutsMenu && (
101
113
  <Box>
102
- <ShortcutsMenu showChat={setShowChat} />
114
+ <ShortcutsMenu />
103
115
  </Box>
104
116
  )}
105
117
 
106
- {showChat && siteSettings['chat-url'] && (
118
+ {showChat && chatUrl && (
107
119
  <DraggableResizable onClose={() => setShowChat(false)} initialWidth={Math.min(1200, window.innerWidth * 0.9)} initialHeight={Math.min(600, window.innerHeight * 0.8)}>
108
120
  <Box sx={styles.chatHeader}>
109
- <IconButton onClick={() => window.open(siteSettings['chat-url'], "_blank")} sx={styles.chatOpenButton}>
121
+ <IconButton onClick={() => window.open(chatUrl, "_blank")} sx={styles.chatOpenButton}>
110
122
  <FontAwesomeIcon icon={["fas", "external-link-alt"]} style={{ fontSize: "10px" }} />
111
123
  </IconButton>
112
124
  </Box>
113
- <MattermostChat jwtToken={jwtToken} mattermostUrl={siteSettings['chat-url']} loginId={userData?.email || ''} width="100%" height="100%" />
125
+ <MattermostChat mattermostUrl={chatUrl} width="100%" height="100%" />
114
126
  </DraggableResizable>
115
127
  )}
116
128
  </>
@@ -2,7 +2,7 @@ import { version } from '../package.json' with { type: 'json' }
2
2
  import { createContext, startTransition, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react'
3
3
  import type { AppData, AppSettings, NavigationContextType, NavkitProviderProps, SiteSettings, UserData } from './types'
4
4
  import type { ThemeMode } from './styles/variables'
5
- import { User, Settings, Auth, App } from "@taruvi/sdk"
5
+ import { User, Settings, Auth, App, Secrets } from "@taruvi/sdk"
6
6
  import { library } from '@fortawesome/fontawesome-svg-core'
7
7
  import { fas } from '@fortawesome/free-solid-svg-icons'
8
8
  import { far } from '@fortawesome/free-regular-svg-icons'
@@ -24,7 +24,7 @@ export const NavkitProvider = ({ children, client, onThemeChange, appName, navba
24
24
 
25
25
  const user = useRef<any>(null)
26
26
  const settings = useRef<any>(null)
27
- const siteSettings = useRef<SiteSettings>({
27
+ const [siteSettings, setSiteSettings] = useState<SiteSettings>({
28
28
  shortcuts: [],
29
29
  logo: '',
30
30
  'show-chat': false,
@@ -38,7 +38,8 @@ export const NavkitProvider = ({ children, client, onThemeChange, appName, navba
38
38
  const [isDesk, setIsDesk] = useState<boolean>(false)
39
39
  const [appsList, setAppsList] = useState<AppData[]>([])
40
40
  const [userData, setUserData] = useState<UserData | null>(null)
41
- const [jwtToken, setJwtToken] = useState<string>('')
41
+ const [chatUrl, setChatUrl] = useState<string>('')
42
+ const [sessionToken, setSessionToken] = useState<string>('')
42
43
  const [isUserAuthenticated, setIsUserAuthenticated] = useState<boolean>(false)
43
44
  const [themeMode, setThemeMode] = useState<ThemeMode>(getInitialTheme)
44
45
 
@@ -75,8 +76,8 @@ export const NavkitProvider = ({ children, client, onThemeChange, appName, navba
75
76
 
76
77
  // Get JWT token if authenticated from sdk
77
78
  if (authenticated) {
78
- const token = client.tokenClient.getToken() || ''
79
- setJwtToken(token)
79
+ const token = auth.getSessionToken() || ''
80
+ setSessionToken(token)
80
81
  }
81
82
  }
82
83
 
@@ -104,18 +105,41 @@ export const NavkitProvider = ({ children, client, onThemeChange, appName, navba
104
105
  }
105
106
 
106
107
  const rawSettings = (fetchedSettings?.data ?? fetchedSettings)?.settings ?? {}
107
- siteSettings.current = {
108
- ...siteSettings.current,
108
+
109
+ let chatUrl = ''
110
+ try {
111
+ const secretResponse = await new Secrets(client).get('chat-url').execute<{ data: { value: string | { chat_url?: string, url?: string } } }>()
112
+ const secretValue = secretResponse?.data?.value
113
+ chatUrl = typeof secretValue === 'string'
114
+ ? secretValue
115
+ : (secretValue?.chat_url ?? secretValue?.url ?? '')
116
+ } catch { }
117
+ setChatUrl(chatUrl)
118
+
119
+ const newSiteSettings: SiteSettings = {
120
+ shortcuts: [],
121
+ logo: rawSettings['navkit.logo'] ?? '',
109
122
  'show-chat': rawSettings['navkit.show-chat'] ?? false,
110
- 'chat-url': rawSettings['navkit.chat-url'] ?? '',
123
+ 'chat-url': chatUrl,
111
124
  frontendUrl: rawSettings['navkit.frontend-url'] ?? '',
112
- logo: rawSettings['navkit.logo'] ?? '',
113
125
  enableDarkMode: rawSettings['navkit.enable-dark-mode'] ?? false,
114
126
  }
127
+ setSiteSettings(newSiteSettings)
115
128
  if (isUserAuthenticated) {
116
129
  const userDataResponse = await auth.getCurrentUser()
117
130
  setUserData(userDataResponse?.data || null)
118
131
 
132
+ // Login to Mattermost on init if chat is configured
133
+ const token = auth.getSessionToken() || ''
134
+ if (chatUrl && token && userDataResponse?.data?.username) {
135
+ fetch(`${chatUrl.replace(/\/$/, '')}/api/v4/users/login`, {
136
+ method: 'POST',
137
+ headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest', 'X-Environment': 'Browser' },
138
+ credentials: 'omit',
139
+ body: JSON.stringify({ username: userDataResponse.data.username, password: token })
140
+ }).catch(() => {})
141
+ }
142
+
119
143
  // Fetch user apps using username from userData
120
144
  if (userDataResponse?.data?.username) {
121
145
  const appsResponse = await user.current.getUserApps?.(userDataResponse.data.username)
@@ -176,7 +200,7 @@ export const NavkitProvider = ({ children, client, onThemeChange, appName, navba
176
200
  }, [themeMode, onThemeChange])
177
201
 
178
202
  return (
179
- <NavigationContext.Provider value={{ navigateToUrl, isDesk, appsList, userData, siteSettings: siteSettings.current, appSettings, appSettingsLoaded, appName, jwtToken, isUserAuthenticated, client, auth, themeMode, toggleTheme, navbarColor, iconColor }}>
203
+ <NavigationContext.Provider value={{ navigateToUrl, isDesk, appsList, userData, siteSettings, appSettings, appSettingsLoaded, appName, chatUrl, sessionToken, isUserAuthenticated, client, auth, themeMode, toggleTheme, navbarColor, iconColor }}>
180
204
  {children}
181
205
  </NavigationContext.Provider>
182
206
  )
@@ -19,7 +19,8 @@ const isValidFaIcon = (icon: string): boolean => {
19
19
  }
20
20
 
21
21
  const AppLauncher = () => {
22
- const { navigateToUrl, appsList, themeMode } = useNavigation()
22
+ const { navigateToUrl, appsList: allApps, themeMode } = useNavigation()
23
+ const appsList = allApps.filter(a => a.id !== 'chat')
23
24
  const styles = getAppLauncherStyles(themeMode)
24
25
  const [filteredApps, setFilteredApps] = useState<AppData[]>(appsList || [])
25
26
 
@@ -1,10 +1,8 @@
1
- import { useEffect, useRef, useState } from 'react'
2
- import { Box, Badge, CircularProgress, Typography } from '@mui/material'
1
+ import {useEffect, useRef, useState} from 'react'
2
+ import {Box, Badge} from '@mui/material'
3
3
 
4
4
  interface MattermostChatProps {
5
- jwtToken: string
6
- mattermostUrl: string
7
- loginId: string
5
+ mattermostUrl: string // Mattermost server URL (must be passed from parent app)
8
6
  onNotification?: (count: number) => void
9
7
  onUrlClick?: (url: string) => void
10
8
  width?: string | number
@@ -22,77 +20,22 @@ interface NotifyMessage {
22
20
  }
23
21
  }
24
22
 
25
- const MattermostChat = ({
26
- jwtToken,
27
- mattermostUrl,
28
- loginId,
29
- onNotification,
30
- onUrlClick,
31
- width = '100%',
32
- height = '100%'
33
- }: MattermostChatProps) => {
23
+ const MattermostChat = ({ mattermostUrl, onNotification, onUrlClick, width = '100%', height = '100%' }: MattermostChatProps) => {
34
24
  const iframeRef = useRef<HTMLIFrameElement>(null)
35
25
  const [unreadCount, setUnreadCount] = useState(0)
36
26
  const [isWindowFocused, setIsWindowFocused] = useState(true)
37
- const [authToken, setAuthToken] = useState<string | null>(null)
38
- const [authError, setAuthError] = useState<string | null>(null)
39
- const [isLoading, setIsLoading] = useState(true)
40
-
41
- // Authenticate with Mattermost on mount
42
- useEffect(() => {
43
- const login = async () => {
44
- try {
45
- const res = await fetch(`${mattermostUrl.replace(/\/$/, '')}/api/v4/users/login`, {
46
- method: 'POST',
47
- headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
48
- credentials: 'omit',
49
- body: JSON.stringify({ login_id: loginId, password: jwtToken, token: '', deviceId: '' })
50
- })
51
-
52
- if (!res.ok) {
53
- setAuthError(`Login failed (${res.status})`)
54
- setIsLoading(false)
55
- return
56
- }
57
-
58
- const token = res.headers.get('Token')
59
- if (token) {
60
- setAuthToken(token)
61
- } else {
62
- setAuthError('No token in response')
63
- }
64
- } catch (e: any) {
65
- setAuthError(e.message || 'Login failed')
66
- }
67
- setIsLoading(false)
68
- }
69
-
70
- if (loginId && jwtToken) login()
71
- else { setAuthError('Missing credentials'); setIsLoading(false) }
72
- }, [mattermostUrl, loginId, jwtToken])
73
-
74
- // Inject auth token into iframe via postMessage once loaded
75
- useEffect(() => {
76
- if (!authToken || !iframeRef.current) return
77
-
78
- const handleIframeLoad = () => {
79
- // Set the auth cookie/token in the iframe context
80
- iframeRef.current?.contentWindow?.postMessage(
81
- { type: 'token', data: authToken },
82
- new URL(mattermostUrl).origin
83
- )
84
- }
85
-
86
- const iframe = iframeRef.current
87
- iframe.addEventListener('load', handleIframeLoad)
88
- return () => iframe.removeEventListener('load', handleIframeLoad)
89
- }, [authToken, mattermostUrl])
90
27
 
91
28
  useEffect(() => {
29
+ // Handle postMessage events from Mattermost iframe
92
30
  const handleMessage = (event: MessageEvent<NotifyMessage>) => {
31
+ // Validate origin for security
93
32
  const mattermostOrigin = new URL(mattermostUrl).origin
94
- if (event.origin !== mattermostOrigin) return
33
+ if (event.origin !== mattermostOrigin) {
34
+ console.warn('Received message from untrusted origin:', event.origin)
35
+ return
36
+ }
95
37
 
38
+ // Handle Notify events
96
39
  if (event.data?.event === 'Notify') {
97
40
  if (!isWindowFocused) {
98
41
  setUnreadCount(prev => {
@@ -101,16 +44,31 @@ const MattermostChat = ({
101
44
  return newCount
102
45
  })
103
46
  }
104
- if (event.data.data?.url && onUrlClick) onUrlClick(event.data.data.url)
47
+
48
+ // Handle URL clicks if provided
49
+ if (event.data.data?.url && onUrlClick) {
50
+ onUrlClick(event.data.data.url)
51
+ }
105
52
  }
106
53
  }
107
54
 
108
- const handleFocus = () => { setIsWindowFocused(true); setUnreadCount(0); onNotification?.(0) }
109
- const handleBlur = () => setIsWindowFocused(false)
55
+ // Handle window focus/blur to track unread messages
56
+ const handleFocus = () => {
57
+ setIsWindowFocused(true)
58
+ setUnreadCount(0)
59
+ onNotification?.(0)
60
+ }
61
+
62
+ const handleBlur = () => {
63
+ setIsWindowFocused(false)
64
+ }
110
65
 
66
+ // Add event listeners
111
67
  window.addEventListener('message', handleMessage)
112
68
  window.addEventListener('focus', handleFocus)
113
69
  window.addEventListener('blur', handleBlur)
70
+
71
+ // Cleanup event listeners on unmount
114
72
  return () => {
115
73
  window.removeEventListener('message', handleMessage)
116
74
  window.removeEventListener('focus', handleFocus)
@@ -118,34 +76,34 @@ const MattermostChat = ({
118
76
  }
119
77
  }, [mattermostUrl, isWindowFocused, onNotification, onUrlClick])
120
78
 
121
- if (isLoading) {
122
- return (
123
- <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width, height }}>
124
- <CircularProgress size={32} />
125
- </Box>
126
- )
127
- }
128
-
129
- if (authError) {
130
- return (
131
- <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width, height }}>
132
- <Typography color="error">{authError}</Typography>
133
- </Box>
134
- )
135
- }
136
-
137
- // Load Mattermost with the auth token as a cookie header via the access_token param
138
- const iframeUrl = `${mattermostUrl.replace(/\/$/, '')}?access_token=${authToken}`
79
+ // Construct iframe URL with JWT authentication
80
+ // const iframeUrl = `${mattermostUrl.replace(/\/$/, '')}/login`
81
+ const iframeUrl = mattermostUrl
139
82
 
140
83
  return (
141
- <Box sx={{ position: 'relative', width, height, overflow: 'hidden' }}>
84
+ <Box
85
+ sx={{
86
+ position: 'relative',
87
+ width,
88
+ height,
89
+ overflow: 'hidden'
90
+ }}
91
+ >
142
92
  {unreadCount > 0 && (
143
93
  <Badge
144
94
  badgeContent={unreadCount}
145
95
  color="error"
146
96
  sx={{
147
- position: 'absolute', top: 16, right: 16, zIndex: 1000,
148
- '& .MuiBadge-badge': { fontSize: '1rem', height: '28px', minWidth: '28px', borderRadius: '14px' }
97
+ position: 'absolute',
98
+ top: 16,
99
+ right: 16,
100
+ zIndex: 1000,
101
+ '& .MuiBadge-badge': {
102
+ fontSize: '1rem',
103
+ height: '28px',
104
+ minWidth: '28px',
105
+ borderRadius: '14px'
106
+ }
149
107
  }}
150
108
  />
151
109
  )}
@@ -154,7 +112,12 @@ const MattermostChat = ({
154
112
  src={iframeUrl}
155
113
  title="Mattermost Chat"
156
114
  allow="clipboard-read; clipboard-write"
157
- style={{ width: '100%', height: '100%', border: 'none', display: 'block' }}
115
+ style={{
116
+ width: '100%',
117
+ height: '100%',
118
+ border: 'none',
119
+ display: 'block'
120
+ }}
158
121
  />
159
122
  </Box>
160
123
  )
@@ -5,7 +5,6 @@ export const shortcutsStyles = {
5
5
  display: { xs: 'none', md: 'flex' },
6
6
  alignItems: 'center',
7
7
  gap: '10px',
8
- ml: spacing.md,
9
8
  },
10
9
  mobileTrigger: {
11
10
  display: { xs: 'flex', md: 'none' },
@@ -16,9 +15,12 @@ export const shortcutsStyles = {
16
15
  display: 'flex',
17
16
  flexDirection: 'column' as const,
18
17
  alignItems: 'center',
18
+ justifyContent: 'center',
19
19
  textDecoration: 'none',
20
20
  cursor: 'pointer',
21
21
  color: colours.text.secondary,
22
+ minWidth: 40,
23
+ minHeight: 40,
22
24
  '&:hover': {
23
25
  opacity: 0.7,
24
26
  },
@@ -1,17 +1,10 @@
1
1
  import type { AppData } from '../../types'
2
- import { Box, Link, IconButton, SvgIcon } from '@mui/material'
2
+ import { Box, Link, IconButton } from '@mui/material'
3
3
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
4
4
  import { shortcutsStyles } from './Shortcuts.styles'
5
5
  import { useNavigation } from '../../NavkitContext'
6
6
 
7
- const ChatIcon = ({ color }: { color?: string }) => (
8
- <SvgIcon viewBox="-2 -2 24 24" sx={{ fontSize: 23, display: 'block', position: 'relative', top: 2 }}>
9
- <path d="M18 0H2C0.9 0 0 0.9 0 2V20L4 16H18C19.1 16 20 15.1 20 14V2C20 0.9 19.1 0 18 0Z" fill={color || "#9DE5FD"}/>
10
- </SvgIcon>
11
- )
12
-
13
7
  interface ShortcutsProps {
14
- showChat?: (showChat: boolean) => void
15
8
  onMenuToggle?: () => void
16
9
  triggerRef?: React.RefObject<HTMLButtonElement | null>
17
10
  iconColor?: string
@@ -19,8 +12,8 @@ interface ShortcutsProps {
19
12
 
20
13
  const Shortcuts = (props: ShortcutsProps) => {
21
14
 
22
- const { showChat, onMenuToggle, triggerRef, iconColor } = props
23
- const { navigateToUrl, siteSettings, isUserAuthenticated } = useNavigation()
15
+ const { onMenuToggle, triggerRef, iconColor } = props
16
+ const { navigateToUrl, siteSettings } = useNavigation()
24
17
  const shortcuts = siteSettings.shortcuts
25
18
 
26
19
  const handleShortcutClick = (shortcut: AppData) => {
@@ -45,19 +38,10 @@ const Shortcuts = (props: ShortcutsProps) => {
45
38
  />
46
39
  </Link>
47
40
  ))}
48
- {siteSettings['show-chat'] && siteSettings['chat-url'] && isUserAuthenticated &&
49
- <Link
50
- key={"chat"}
51
- onClick={() => showChat?.(true)}
52
- sx={shortcutsStyles.shortcut}
53
- >
54
- <ChatIcon color={iconColor} />
55
- </Link>
56
- }
57
41
  </Box>
58
42
 
59
43
  {/* Mobile view - trigger button */}
60
- {((shortcuts?.length ?? 0) > 0 || (siteSettings['show-chat'] && siteSettings['chat-url'] && isUserAuthenticated)) && (
44
+ {(shortcuts?.length ?? 0) > 0 && (
61
45
  <IconButton
62
46
  ref={triggerRef}
63
47
  onClick={onMenuToggle}
@@ -1,22 +1,13 @@
1
- import { Card, MenuItem, Typography, SvgIcon } from '@mui/material'
1
+ import { Card, MenuItem, Typography } from '@mui/material'
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
3
3
  import type { AppData } from '../../types'
4
4
  import { getShortcutsMenuStyles } from './ShortcutsMenu.styles'
5
5
  import { useNavigation } from '../../NavkitContext'
6
6
 
7
- const ChatIcon = ({ style }: { style: Record<string, any> }) => (
8
- <SvgIcon viewBox="-2 -2 24 24" sx={{ fontSize: style.fontSize, color: style.color }}>
9
- <path d="M18 0H2C0.9 0 0 0.9 0 2V20L4 16H18C19.1 16 20 15.1 20 14V2C20 0.9 19.1 0 18 0Z" fill="currentColor"/>
10
- </SvgIcon>
11
- )
7
+ interface ShortcutsMenuProps {}
12
8
 
13
- interface ShortcutsMenuProps {
14
- showChat: (showChat: boolean) => void
15
- }
16
-
17
- const ShortcutsMenu = (props: ShortcutsMenuProps) => {
18
- const { showChat } = props
19
- const { navigateToUrl, siteSettings, isUserAuthenticated, themeMode } = useNavigation()
9
+ const ShortcutsMenu = (_props: ShortcutsMenuProps) => {
10
+ const { navigateToUrl, siteSettings, themeMode } = useNavigation()
20
11
  const shortcuts = siteSettings.shortcuts
21
12
  const themedStyles = getShortcutsMenuStyles(themeMode)
22
13
 
@@ -28,18 +19,6 @@ const ShortcutsMenu = (props: ShortcutsMenuProps) => {
28
19
 
29
20
  return (
30
21
  <Card sx={themedStyles.menu}>
31
- {siteSettings['show-chat'] && siteSettings['chat-url'] && isUserAuthenticated && (
32
- <MenuItem
33
- key="chat"
34
- onClick={() => showChat(true)}
35
- sx={themedStyles.menuItem}
36
- >
37
- <ChatIcon style={themedStyles.iconStyle} />
38
- <Typography sx={themedStyles.menuItemText}>
39
- Chat
40
- </Typography>
41
- </MenuItem>
42
- )}
43
22
  {shortcuts?.map((shortcut) => (
44
23
  <MenuItem
45
24
  key={shortcut.id}
package/src/types.ts CHANGED
@@ -37,7 +37,8 @@ export interface NavigationContextType {
37
37
  appSettings: AppSettings
38
38
  appSettingsLoaded: boolean
39
39
  appName?: string
40
- jwtToken: string
40
+ chatUrl: string
41
+ sessionToken: string
41
42
  isUserAuthenticated: boolean
42
43
  client: Client
43
44
  auth: Auth