168 lines
5.1 KiB
TypeScript
168 lines
5.1 KiB
TypeScript
import React, { useEffect, Suspense, useRef, useState } from 'react'
|
||
import { Routes, Route, useNavigate } from 'react-router-dom'
|
||
import { Provider } from 'react-redux'
|
||
import { getNavigationValue } from '@brojs/cli'
|
||
import { Box, Container, Spinner, VStack, useColorMode } from '@chakra-ui/react'
|
||
import { useTranslation } from 'react-i18next'
|
||
|
||
import {
|
||
CourseListPage,
|
||
LessonDetailsPage,
|
||
LessonListPage,
|
||
UserPage,
|
||
AttendancePage,
|
||
} from './pages'
|
||
import { ErrorBoundary, AppHeader, BreadcrumbsProvider, useBreadcrumbs } from './components'
|
||
import { keycloak } from './__data__/kc'
|
||
|
||
const MENU_SCRIPT_URL = 'https://admin.bro-js.ru/remote-assets/lib/serviceMenu/serviceMenu.js'
|
||
|
||
const loadServiceMenu = () => {
|
||
return new Promise((resolve, reject) => {
|
||
const script = document.createElement('script')
|
||
script.src = MENU_SCRIPT_URL
|
||
script.onload = () => setTimeout(() => resolve(true), 1000)
|
||
script.onerror = reject
|
||
document.body.appendChild(script)
|
||
})
|
||
}
|
||
|
||
declare global {
|
||
interface Window {
|
||
createServiceMenu?: (options: any) => {
|
||
show: () => void;
|
||
hide: () => void;
|
||
update: () => void;
|
||
destroy: () => void;
|
||
};
|
||
}
|
||
}
|
||
|
||
const Wrapper = ({ children }: { children: React.ReactElement }) => (
|
||
<Suspense
|
||
fallback={
|
||
<ErrorBoundary>
|
||
<Container>
|
||
<VStack>
|
||
<Box mt="150">
|
||
<Spinner
|
||
thickness="4px"
|
||
speed="0.65s"
|
||
emptyColor="gray.200"
|
||
color="blue.500"
|
||
size="xl"
|
||
/>
|
||
</Box>
|
||
</VStack>
|
||
</Container>
|
||
</ErrorBoundary>
|
||
}
|
||
>
|
||
{children}
|
||
</Suspense>
|
||
)
|
||
|
||
// Компонент, который соединяет хлебные крошки с AppHeader
|
||
const HeaderWithBreadcrumbs = ({ serviceMenuContainerRef }: { serviceMenuContainerRef: React.RefObject<HTMLDivElement> }) => {
|
||
const { breadcrumbs } = useBreadcrumbs();
|
||
return <AppHeader serviceMenuContainerRef={serviceMenuContainerRef} breadcrumbs={breadcrumbs} />;
|
||
};
|
||
|
||
interface DashboardProps {
|
||
store: any; // Используем any, поскольку точный тип store не указан
|
||
}
|
||
|
||
export const Dashboard = ({ store }: DashboardProps) => {
|
||
const serviceMenuContainerRef = useRef<HTMLDivElement>(null);
|
||
const serviceMenuInstanceRef = useRef<any>(null);
|
||
const [serviceMenu, setServiceMenu] = useState(false);
|
||
const { colorMode } = useColorMode();
|
||
const { t } = useTranslation();
|
||
|
||
useEffect(() => {
|
||
loadServiceMenu().then(() => {
|
||
setServiceMenu(true)
|
||
}).catch(console.error)
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
// Проверяем, что библиотека загружена и есть контейнер для меню
|
||
if (window.createServiceMenu && serviceMenuContainerRef.current && serviceMenu) {
|
||
// Создаем меню сервисов
|
||
serviceMenuInstanceRef.current = window.createServiceMenu({
|
||
accessToken: keycloak.token,
|
||
apiUrl: 'https://admin.bro-js.ru',
|
||
targetElement: serviceMenuContainerRef.current,
|
||
styles: {
|
||
dotColor: colorMode === 'light' ? '#333' : '#ccc',
|
||
hoverColor: colorMode === 'light' ? '#eee' : '#444',
|
||
backgroundColor: colorMode === 'light' ? '#fff' : '#2D3748',
|
||
textColor: colorMode === 'light' ? '#333' : '#fff',
|
||
},
|
||
translations: {
|
||
menuTitle: t('journal.pl.serviceMenu.title'),
|
||
menuAriaLabel: t('journal.pl.serviceMenu.ariaLabel'),
|
||
}
|
||
});
|
||
}
|
||
|
||
// Очистка при размонтировании
|
||
return () => {
|
||
if (serviceMenuInstanceRef.current) {
|
||
serviceMenuInstanceRef.current.destroy();
|
||
serviceMenuInstanceRef.current = null;
|
||
}
|
||
};
|
||
}, [keycloak.token, serviceMenu, colorMode, t]);
|
||
|
||
return (
|
||
<Provider store={store}>
|
||
<BreadcrumbsProvider>
|
||
<HeaderWithBreadcrumbs serviceMenuContainerRef={serviceMenuContainerRef} />
|
||
<Routes>
|
||
<Route
|
||
path={getNavigationValue('journal.main')}
|
||
element={
|
||
<Wrapper>
|
||
<CourseListPage />
|
||
</Wrapper>
|
||
}
|
||
/>
|
||
<Route
|
||
path={`${getNavigationValue('journal.main')}/lessons-list/:courseId`}
|
||
element={
|
||
<Wrapper>
|
||
<LessonListPage />
|
||
</Wrapper>
|
||
}
|
||
/>
|
||
<Route
|
||
path={`${getNavigationValue('journal.main')}/u/:lessonId/:accessId`}
|
||
element={
|
||
<Wrapper>
|
||
<UserPage />
|
||
</Wrapper>
|
||
}
|
||
/>
|
||
<Route
|
||
path={`${getNavigationValue('journal.main')}/lesson/:courseId/:lessonId`}
|
||
element={
|
||
<Wrapper>
|
||
<LessonDetailsPage />
|
||
</Wrapper>
|
||
}
|
||
/>
|
||
<Route
|
||
path={`${getNavigationValue('journal.main')}${getNavigationValue('link.journal.attendance')}`}
|
||
element={
|
||
<Wrapper>
|
||
<AttendancePage />
|
||
</Wrapper>
|
||
}
|
||
/>
|
||
</Routes>
|
||
</BreadcrumbsProvider>
|
||
</Provider>
|
||
)
|
||
}
|