внедрены базовые страницы нового функционала

This commit is contained in:
Kayashov.SM
2026-02-02 12:04:53 +04:00
parent bad457e6f6
commit caad2a10a6
16 changed files with 1636 additions and 69 deletions

View File

@@ -0,0 +1,403 @@
import React, { useState } from 'react';
import {
Container,
Typography,
Box,
Drawer,
List,
ListItem,
ListItemText,
Chip,
Select,
MenuItem,
FormControl,
InputLabel,
Button,
Divider,
useMediaQuery,
useTheme,
Paper,
} from '@mui/material';
import { CalendarToday as CalendarIcon, FilterList as FilterIcon } from '@mui/icons-material';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import ruLocale from 'date-fns/locale/ru';
const CHAMPIONSHIP_STAGES = [
{
id: 1,
title: 'SWC Зимний чемпионат',
stage: '2й этап',
date: '2026-02-08',
class: 'Юниоры',
status: 'Идёт',
},
{
id: 2,
title: 'Honda Winter Cup',
stage: '1й этап',
date: '2026-01-31',
class: 'Pro',
status: 'Регистрация открыта',
},
{
id: 3,
title: 'Кубок Покровска (онлайн)',
stage: '1й этап',
date: '2026-02-01',
class: 'Симулятор A',
status: 'Предрегистрация',
},
];
const CalendarPage = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const [viewDate, setViewDate] = useState(new Date()); // Дата для отображения месяца
const [selectedClass, setSelectedClass] = useState('Все');
const [showFilters, setShowFilters] = useState(false);
const [openDrawer, setOpenDrawer] = useState(false);
// Фильтрованные этапы для текущего месяца/класса
const filteredStages = CHAMPIONSHIP_STAGES.filter((stage) => {
const stageDate = new Date(stage.date);
const isSameMonth = stageDate.getMonth() === viewDate.getMonth();
const isSameYear = stageDate.getFullYear() === viewDate.getFullYear();
const classMatch = selectedClass === 'Все' || stage.class === selectedClass;
return isSameMonth && isSameYear && classMatch;
});
// Группируем этапы по дате
const stagesByDate = filteredStages.reduce((acc, stage) => {
const dayKey = new Date(stage.date).toDateString();
acc[dayKey] = acc[dayKey] || [];
acc[dayKey].push(stage);
return acc;
}, {});
// Содержимое drawer для мобильных
const drawerContent = (
<Box sx={{ p: 3, minWidth: 280 }}>
<Typography variant="h6" gutterBottom>
Этапы на {viewDate.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' })}
</Typography>
{filteredStages.length === 0 ? (
<Typography color="text.secondary" sx={{ mt: 2 }}>
Нет этапов в этот день
</Typography>
) : (
<List sx={{ mt: 2 }}>
{filteredStages.map((stage) => (
<ListItem key={stage.id} sx={{ mb: 1, borderBottom: '1px solid', borderColor: 'divider' }}>
<Box sx={{ flexGrow: 1 }}>
<Typography variant="subtitle1" fontWeight="bold">
{stage.title}
</Typography>
<Typography variant="body2" color="text.secondary">
{stage.stage} · {stage.class}
</Typography>
<Box sx={{ mt: 0.5 }}>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: 'info'
}
sx={{ fontSize: '0.8rem' }}
/>
</Box>
</Box>
</ListItem>
))}
</List>
)}
</Box>
);
return (
<Container maxWidth={false} disableGutters sx={{ px: { xs: 1, sm: 3, md: 6 } }}>
{/* Шапка */}
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 4,
flexWrap: 'wrap',
gap: 2
}}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<CalendarIcon color="primary" />
<Typography variant="h4">Календарь чемпионатов</Typography>
</Box>
{/* Фильтры */}
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
<Button
variant="outlined"
startIcon={<FilterIcon />}
onClick={() => setShowFilters(!showFilters)}
size="small"
>
Фильтры
</Button>
{showFilters && (
<FormControl size="small" sx={{ minWidth: 120 }}>
<InputLabel>Класс</InputLabel>
<Select value={selectedClass} onChange={(e) => setSelectedClass(e.target.value)}>
{['Все', 'Юниоры', 'Взрослые', 'Богатыри', '35+', 'Pro', 'Amateur', 'Симулятор A', 'Симулятор B'].map(
(cls) => (
<MenuItem key={cls} value={cls}>
{cls}
</MenuItem>
)
)}
</Select>
</FormControl>
)}
</Box>
</Box>
{/* Основной контент */}
<Box sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', md: '2fr 1fr' },
gap: { xs: 0, md: 4 },
width: '100%',
maxWidth: 1400,
mx: 'auto'
}}>
{/* Календарь */}
<Paper variant="outlined" sx={{ borderRadius: 2, overflow: 'hidden', height: '100%' }}>
<LocalizationProvider dateAdapter={AdapterDateFns} locale={ruLocale}>
<DateCalendar
value={viewDate}
onChange={(newValue) => {
// Не меняем viewDate при клике на день — только навигация по месяцам
if (newValue.getMonth() !== viewDate.getMonth()) {
setViewDate(newValue);
}
}}
showDaysOutsideCurrentMonth
skipDisabledDateSelection
sx={{
height: '100%',
'.MuiDayCalendar-dayButton': {
minHeight: { xs: 80, sm: 100 },
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
p: 1,
},
'.MuiPickersDay-root': {
fontSize: { xs: '1rem', sm: '1.1rem' },
},
// Подсветка дней с событиями
'&.MuiPickersDay-root[data-selected="true"]': {
backgroundColor: 'primary.main',
color: 'white',
},
'&.MuiPickersDay-root:has(.event-chip)': {
border: '2px solid',
borderColor: 'primary.main',
'&:hover': {
borderColor: 'primary.dark',
}
}
}}
dayRenderer={(params) => {
const dayKey = params.day.toDateString();
const events = stagesByDate[dayKey] || [];
return (
<Box sx={{ width: '100%', height: '100%' }}>
<Typography
variant="body2"
sx={{
fontWeight: 500,
color: params.outsideCurrentMonth ? 'text.disabled' : 'inherit',
textAlign: 'center',
}}
>
{params.day.getDate()}
</Typography>
{events.length > 0 && (
<Box
sx={{
mt: 0.5,
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
gap: 0.25,
}}
>
{events.map((event, idx) => (
<Chip
key={idx}
label={event.stage}
size="small"
className="event-chip" // Для CSS-селектора
color={
event.status === 'Идёт'
? 'warning'
: event.status === 'Регистрация открыта'
? 'success'
: 'info'
}
sx={{
backgroundColor:
event.status === 'Идёт'
? 'warning.dark'
: event.status === 'Регистрация открыта'
? 'success.dark'
: 'info.dark',
color: 'white',
fontSize: '0.65rem',
fontWeight: 500,
px: 0.3,
lineHeight: 1.1,
}}
/>
))}
</Box>
)}
</Box>
);
}}
/>
</LocalizationProvider>
</Paper>
{/* Список этапов (только на десктопе) */}
{!isMobile && (
<Box sx={{ overflowY: 'auto', maxHeight: 'calc(100vh - 200px)' }}>
<Paper variant="outlined" sx={{ borderRadius: 2 }}>
<Box sx={{ p: 3 }}>
<Typography variant="h6" gutterBottom>
Этапы на {viewDate.toLocaleDateString('ru-RU', { month: 'long', year: 'numeric' })}
</Typography>
{filteredStages.length === 0 ? (
<Typography color="text.secondary" sx={{ mt: 2 }}>
Нет этапов в выбранном периоде
</Typography>
) : (
filteredStages.map((stage) => (
<Box
key={stage.id}
sx={{
p: 2.5,
borderRadius: 2,
backgroundColor: 'action.hover',
mb: 2,
'&:last-child': { mb: 0 },
}}
>
<Typography
variant="subtitle1"
fontWeight="bold"
noWrap
sx={{ mb: 0.5 }}
>
{stage.title}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
{stage.stage} · {stage.class}
</Typography>
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: 'info'
}
sx={{
backgroundColor:
stage.status === 'Идёт'
? 'warning.dark'
: stage.status === 'Регистрация открыта'
? 'success.dark'
: 'info.dark',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem',
}}
/>
</Box>
<Typography
variant="body2"
color="text.secondary"
sx={{ mt: 1.5 }}
>
{new Date(stage.date).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long',
weekday: 'short',
})}
</Typography>
</Box>
))
)}
</Box>
</Paper>
</Box>
)}
</Box>
{/* Drawer для мобильных */}
{isMobile && (
<Drawer
anchor="bottom"
open={openDrawer}
onClose={() => setOpenDrawer(false)}
PaperProps={{ sx: { borderRadius: '16px 16px 0 0' } }}
>
{drawerContent}
</Drawer>
)}
{/* Кнопка для открытия drawer на мобильных */}
{isMobile && filteredStages.length > 0 && (
<Box sx={{ position: 'fixed', bottom: 16, right: 16 }}>
<Button
variant="contained"
color="primary"
size="large"
onClick={() => setOpenDrawer(true)}
startIcon={<CalendarIcon />}
sx={{
boxShadow: 3,
'&:hover': { boxShadow: 4 },
borderRadius: 24,
}}
>
Этапы на сегодня
</Button>
</Box>
)}
{/* Подвал */}
<Divider sx={{ my: 6 }} />
<Typography
variant="body2"
color="text.secondary"
align="center"
sx={{ mb: 4 }}
>
© 2026 КартХолл. Календарь соревнований.
</Typography>
</Container>
);
};
export default CalendarPage;

