diff --git a/ospabhost/backend/src/index.ts b/ospabhost/backend/src/index.ts index c17ba97..32f2062 100644 --- a/ospabhost/backend/src/index.ts +++ b/ospabhost/backend/src/index.ts @@ -3,33 +3,38 @@ import cors from 'cors'; import dotenv from 'dotenv'; import authRoutes from './modules/auth/auth.routes'; -// Загружаем переменные окружения из .env файла dotenv.config(); -// Инициализируем приложение Express const app = express(); -// Middleware для CORS -// Это позволяет фронтенду (на другом порту) отправлять запросы на бэкенд -app.use(cors()); +// ИСПРАВЛЕНО: более точная настройка CORS +app.use(cors({ + origin: ['http://localhost:3000', 'http://localhost:5173'], // Vite обычно использует 5173 + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +})); -// Middleware для парсинга JSON -// Это позволяет Express читать данные, которые приходят в теле запроса в формате JSON app.use(express.json()); -// Основной маршрут для проверки работы сервера -app.get('/', (req, res) => { - res.send('Сервер ospab.host запущен!'); +// Добавим логирование для отладки +app.use((req, res, next) => { + console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`); + next(); +}); + +app.get('/', (req, res) => { + res.json({ + message: 'Сервер ospab.host запущен!', + timestamp: new Date().toISOString() + }); }); -// Подключаем наши маршруты для аутентификации -// Все маршруты в authRoutes будут доступны по адресу /api/auth/... app.use('/api/auth', authRoutes); -// Получаем порт из переменных окружения или используем 5000 по умолчанию const PORT = process.env.PORT || 5000; -// Запускаем сервер app.listen(PORT, () => { - console.log(`Сервер работает на порту ${PORT}`); + console.log(`🚀 Сервер запущен на порту ${PORT}`); + console.log(`📊 База данных: ${process.env.DATABASE_URL ? 'подключена' : 'НЕ НАСТРОЕНА'}`); }); \ No newline at end of file diff --git a/ospabhost/frontend/.gitignore b/ospabhost/frontend/.gitignore index a547bf3..ccede5e 100644 --- a/ospabhost/frontend/.gitignore +++ b/ospabhost/frontend/.gitignore @@ -22,3 +22,6 @@ dist-ssr *.njsproj *.sln *.sw? + +.env +.env.* diff --git a/ospabhost/frontend/src/App.tsx b/ospabhost/frontend/src/App.tsx index 0cb68e5..84866d6 100644 --- a/ospabhost/frontend/src/App.tsx +++ b/ospabhost/frontend/src/App.tsx @@ -1,6 +1,6 @@ -// src/app.tsx import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import Pagetempl from './components/pagetempl'; +import DashboardTempl from './components/dashboardtempl'; import Homepage from './pages/index'; import Dashboard from './pages/dashboard/mainpage'; import Loginpage from './pages/login'; @@ -8,23 +8,32 @@ import Registerpage from './pages/register'; import Tariffspage from './pages/tariffs'; import Aboutpage from './pages/about'; import Privateroute from './components/privateroute'; -import { AuthProvider } from './context/authcontext'; // Import AuthProvider +import { AuthProvider } from './context/authcontext'; function App() { return ( - {/* Wrap the entire application with AuthProvider */} + + {/* Обычные страницы с footer */} } /> } /> } /> - } /> } /> } /> + + {/* Дашборд без footer */} + + + + + + } /> ); } -export default App; \ No newline at end of file +export default App; diff --git a/ospabhost/frontend/src/components/dashboardtempl.tsx b/ospabhost/frontend/src/components/dashboardtempl.tsx new file mode 100644 index 0000000..d8b4b25 --- /dev/null +++ b/ospabhost/frontend/src/components/dashboardtempl.tsx @@ -0,0 +1,20 @@ +// frontend/src/components/dashboardtempl.tsx +import React from 'react'; +import Header from './header'; + +interface DashboardTemplProps { + children: React.ReactNode; +} + +const DashboardTempl: React.FC = ({ children }) => { + return ( +
+
+
+ {children} +
+
+ ); +}; + +export default DashboardTempl; \ No newline at end of file diff --git a/ospabhost/frontend/src/pages/dashboard/billing.tsx b/ospabhost/frontend/src/pages/dashboard/billing.tsx index e3b48b2..8fc77ea 100644 --- a/ospabhost/frontend/src/pages/dashboard/billing.tsx +++ b/ospabhost/frontend/src/pages/dashboard/billing.tsx @@ -1,3 +1,4 @@ +// 3. Исправляем frontend/src/pages/dashboard/billing.tsx import { useState } from 'react'; import { Link } from 'react-router-dom'; import QRCode from 'react-qr-code'; @@ -7,8 +8,9 @@ const Billing = () => { const [isPaymentGenerated, setIsPaymentGenerated] = useState(false); const [copyStatus, setCopyStatus] = useState(''); - const cardNumber = process.env.REACT_APP_CARD_NUMBER || ''; - const sbpUrl = process.env.REACT_APP_SBP_QR_URL || ''; + // ИСПРАВЛЕНО: используем правильные переменные окружения для Vite + const cardNumber = import.meta.env.VITE_CARD_NUMBER || ''; + const sbpUrl = import.meta.env.VITE_SBP_QR_URL || ''; const handleGeneratePayment = () => { if (amount <= 0) { @@ -59,38 +61,52 @@ const Billing = () => { ) : (
-

