Files
journal.pl/src/dashboard.tsx
T

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>
)
}