View File

@@ -0,0 +1,226 @@
// src/pages/ChampionshipPage.jsx
import React, { useState, useEffect } from 'react';
import {
Container,
Typography,
Paper,
Box,
Button,
Chip,
Divider,
Alert,
CircularProgress
} from '@mui/material';
import { Launch as LaunchIcon, Download as DownloadIcon } from '@mui/icons-material';
import { useParams } from 'react-router-dom';
// Импортируем константы (из предыдущего файла)
import { MOCK_STAGES, STAGE_STATUSES } from '../../../data/constants';
const ChampionshipPage = () => {
const { id } = useParams();
const [championship, setChampionship] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useEffect(() => {
// Имитируем запрос на сервер
const fetchChampionship = async () => {
setLoading(true);
setError(false);
try {
// В реальном проекте тут будет fetch(`/api/championships/${id}`)
// Для примера фильтруем MOCK_STAGES по id этапа (упрощённо)
const stagesForChampionship = MOCK_STAGES.filter(stage => stage.id === Number(id));
if (stagesForChampionship.length === 0) {
setError(true);
} else {
// Формируем данные чемпионата на основе первого подходящего этапа
const stage = stagesForChampionship[0];
setChampionship({
id: stage.id,
title: stage.title,
description: stage.description || 'Информация о чемпионате отсутствует.',
regulationsUrl: '/dummy-regulations.pdf', // Условный URL регламента
stages: MOCK_STAGES.filter(s => s.title === stage.title) // Все этапы этого чемпионата
});
}
} catch (err) {
setError(true);
} finally {
setLoading(false);
}
};
fetchChampionship();
}, [id]);
if (loading) {
return (
<Container maxWidth="lg" sx={{ py: 4, textAlign: 'center' }}>
<CircularProgress />
<Typography sx={{ mt: 2 }}>Загрузка данных чемпионата...</Typography>
</Container>
);
}
if (error || !championship) {
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Alert severity="error" sx={{ mb: 3 }}>
Чемпионат не найден или произошла ошибка при загрузке данных.
</Alert>
<Button variant="contained" onClick={() => window.history.back()}>
Вернуться назад
</Button>
</Container>
);
}
// Сортируем этапы: сначала предстоящие (регистрация открыта / идёт), потом прошедшие
const sortedStages = [...championship.stages].sort((a, b) => {
const isAPast = a.status === STAGE_STATUSES.COMPLETED;
const isBPast = b.status === STAGE_STATUSES.COMPLETED;
if (isAPast && !isBPast) return 1;
if (!isAPast && isBPast) return -1;
return 0; // Сохраняем порядок для этапов одного типа
});
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
{/* Заголовок и основная информация */}
<Typography variant="h4" gutterBottom>
{championship.title}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
{championship.description}
</Typography>
{/* Кнопка загрузки регламента */}
<Button
variant="outlined"
startIcon={<DownloadIcon />}
href={championship.regulationsUrl}
target="_blank"
rel="noopener noreferrer"
sx={{ mb: 4 }}
>
Скачать регламент
</Button>
<Divider sx={{ mb: 4 }} />
{/* Список этапов */}
<Typography variant="h5" gutterBottom>Этапы чемпионата</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
{sortedStages.map((stage) => (
<Paper
key={stage.id}
variant="outlined"
sx={{
p: 3,
'&:hover': { boxShadow: 3 },
transition: 'box-shadow 0.2s'
}}
onClick={() => window.location.replace("/stages/" + stage.id)}
>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
<Typography variant="subtitle1" fontWeight={600}>
{stage.stage}
</Typography>
<Chip
label={stage.status}
color={
stage.status === STAGE_STATUSES.GOING
? 'warning'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === STAGE_STATUSES.GOING
? 'warning.dark'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success.dark'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info.dark'
: 'grey.300',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem'
}}
/>
</Box>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
{new Date(stage.date).toLocaleDateString('ru-RU', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</Typography>
<Typography variant="body2" sx={{ mb: 1 }}>
Место: {stage.location}
</Typography>
{stage.description && (
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
{stage.description}
</Typography>
)}
{/* Бейджи вместо кнопок */}
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
{stage.status === STAGE_STATUSES.REGISTRATION_OPEN && (
<Chip
label="Регистрация открыта"
color="success"
variant="outlined"
icon={<LaunchIcon fontSize="small" />}
/>
)}
{stage.status === STAGE_STATUSES.COMPLETED && (
<Chip
label="Результаты"
color="primary"
variant="outlined"
icon={<LaunchIcon fontSize="small" />}
/>
)}
{(stage.status === STAGE_STATUSES.GOING ||
stage.status === STAGE_STATUSES.PRE_REGISTRATION) && (
<Chip
label={
stage.status === STAGE_STATUSES.GOING
? 'Идёт сейчас'
: 'Предрегистрация'
}
color={stage.status === STAGE_STATUSES.GOING ? 'warning' : 'info'}
variant="outlined"
/>
)}
</Box>
</Paper>
))}
</Box>
<Divider sx={{ my: 4 }} />
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
};
export default ChampionshipPage;