Для пополнения баланса, пожалуйста, переведите сумму **₽{amount}**.

+

+ Для пополнения баланса переведите ₽{amount}. +

Ваш заказ будет обработан вручную после проверки чека.

-
-

Оплата по СБП

-
- + {sbpUrl && ( +
+

Оплата по СБП

+
+ +
+

+ Отсканируйте QR-код через мобильное приложение вашего банка. +

-

Отсканируйте QR-код через мобильное приложение вашего банка.

-
+ )} -
-

Оплата по номеру карты

-

{cardNumber}

- - {copyStatus &&

{copyStatus}

} -
+ {cardNumber && ( +
+

Оплата по номеру карты

+

{cardNumber}

+ + {copyStatus &&

{copyStatus}

} +
+ )}

Важно:

-

После оплаты сделайте скриншот или сохраните чек и отправьте его нам в тикет поддержки, чтобы мы могли подтвердить платёж.

+

+ После оплаты сделайте скриншот или сохраните чек и отправьте его нам в тикет поддержки. +

- После подтверждения ваш баланс будет пополнен. Вы можете перейти в раздел Тикеты, чтобы отправить нам чек. + После подтверждения ваш баланс будет пополнен. Перейдите в раздел{' '} + + Тикеты + + , чтобы отправить нам чек.

)} diff --git a/ospabhost/frontend/src/pages/dashboard/mainpage.tsx b/ospabhost/frontend/src/pages/dashboard/mainpage.tsx index 586d497..6d2177c 100644 --- a/ospabhost/frontend/src/pages/dashboard/mainpage.tsx +++ b/ospabhost/frontend/src/pages/dashboard/mainpage.tsx @@ -1,5 +1,6 @@ +// frontend/src/pages/dashboard/mainpage.tsx import { useState, useEffect } from 'react'; -import { Routes, Route, Link, useNavigate } from 'react-router-dom'; +import { Routes, Route, Link, useNavigate, useLocation } from 'react-router-dom'; import axios from 'axios'; import AuthContext from '../../context/authcontext'; import { useContext } from 'react'; @@ -10,44 +11,55 @@ import Servers from './servers'; import Tickets from './tickets'; import Billing from './billing'; import Settings from './settings'; -import CheckVerification from './checkverification.tsx'; -import TicketResponse from './ticketresponse.tsx'; +import CheckVerification from './checkverification'; +import TicketResponse from './ticketresponse'; const Dashboard = () => { - const [activeTab, setActiveTab] = useState('summary'); const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(true); const navigate = useNavigate(); + const location = useLocation(); const { logout } = useContext(AuthContext); + // Определяем активную вкладку из URL + const getActiveTab = () => { + const path = location.pathname.split('/dashboard/')[1] || ''; + return path === '' ? 'summary' : path; + }; + + const [activeTab, setActiveTab] = useState(getActiveTab()); + + // Обновляем активную вкладку при изменении URL + useEffect(() => { + setActiveTab(getActiveTab()); + }, [location]); + useEffect(() => { const fetchData = async () => { try { const token = localStorage.getItem('access_token'); if (!token) { + console.log('Токен не найден, перенаправляем на логин'); logout(); navigate('/login'); return; } const headers = { Authorization: `Bearer ${token}` }; - const userRes = await axios.get('http://localhost:5000/api/auth/me', { headers }); - // Моделируем остальные данные - const serversRes = { data: { servers: [] } }; - const ticketsRes = { data: { tickets: [] } }; - setUserData({ user: userRes.data.user, - balance: 1500, // Пример - servers: serversRes.data.servers, - tickets: ticketsRes.data.tickets, + balance: 1500, + servers: [], + tickets: [], }); } catch (err) { console.error('Ошибка загрузки данных:', err); - logout(); - navigate('/login'); + if (axios.isAxiosError(err) && err.response?.status === 401) { + logout(); + navigate('/login'); + } } finally { setLoading(false); } @@ -57,53 +69,201 @@ const Dashboard = () => { if (loading) { return ( -
-

Загрузка...

+
+
+
+

Загрузка...

+
); } if (!userData || !userData.user) { - return null; + return ( +
+
+

Ошибка загрузки данных

+ +
+
+ ); } const isOperator = userData.user.operator === 1; return ( -
-
-