View File

@@ -0,0 +1,195 @@
import React from 'react';
import {
Box,
Button,
Card,
CardActions,
CardContent,
Container,
Grid,
IconButton,
Paper,
Table,
TableBody,
TableCell,
TableRow,
Tooltip,
Typography,
} from '@mui/material';
import {Add as AddIcon, Edit as EditIcon, Visibility as VisibilityIcon} from '@mui/icons-material';
import Divider from "@mui/material/Divider";
// Данные чемпионатов (можно заменить на API-запрос)
const CHAMPIONSHIPS = [
{
id: 1,
title: 'SWC Зимний чемпионат 20252026',
season: 'Зима 20252026',
stages: 5,
status: 'Идёт',
classes: ['Юниоры', 'Взрослые', 'Богатыри', '35+'],
startDate: '18.01.2026',
endDate: '08.03.2026',
},
{
id: 2,
title: 'Honda Winter Cup 2026',
season: 'Зима 2026',
stages: 3,
status: 'Регистрация открыта',
classes: ['Pro', 'Amateur'],
startDate: '31.01.2026',
endDate: '28.02.2026',
},
{
id: 3,
title: 'Кубок Покровска 2026 (онлайн)',
season: '2026',
stages: 4,
status: 'Предрегистрация',
classes: ['Симулятор A', 'Симулятор B'],
startDate: '01.02.2026',
endDate: '25.03.2026',
},
];
const ChampionshipsPage = () => {
return (
<Container maxWidth="xl" sx={{py: 6}}>
{/* Заголовок и кнопка создания */}
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4}}>
<Typography variant="h4">
Все чемпионаты
</Typography>
<Button
variant="contained"
size={'small'}
color="primary"
startIcon={<AddIcon/>}
href="/championships/create"
sx={{px: 3}}
>
Создать чемпионат
</Button>
</Box>
{/* Список чемпионатов */}
<Grid container spacing={4}>
{CHAMPIONSHIPS.map((champ) => (
<Grid item xs={12} sm={6} md={4} key={champ.id}>
<Card variant="outlined" sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between', // Растягивает содержимое, прижимает actions вниз
transition: 'transform 0.2s',
'&:hover': { transform: 'scale(1.02)'
}}}>
<CardContent>
<Box
sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'start', mb: 2}}>
<Box>
<Typography variant="h6">
{champ.title}
</Typography>
<Tooltip title={champ.status}>
<Typography
variant="caption"
sx={{
backgroundColor: champ.status === 'Идёт' ? 'warning.main' :
champ.status === 'Регистрация открыта' ? 'success.main' : 'info.main',
color: 'white',
px: 1,
borderRadius: 1,
whiteSpace: 'nowrap'
}}
>
{champ.status}
</Typography>
</Tooltip>
<Typography variant="subtitle2" color="text.secondary">
{champ.season}
</Typography>
</Box>
</Box>
{/* Таблица с основными данными */}
<Table size="small" sx={{mt: 2}}>
<TableBody>
<TableRow>
<TableCell variant="head">Этапы</TableCell>
<TableCell>{champ.stages}</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Классы</TableCell>
<TableCell>
{champ.classes.join(', ')}
</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Начало</TableCell>
<TableCell>{champ.startDate}</TableCell>
</TableRow>
<TableRow>
<TableCell variant="head">Конец</TableCell>
<TableCell>{champ.endDate}</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end', p: 2 }}>
{/* Действия */}
<Box sx={{display: 'flex', gap: 1}}>
<IconButton
component="a"
href={`/championships/${champ.id}`}
size="small"
color="primary"
title="Посмотреть детали"
>
<VisibilityIcon fontSize="small"/>
</IconButton>
<IconButton
component="a"
href={`/championships/${champ.id}/edit`}
size="small"
color="secondary"
title="Редактировать"
>
<EditIcon fontSize="small"/>
</IconButton>
</Box>
</CardActions>
</Card>
</Grid>
))}
</Grid>
{/* Сообщение, если чемпионатов нет */}
{CHAMPIONSHIPS.length === 0 && (
<Paper sx={{textAlign: 'center', py: 8}}>
<Typography color="text.secondary">
Пока нет ни одного чемпионата. Создайте первый!
</Typography>
<Button
variant="outlined"
sx={{mt: 2}}
href="/championships/create"
>
Создать чемпионат
</Button>
</Paper>
)}
{/* Подвал */}
<Divider sx={{my: 6}}/>
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Управление чемпионатами.
</Typography>
</Container>
);
};
export default ChampionshipsPage;

View File

@@ -1,7 +0,0 @@
import CocktailsPageContent from "./CocktailsPageContent";
export function MenuPage() {
return (
<CocktailsPageContent/>
)
}

View File

@@ -0,0 +1,332 @@
import Grid from "@mui/material/Grid";
import * as React from "react";
import {Card, CardContent} from "@mui/material";
import {useUser} from "../../../hooks/useUser";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Divider from "@mui/material/Divider";
import Container from "@mui/material/Container";
import Avatar from "@mui/material/Avatar";
import {Trophy} from "@phosphor-icons/react";
// Компонент таймера (упрощённый)
const CountdownTimer = ({targetDate}) => {
const [timeLeft, setTimeLeft] = React.useState({});
React.useEffect(() => {
const updateTimer = () => {
const now = new Date().getTime();
const distance = new Date(targetDate).getTime() - now;
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
setTimeLeft({days, hours, minutes, seconds});
};
const interval = setInterval(updateTimer, 1000);
updateTimer();
return () => clearInterval(interval);
}, [targetDate]);
return (
<Typography variant="h6" color="error" sx={{fontWeight: 'bold'}}>
До старта: {timeLeft.days}д {timeLeft.hours}ч {timeLeft.minutes}м {timeLeft.seconds}с
</Typography>
);
};
// Основной компонент приветственного блока
const HomePageContent = () => {
const {user} = useUser();
// Данные чемпионатов (можно подтянуть из API/state)
const championships = [
{
title: 'SWC Зимний чемпионат 20252026',
stage: '2й этап',
date: '08.02.2026',
link: '/swc-registration',
icon: <Trophy fontSize="large"/>,
},
{
title: 'Honda Winter Cup 2026',
stage: '1й этап',
date: '31.01.2026',
link: '/hwc-info',
icon: <Trophy fontSize="large"/>,
},
{
title: 'Кубок Покровска 2026 (онлайн)',
stage: '1й этап',
date: '01.02.2026',
link: '/pokrovsk-sim',
icon: <Trophy fontSize="large"/>,
},
];
// Результаты последнего этапа
const results = {
Юниоры: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
Взрослые: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
Богатыри: ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
'35+': ['Пупкин Петя', 'Иванов Ваня', 'Кот Кирилл'],
};
// Спонсоры (макеты URL)
const sponsors = [
{name: 'Минеральная вода Ульянка', logo: '/sponsors/ulyanka.png'},
{name: 'Gosha Racing Team', logo: '/sponsors/gosha.png'},
{name: 'Diff', logo: '/sponsors/diff.png'},
];
return (
<Container maxWidth="xl" sx={{py: 3}}>
{/* 1. Приветствие */}
<Typography variant="h4" gutterBottom>
Добро пожаловать на платформу «КартХолл»!
</Typography>
<Typography variant="h6" color="text.secondary" gutterBottom sx={{mb: 4}}>
Ваш гид по гоночным чемпионатам, этапам и онлайнсоревнованиям.
</Typography>
{/* 2. Карточки анонсов */}
<Grid container spacing={4} sx={{mb: 6}}>
{championships.map((champ, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Card variant="outlined" sx={{
height: '100%',
transition: 'transform 0.2s',
'&:hover': {transform: 'scale(1.02)'}
}}>
<CardContent>
<Box sx={{display: 'flex', alignItems: 'center', mb: 2}}>
{champ.icon}
<Typography variant="h6" sx={{ml: 1}}>
{champ.title}
</Typography>
</Box>
<Typography color="text.secondary" sx={{mb: 1}}>
{champ.stage} {champ.date}
</Typography>
<Button
variant="contained"
color="primary"
href={champ.link}
sx={{mt: 2}}
>
Подробнее
</Button>
</CardContent>
</Card>
</Grid>
))}
</Grid>
{/* 3. Быстрые действия */}
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 2, mb: 6}}>
<Button variant="contained" color="secondary" href="/register">
Зарегистрироваться на этап
</Button>
<Button variant="outlined" href="/calendar">
Посмотреть календарь всех этапов
</Button>
<Button variant="outlined" href="/rules">
Правила гонок
</Button>
</Box>
{/* 4. Спонсоры */}
<Box sx={{display: 'flex', overflowX: 'auto', py: 2, gap: 3, mb: 4}}>
{sponsors.map((sponsor, idx) => (
<Avatar
key={idx}
src={sponsor.logo}
alt={sponsor.name}
sx={{width: 300, height: 150, borderRadius: '8px'}}
/>
))}
</Box>
<Typography variant="caption" color="text.secondary" sx={{mb: 4}}>
Наши партнёры: поддержка чемпионатов и призов
</Typography>
{/* 5. Прокат */}
<Box sx={{textAlign: 'center', mb: 6}}>
<Typography variant="h5" sx={{mb: 2}}>
Не гоняешь? Попробуй прокат!
</Typography>
<Typography color="text.secondary" sx={{mb: 3}}>
Ощутите адреналин за рулём прокатного карта. Доступно ежедневно с 10:00 до 22:00.
</Typography>
<Button variant="contained" color="success" href="/rent">
Забронировать карта
</Button>
</Box>
{/* 6. Таймер до ближайшего этапа (Honda Winter Cup) */}
<Box sx={{textAlign: 'center', mb: 6}}>
<Typography variant="h5" sx={{mb: 2}}>
Следующий этап стартует уже:
</Typography>
<CountdownTimer targetDate="2026-01-31T14:00:00"/>
</Box>
{/* 7. Результаты последнего этапа */}
<Box sx={{mb: 6}}>
<Typography variant="h5" sx={{mb: 3}}>
Итоги 1го этапа SWC (18.01.2026)
</Typography>
{Object.entries(results).map(([category, winners]) => (
<Box key={category} sx={{mb: 2}}>
<Typography variant="subtitle1" color="primary">
{category}:
</Typography>
<Typography color="text.secondary">
1 место: {winners[0]}, 2 место: {winners[1]}, 3 место: {winners[2]}
</Typography>
</Box>
))}
<Button
variant="outlined"
href="/stages"
sx={{mt: 3}}
>
Все результаты
</Button>
</Box>
{/* Разделитель и подвал */}
<Divider sx={{my: 4}}/>
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
// return (
// <Paper sx={{flexGrow: 1, p: 1}}>
// <Box sx={{mb: 3, p: 2}}>
// <Typography variant="h3" component="div" sx={{flexGrow: 1}}>
// Добро пожаловать на платформу «КартХолл»!
// </Typography>
// <Typography variant="h6" component="div" sx={{flexGrow: 1, mt: 1}}>
// Ваш гид по гоночным чемпионатам, этапам и онлайн‑соревнованиям.
// </Typography>
// </Box>
//
// <Box sx={{p: 2}}>
//
// <Grid spacing={1} rowSpacing={1}>
// {anounce.map((item, index) => {
// return (
// // Карточка анонса
// <Grid size={3}>
// <Paper sx={{p: 2, mb: 1}}>
// <Stack>
// <Typography variant="h5">{item.championship}</Typography>
// </Stack>
// <CardMedia
// sx={{
// loading: "eager",
// borderRadius: 2
// }}
// // onClick={() => handleSelect(row)}
// component="img"
// alt={item.name}
// height="300"
//
// image={item.photo}
// />
// <CardContent sx={{pb: 0, pl: 2, pt: 0}}>
// <Typography variant="h6"
// mt={2}>{item.name} - {item.message} </Typography>
// <Typography> </Typography>
// {/*<CocktailDescription row={row}/>*/}
// </CardContent>
// <CardActions>
// <Button variant="contained" color="primary" component="div"
// // onClick={() => cocktailClient.drinkCocktail(row.id, createSuccess, createError)}
// >
// <LocalBarIcon fontSize='small'/> Регистрация
// </Button>
// </CardActions>
// </Paper>
// </Grid>
// )
// })}
// </Grid>
// </Box>
//
// <Card sx={{p: 2, mt: 3}}>
// {/*todo: под вопросом*/}
// <Typography variant={'h6'}>Быстрые действия</Typography>
// <Stack direction={"row"} spacing={2} sx={{justifyContent: 'center', alignItems: 'center'}}>
// <Button variant={"contained"} size={"large"}>
// Зарегистрироваться на этап
// </Button>
// <Button variant={"contained"} size={"large"}>
// Посмотреть календарь этапов
// </Button>
// </Stack>
// </Card>
//
// <Box sx={{p: 2, my: 3}}>
// <Stack direction={'row'} sx={{my: 1}}>
// {
// sponsors.map((item) => {
// return (
// <Card sx={{m:1}}>
// <CardMedia
// sx={{
// loading: "eager",
// borderRadius: 2
// }}
// // onClick={() => handleSelect(row)}
// component="img"
// alt={item.alt}
// height="60"
//
// image={item.photo}
// />
// </Card>
// )
// })
// }
// </Stack>
// <Typography variant={'h5'}>Наши партнёры: поддержка чемпионатов и призов</Typography>
// </Box>
//
//
//
//
// <Fab sx={{
// alpha: '30%',
// position: 'sticky',
// left: 'calc(100% - 16px)',
// bottom: '16px',
// color: 'common.white',
// bgcolor: blue[600],
// '&:hover': {
// bgcolor: blue[600],
// },
// }}
// onClick={() => window.window.scrollTo(0, 0)}
// aria-label='Expand'
// color='inherit'>
// <UpIcon/>
// </Fab>
// </Paper>
// );
}
export default HomePageContent;

View File

@@ -0,0 +1,7 @@
import HomePageContent from "./HomePageContent";
export function MenuPage() {
return (
<HomePageContent/>
)
}

View File

@@ -0,0 +1,26 @@
export const anounce = [
{
championship: 'SWC Зимний чемпионат 20252026',
name: '2й этап',
date: '08.02.2026',
message: 'Открыта регистрация!',
new: false,
photo: '/assets/background.png'
},
{
championship: 'Honda Winter Cup 2026',
name: '1й этап',
date: '31.01.2026',
message: 'Успейте зарегистрироваться: осталось 12 мест',
new: true,
photo: '/assets/background.png'
},
{
championship: 'Кубок Покровска 2026 (онлайн)',
name: '1й этап',
date: '01.02.2026',
message: 'Участвуйте из дома: подключение через симулятор',
new: true,
photo: '/assets/background.png'
},
]

View File

@@ -0,0 +1,38 @@
export const sponsors = [
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
{
alt: 'Ульянка',
photo: '/assets/logo_ulyanka-1.svg',
link: '#'
},
]

View File

@@ -0,0 +1,137 @@
// src/pages/StagePage.jsx
import React, { useState, useEffect } from 'react';
import {
Container, Typography, Button, Paper, Box, Divider, Alert, Chip
} from '@mui/material';
import { Download as DownloadIcon } from '@mui/icons-material';
import { useParams } from 'react-router-dom';
import {MOCK_STAGES, STAGE_STATUSES} from '../../../data/constants';
const StagePage = () => {
const { id } = useParams();
const [stage, setStage] = useState(null);
const [error, setError] = useState(false);
useEffect(() => {
const foundStage = MOCK_STAGES.find(s => s.id === Number(id));
if (foundStage) {
setStage(foundStage);
} else {
setError(true);
}
}, [id]);
if (error) {
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Alert severity="error" sx={{ mb: 3 }}>
Этап не найден.
</Alert>
<Button variant="contained" onClick={() => window.history.back()}>
Вернуться назад
</Button>
</Container>
);
}
if (!stage) {
return null; // или спиннер
}
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Typography variant="h4" gutterBottom>{stage.title}</Typography>
<Typography variant="h6" color="text.secondary" gutterBottom>
{stage.stage}
</Typography>
<Paper sx={{ p: 4, mb: 4 }}>
<Typography variant="h5" gutterBottom>Информация об этапе</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 3 }}>
<Box>
<Typography variant="subtitle2" color="text.secondary">
Дата
</Typography>
<Typography>
{new Date(stage.date).toLocaleDateString('ru-RU', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric'
})}
</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">
Место проведения
</Typography>
<Typography>{stage.location}</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">
Класс
</Typography>
<Typography>{stage.class}</Typography>
</Box>
<Box>
<Typography variant="subtitle2" color="text.secondary">
Статус
</Typography>
<Chip
label={stage.status}
color={
stage.status === STAGE_STATUSES.GOING
? 'warning'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === STAGE_STATUSES.GOING
? 'warning.dark'
: stage.status === STAGE_STATUSES.REGISTRATION_OPEN
? 'success.dark'
: stage.status === STAGE_STATUSES.PRE_REGISTRATION
? 'info.dark'
: 'grey.300',
color: 'white',
fontWeight: 500,
fontSize: '0.8rem'
}}
/>
</Box>
</Box>
<Divider sx={{ my: 3 }} />
<Typography variant="body1" paragraph>
{stage.description}
</Typography>
{stage.registrationLink && (
<Button
variant="contained"
color="success"
href={stage.registrationLink}
target="_blank"
startIcon={<DownloadIcon />}
sx={{ mt: 2 }}
>
Перейти на регистрацию
</Button>
)}
</Paper>
<Divider sx={{ my: 4 }} />
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
};
export default StagePage;

View File

@@ -0,0 +1,230 @@
import React, { useState, useEffect } from 'react';
import {
Container,
Typography,
Paper,
Table,
TableHead,
TableRow,
TableCell,
TableBody,
TableContainer,
Select,
MenuItem,
InputLabel,
FormControl,
Box,
Pagination,
Divider, Chip
} from '@mui/material';
import { Sort as SortIcon } from '@mui/icons-material';
// Моковые данные этапов
const MOCK_STAGES = [
{
id: 1,
title: 'SWC Зимний чемпионат',
stage: '2й этап',
date: '2026-02-08',
class: 'Юниоры',
status: 'Идёт',
},
{
id: 2,
title: 'Honda Winter Cup',
stage: '1й этап',
date: '2026-01-31',
class: 'Pro',
status: 'Регистрация открыта',
},
{
id: 3,
title: 'Кубок Покровска (онлайн)',
stage: '1й этап',
date: '2026-02-01',
class: 'Симулятор A',
status: 'Предрегистрация',
},
{
id: 4,
title: 'Гран-при Урала',
stage: 'Финальный этап',
date: '2026-03-15',
class: 'Взрослые',
status: 'Предрегистрация',
},
{
id: 5,
title: 'Открытый кубок Москвы',
stage: 'Квалификационный раунд',
date: '2026-01-20',
class: 'Amateur',
status: 'Завершено',
},
// Добавим ещё для демонстрации пагинации
{ id: 6, title: 'Этап 6', stage: 'Тест', date: '2026-04-01', class: 'Pro', status: 'Регистрация открыта' },
{ id: 7, title: 'Этап 7', stage: 'Тест', date: '2026-05-01', class: 'Юниоры', status: 'Идёт' },
{ id: 8, title: 'Этап 8', stage: 'Тест', date: '2026-06-01', class: 'Взрослые', status: 'Предрегистрация' },
];
const StagesPage = () => {
const [page, setPage] = useState(1);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [sortOrder, setSortOrder] = useState('asc');
const [filteredStages, setFilteredStages] = useState([]);
useEffect(() => {
let sorted = [...MOCK_STAGES];
sorted.sort((a, b) => {
const dateA = new Date(a.date);
const dateB = new Date(b.date);
return sortOrder === 'asc' ? dateA - dateB : dateB - dateA;
});
setFilteredStages(sorted);
}, [sortOrder]);
const handlePageChange = (event, newPage) => {
setPage(newPage);
};
const handleRowsPerPageChange = (event) => {
setRowsPerPage(Number(event.target.value));
setPage(1);
};
const currentStages = filteredStages.slice(
(page - 1) * rowsPerPage,
page * rowsPerPage
);
// Обработчик клика по строке
const handleRowClick = (stage) => {
// Здесь можно:
// - перенаправить на страницу этапа: navigate(`/stages/${stage.id}`)
// - открыть модалку с деталями
// - показать alert (пример ниже)
alert(`
Этап: ${stage.title}
Дата: ${new Date(stage.date).toLocaleDateString('ru-RU')}
Статус: ${stage.status}
Описание: ${stage.description}
`);
};
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Typography variant="h4" gutterBottom>
Этапы соревнований
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 3 }}>
<FormControl size="small">
<InputLabel>Сортировка</InputLabel>
<Select
value={sortOrder}
onChange={(e) => setSortOrder(e.target.value)}
startAdornment={<SortIcon sx={{ ml: 1 }} />}
>
<MenuItem value="asc">По возрастанию даты</MenuItem>
<MenuItem value="desc">По убыванию даты</MenuItem>
</Select>
</FormControl>
<FormControl size="small">
<InputLabel>Строк на странице</InputLabel>
<Select
value={rowsPerPage}
onChange={handleRowsPerPageChange}
>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={10}>10</MenuItem>
<MenuItem value={20}>20</MenuItem>
</Select>
</FormControl>
</Box>
<TableContainer component={Paper} variant="outlined">
<Table aria-label="таблица этапов">
<TableHead>
<TableRow>
<TableCell>Название</TableCell>
<TableCell>Этап</TableCell>
<TableCell>Дата</TableCell>
<TableCell>Класс</TableCell>
<TableCell>Статус</TableCell>
</TableRow>
</TableHead>
<TableBody>
{currentStages.map((stage) => (
<TableRow
key={stage.id}
sx={{
'&:hover': {
backgroundColor: 'action.hover',
cursor: 'pointer'
}
}}
onClick={() => handleRowClick(stage)}
>
<TableCell>{stage.title}</TableCell>
<TableCell>{stage.stage}</TableCell>
<TableCell>
{new Date(stage.date).toLocaleDateString('ru-RU')}
</TableCell>
<TableCell>{stage.class}</TableCell>
<TableCell>
<Chip
label={stage.status}
size="small"
color={
stage.status === 'Идёт'
? 'warning'
: stage.status === 'Регистрация открыта'
? 'success'
: stage.status === 'Предрегистрация'
? 'info'
: 'default'
}
sx={{
backgroundColor:
stage.status === 'Идёт'
? 'warning.dark'
: stage.status === 'Регистрация открыта'
? 'success.dark'
: stage.status === 'Предрегистрация'
? 'info.dark'
: 'grey.300',
color: 'white',
fontSize: '0.8rem',
}}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="body2" color="text.secondary">
Показано {currentStages.length} из {filteredStages.length} этапов
</Typography>
<Pagination
count={Math.ceil(filteredStages.length / rowsPerPage)}
page={page}
onChange={handlePageChange}
color="primary"
size="large"
/>
</Box>
<Divider sx={{ my: 4 }} />
<Typography variant="body2" color="text.secondary" align="center">
© 2026 КартХолл. Все права защищены.
</Typography>
</Container>
);
};
export default StagesPage;

View File

@@ -26,7 +26,7 @@ export function IngredientCard({row, value, infoHandler, changeHandler}) {
<IconButton size='small' onClick={() => infoHandler(row)}>
<InfoRoundedIcon/>
</IconButton>
<IconButton size='small' href={`${paths.bar.ingredientEdit}?id=${row.id}`}>
<IconButton size='small' href={`${paths.stg.stages}?id=${row.id}`}>
<EditIcon/>
</IconButton>
</Stack>

View File

@@ -8,6 +8,10 @@ import {List as ListIcon} from '@phosphor-icons/react/dist/ssr/List';
import {usePopover} from "../../hooks/usePopover";
import {MobileNav} from "./MobileNav";
import {UserPopover} from "../core/UserPopover";
import Button from "@mui/material/Button";
import {renderNavItems} from "./NavItem";
import {navItems} from "../../navItems";
import {useLocation} from "react-router-dom";
// import Tooltip from "@mui/material/Tooltip";
// import {Badge} from "@mui/material";
// import {useAlert} from "../../hooks/useAlert";
@@ -15,6 +19,8 @@ import {UserPopover} from "../core/UserPopover";
export function MainNav() {
const [openNav, setOpenNav] = React.useState(false);
const userPopover = usePopover();
const location = useLocation();
const pathname = location.pathname;
return (
<>
@@ -32,9 +38,12 @@ export function MainNav() {
<Stack direction="row" spacing={3}
sx={{alignItems: 'center', justifyContent: 'space-between', minHeight: '64px', px: 2}}>
<Stack sx={{alignItems: 'center'}} direction="row" spacing={3}>
<IconButton onClick={() => setOpenNav(true)} sx={{display: {xl: 'none'}}}>
<IconButton onClick={() => setOpenNav(true)} sx={{display: {sm: 'none'}}}>
<ListIcon/>
</IconButton>
<Box component="nav" sx={{flex: '1 1 auto', p: 1}}>
{renderNavItems({items: navItems, pathname: pathname, direction: 'row'})}
</Box>
</Stack>
<Stack sx={{alignItems: 'center'}} direction="row" spacing={2}>
<Avatar onClick={userPopover.handleOpen} ref={userPopover.anchorRef} src="/assets/avatar.png"

View File

@@ -5,7 +5,7 @@ import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import {Link} from "react-router-dom";
export function renderNavItems({items = [], pathname}) {
export function renderNavItems({items = [], pathname, direction}) {
const children = items.reduce((acc, curr) => {
const {key, ...item} = curr;
acc.push(<NavItem key={key} pathname={pathname} {...item} />);
@@ -13,7 +13,7 @@ export function renderNavItems({items = [], pathname}) {
}, []);
return (
<Stack key={"stack-NavItem-key"} component="ul" spacing={1} sx={{listStyle: 'none', m: 0, p: 0}}>
<Stack key={"stack-NavItem-key"} component="ul" spacing={1} sx={{listStyle: 'none', m: 0, p: 0}} direction={direction}>
{children}
</Stack>
);

View File

@@ -7,15 +7,6 @@ import {navItems} from "../../navItems";
import React, {useEffect, useState} from "react";
import {useLocation} from "react-router-dom";
import {useUser} from "../../hooks/useUser";
import Typography from "@mui/material/Typography";
function renderSpecialItems(items, label, pathname) {
return (
<Box>
{renderNavItems({items: items, pathname: pathname})}
</Box>
)
}
export function NavigationMenu() {
const location = useLocation();
@@ -23,17 +14,10 @@ export function NavigationMenu() {
const {user} = useUser();
const [items, setItems] = useState(null)
const userChild = navItems.filter((item) => !item.forBarmen && !item.forAdmin)
const barmenChild = navItems.filter((item) => item.forBarmen)
const adminChild = navItems.filter((item) => item.forAdmin)
useEffect(() => {
const role = !user ? "USER" : Object.keys(user).length === 0 ? "USER" : user.role
const newState = (
<Box component="nav" sx={{flex: '1 1 auto', p: '12px'}}>
{renderNavItems({items: userChild, pathname: pathname})}
{role !== "USER" && renderSpecialItems(barmenChild, "Для бармена:", pathname)}
{role === "ADMIN" && renderSpecialItems(adminChild, "Для админа", pathname)}
{renderNavItems({items: navItems, pathname: pathname, direction: 'column'})}
</Box>
)
setItems(newState)

View File

@@ -1,19 +1,18 @@
import {Route, Routes} from "react-router-dom";
import {paths} from "../path";
import {useAuth} from "../hooks/useAuth";
import NotFoundPage from "./pages/notFound/NotFoundPage";
import {UserLayout} from "./layout/UserLayout";
import {HomeRedirect} from "./HomeRedirect";
import {PublicLayout} from "./layout/PublicLayout";
import LoginPage from "./pages/auth/sign-in/loginPage";
import {TelegramCode} from "./pages/auth/sign-in/telegram-code";
import {IngredientsPage} from "./pages/ingredients/IngredientsPage";
import {MenuPage} from "./pages/cocktails/MenuPage";
import {EditIngredientPage} from "./pages/ingredients/EditIngredientPage";
import {EditCocktailPage} from "./pages/cocktails/EditCocktailPage";
import {paths} from "../../path";
import {useAuth} from "../../hooks/useAuth";
import NotFoundPage from "../../app/pages/notFound/NotFoundPage";
import {UserLayout} from "../../app/layout/UserLayout";
import {PublicLayout} from "../../app/layout/PublicLayout";
import LoginPage from "../../app/pages/auth/sign-in/loginPage";
import {TelegramCode} from "../../app/pages/auth/sign-in/telegram-code";
import {MenuPage} from "../../app/pages/home/MenuPage";
import {useEffect, useState} from "react";
import {BarChangePage} from "./pages/BarChangePage";
import {CalcPage} from "./pages/calc/CalcPage";
import ChampionshipsPage from "../../app/pages/championship/ChampionshipsPage";
import CalendarPage from "../../app/pages/calendar/CalendarPage";
import StagesPage from "../../app/pages/stages/StagesPage";
import ChampionshipPage from "../../app/pages/championship/ChampionshipPage";
import StagePage from "../../app/pages/stages/StagePage";
export function NavigationRoutes() {
const {auth} = useAuth();
@@ -51,9 +50,10 @@ function ElementProvider({isPrivate, children}) {
const authPages = [
{
children: (<HomeRedirect auth={true}/>),
isPrivate: false,
path: paths.home,
isPrivate: true,
children: (<MenuPage/>),
exact: true,
},
{
path: paths.auth.signIn,
@@ -61,37 +61,29 @@ const authPages = [
isPrivate: false,
},
{
path: paths.bar.calc,
children: (<CalcPage/>),
isPrivate: true,
path: paths.chp.championships,
isPrivate: true,
children: (<ChampionshipsPage/>),
},
{
path: paths.dashboard.overview,
path: paths.chp.championship,
isPrivate: true,
children: (<MenuPage/>),
exact: true,
children: (<ChampionshipPage/>),
},
{
path: paths.bar.list,
path: paths.calendar,
isPrivate: true,
children: (<BarChangePage/>),
children: (<CalendarPage/>)
},
{
path: paths.bar.ingredients,
path: paths.stg.stages,
isPrivate: true,
children: (<IngredientsPage/>)
children: (<StagesPage/>)
},
{
path: paths.bar.ingredientEdit,
path: paths.stg.stage,
isPrivate: true,
forAdmin: true,
children: (<EditIngredientPage/>)
},
{
path: paths.bar.cocktailEdit,
isPrivate: true,
forAdmin: true,
children: (<EditCocktailPage/>)
children: (<StagePage/>)
},
{
path: paths.notFound,
@@ -102,16 +94,11 @@ const authPages = [
const guestPages = [
{
path: paths.dashboard.overview,
path: paths.home,
isPrivate: true,
children: (<MenuPage/>),
exact: true,
},
{
children: (<HomeRedirect auth={true}/>),
isPrivate: false,
path: paths.home,
},
{
path: paths.auth.tg,
isPrivate: false,