mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
Merge pull request #34 from BEDOLAGA-DEV/PEDZ
Refactor App component to implement lazy loading for user and admin p…
This commit is contained in:
120
src/App.tsx
120
src/App.tsx
@@ -1,39 +1,46 @@
|
||||
import { lazy, Suspense } from 'react'
|
||||
import { Routes, Route, Navigate, useLocation } from 'react-router-dom'
|
||||
import { useAuthStore } from './store/auth'
|
||||
import Layout from './components/layout/Layout'
|
||||
import PageLoader from './components/common/PageLoader'
|
||||
import { saveReturnUrl } from './utils/token'
|
||||
|
||||
// Auth pages - load immediately (small)
|
||||
import Login from './pages/Login'
|
||||
import TelegramCallback from './pages/TelegramCallback'
|
||||
import TelegramRedirect from './pages/TelegramRedirect'
|
||||
import DeepLinkRedirect from './pages/DeepLinkRedirect'
|
||||
import Dashboard from './pages/Dashboard'
|
||||
import Subscription from './pages/Subscription'
|
||||
import Balance from './pages/Balance'
|
||||
import Referral from './pages/Referral'
|
||||
import Support from './pages/Support'
|
||||
import Profile from './pages/Profile'
|
||||
import AdminTickets from './pages/AdminTickets'
|
||||
import AdminSettings from './pages/AdminSettings'
|
||||
import AdminApps from './pages/AdminApps'
|
||||
import VerifyEmail from './pages/VerifyEmail'
|
||||
import Contests from './pages/Contests'
|
||||
import Polls from './pages/Polls'
|
||||
import Info from './pages/Info'
|
||||
import Wheel from './pages/Wheel'
|
||||
import AdminWheel from './pages/AdminWheel'
|
||||
import AdminTariffs from './pages/AdminTariffs'
|
||||
import AdminServers from './pages/AdminServers'
|
||||
import AdminPanel from './pages/AdminPanel'
|
||||
import AdminDashboard from './pages/AdminDashboard'
|
||||
import AdminBanSystem from './pages/AdminBanSystem'
|
||||
import AdminBroadcasts from './pages/AdminBroadcasts'
|
||||
import AdminPromocodes from './pages/AdminPromocodes'
|
||||
import AdminCampaigns from './pages/AdminCampaigns'
|
||||
import AdminUsers from './pages/AdminUsers'
|
||||
import AdminPayments from './pages/AdminPayments'
|
||||
import AdminPromoOffers from './pages/AdminPromoOffers'
|
||||
import AdminRemnawave from './pages/AdminRemnawave'
|
||||
|
||||
// User pages - lazy load
|
||||
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
||||
const Subscription = lazy(() => import('./pages/Subscription'))
|
||||
const Balance = lazy(() => import('./pages/Balance'))
|
||||
const Referral = lazy(() => import('./pages/Referral'))
|
||||
const Support = lazy(() => import('./pages/Support'))
|
||||
const Profile = lazy(() => import('./pages/Profile'))
|
||||
const Contests = lazy(() => import('./pages/Contests'))
|
||||
const Polls = lazy(() => import('./pages/Polls'))
|
||||
const Info = lazy(() => import('./pages/Info'))
|
||||
const Wheel = lazy(() => import('./pages/Wheel'))
|
||||
|
||||
// Admin pages - lazy load (only for admins)
|
||||
const AdminPanel = lazy(() => import('./pages/AdminPanel'))
|
||||
const AdminTickets = lazy(() => import('./pages/AdminTickets'))
|
||||
const AdminSettings = lazy(() => import('./pages/AdminSettings'))
|
||||
const AdminApps = lazy(() => import('./pages/AdminApps'))
|
||||
const AdminWheel = lazy(() => import('./pages/AdminWheel'))
|
||||
const AdminTariffs = lazy(() => import('./pages/AdminTariffs'))
|
||||
const AdminServers = lazy(() => import('./pages/AdminServers'))
|
||||
const AdminDashboard = lazy(() => import('./pages/AdminDashboard'))
|
||||
const AdminBanSystem = lazy(() => import('./pages/AdminBanSystem'))
|
||||
const AdminBroadcasts = lazy(() => import('./pages/AdminBroadcasts'))
|
||||
const AdminPromocodes = lazy(() => import('./pages/AdminPromocodes'))
|
||||
const AdminCampaigns = lazy(() => import('./pages/AdminCampaigns'))
|
||||
const AdminUsers = lazy(() => import('./pages/AdminUsers'))
|
||||
const AdminPayments = lazy(() => import('./pages/AdminPayments'))
|
||||
const AdminPromoOffers = lazy(() => import('./pages/AdminPromoOffers'))
|
||||
const AdminRemnawave = lazy(() => import('./pages/AdminRemnawave'))
|
||||
|
||||
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const { isAuthenticated, isLoading } = useAuthStore()
|
||||
@@ -73,6 +80,15 @@ function AdminRoute({ children }: { children: React.ReactNode }) {
|
||||
return <Layout>{children}</Layout>
|
||||
}
|
||||
|
||||
// Suspense wrapper for lazy components
|
||||
function LazyPage({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<Suspense fallback={<PageLoader variant="dark" />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Routes>
|
||||
@@ -90,7 +106,7 @@ function App() {
|
||||
path="/"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Dashboard />
|
||||
<LazyPage><Dashboard /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -98,7 +114,7 @@ function App() {
|
||||
path="/subscription"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Subscription />
|
||||
<LazyPage><Subscription /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -106,7 +122,7 @@ function App() {
|
||||
path="/balance"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Balance />
|
||||
<LazyPage><Balance /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -114,7 +130,7 @@ function App() {
|
||||
path="/referral"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Referral />
|
||||
<LazyPage><Referral /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -122,7 +138,7 @@ function App() {
|
||||
path="/support"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Support />
|
||||
<LazyPage><Support /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -130,7 +146,7 @@ function App() {
|
||||
path="/profile"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Profile />
|
||||
<LazyPage><Profile /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -138,7 +154,7 @@ function App() {
|
||||
path="/contests"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Contests />
|
||||
<LazyPage><Contests /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -146,7 +162,7 @@ function App() {
|
||||
path="/polls"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Polls />
|
||||
<LazyPage><Polls /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -154,7 +170,7 @@ function App() {
|
||||
path="/info"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Info />
|
||||
<LazyPage><Info /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -162,7 +178,7 @@ function App() {
|
||||
path="/wheel"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<Wheel />
|
||||
<LazyPage><Wheel /></LazyPage>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
@@ -172,7 +188,7 @@ function App() {
|
||||
path="/admin"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminPanel />
|
||||
<LazyPage><AdminPanel /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -180,7 +196,7 @@ function App() {
|
||||
path="/admin/tickets"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminTickets />
|
||||
<LazyPage><AdminTickets /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -188,7 +204,7 @@ function App() {
|
||||
path="/admin/settings"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminSettings />
|
||||
<LazyPage><AdminSettings /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -196,7 +212,7 @@ function App() {
|
||||
path="/admin/apps"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminApps />
|
||||
<LazyPage><AdminApps /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -204,7 +220,7 @@ function App() {
|
||||
path="/admin/wheel"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminWheel />
|
||||
<LazyPage><AdminWheel /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -212,7 +228,7 @@ function App() {
|
||||
path="/admin/tariffs"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminTariffs />
|
||||
<LazyPage><AdminTariffs /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -220,7 +236,7 @@ function App() {
|
||||
path="/admin/servers"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminServers />
|
||||
<LazyPage><AdminServers /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -228,7 +244,7 @@ function App() {
|
||||
path="/admin/dashboard"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminDashboard />
|
||||
<LazyPage><AdminDashboard /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -236,7 +252,7 @@ function App() {
|
||||
path="/admin/ban-system"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminBanSystem />
|
||||
<LazyPage><AdminBanSystem /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -244,7 +260,7 @@ function App() {
|
||||
path="/admin/broadcasts"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminBroadcasts />
|
||||
<LazyPage><AdminBroadcasts /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -252,7 +268,7 @@ function App() {
|
||||
path="/admin/promocodes"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminPromocodes />
|
||||
<LazyPage><AdminPromocodes /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -260,7 +276,7 @@ function App() {
|
||||
path="/admin/campaigns"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminCampaigns />
|
||||
<LazyPage><AdminCampaigns /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -268,7 +284,7 @@ function App() {
|
||||
path="/admin/users"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminUsers />
|
||||
<LazyPage><AdminUsers /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -276,7 +292,7 @@ function App() {
|
||||
path="/admin/payments"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminPayments />
|
||||
<LazyPage><AdminPayments /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -284,7 +300,7 @@ function App() {
|
||||
path="/admin/promo-offers"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminPromoOffers />
|
||||
<LazyPage><AdminPromoOffers /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
@@ -292,7 +308,7 @@ function App() {
|
||||
path="/admin/remnawave"
|
||||
element={
|
||||
<AdminRoute>
|
||||
<AdminRemnawave />
|
||||
<LazyPage><AdminRemnawave /></LazyPage>
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createContext, useContext, useState, useCallback, ReactNode } from 'react'
|
||||
import { createContext, useContext, useState, useCallback, useRef, useEffect, ReactNode } from 'react'
|
||||
|
||||
interface ToastOptions {
|
||||
type?: 'success' | 'error' | 'info' | 'warning'
|
||||
@@ -29,22 +29,41 @@ export function useToast() {
|
||||
|
||||
export function ToastProvider({ children }: { children: ReactNode }) {
|
||||
const [toasts, setToasts] = useState<Toast[]>([])
|
||||
const timersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map())
|
||||
|
||||
const showToast = useCallback((options: ToastOptions) => {
|
||||
const id = Date.now()
|
||||
const id = Date.now() + Math.random() // Avoid ID collision
|
||||
const toast: Toast = { id, duration: 5000, type: 'info', ...options }
|
||||
|
||||
setToasts(prev => [...prev, toast])
|
||||
|
||||
setTimeout(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setToasts(prev => prev.filter(t => t.id !== id))
|
||||
timersRef.current.delete(id)
|
||||
}, toast.duration)
|
||||
|
||||
timersRef.current.set(id, timer)
|
||||
}, [])
|
||||
|
||||
const removeToast = useCallback((id: number) => {
|
||||
// Clear timer when manually removing
|
||||
const timer = timersRef.current.get(id)
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
timersRef.current.delete(id)
|
||||
}
|
||||
setToasts(prev => prev.filter(t => t.id !== id))
|
||||
}, [])
|
||||
|
||||
// Cleanup all timers on unmount
|
||||
useEffect(() => {
|
||||
const timers = timersRef.current
|
||||
return () => {
|
||||
timers.forEach(timer => clearTimeout(timer))
|
||||
timers.clear()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={{ showToast }}>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react'
|
||||
import { useAuthStore } from '../store/auth'
|
||||
|
||||
const isDev = import.meta.env.DEV
|
||||
|
||||
export interface WSMessage {
|
||||
type: string
|
||||
ticket_id?: number
|
||||
@@ -80,7 +82,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}) {
|
||||
wsRef.current = ws
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('[WS] Connected')
|
||||
if (isDev) console.log('[WS] Connected')
|
||||
setIsConnected(true)
|
||||
reconnectAttemptsRef.current = 0
|
||||
optionsRef.current.onConnect?.()
|
||||
@@ -104,12 +106,12 @@ export function useWebSocket(options: UseWebSocketOptions = {}) {
|
||||
|
||||
optionsRef.current.onMessage?.(message)
|
||||
} catch (e) {
|
||||
console.error('[WS] Failed to parse message:', e)
|
||||
if (isDev) console.error('[WS] Failed to parse message:', e)
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = (event) => {
|
||||
console.log('[WS] Disconnected:', event.code, event.reason)
|
||||
if (isDev) console.log('[WS] Disconnected:', event.code, event.reason)
|
||||
setIsConnected(false)
|
||||
optionsRef.current.onDisconnect?.()
|
||||
|
||||
@@ -121,7 +123,7 @@ export function useWebSocket(options: UseWebSocketOptions = {}) {
|
||||
// Attempt to reconnect if not closed intentionally
|
||||
if (event.code !== 1000 && reconnectAttemptsRef.current < maxReconnectAttempts) {
|
||||
const delay = Math.min(1000 * Math.pow(2, reconnectAttemptsRef.current), 30000)
|
||||
console.log(`[WS] Reconnecting in ${delay}ms (attempt ${reconnectAttemptsRef.current + 1})`)
|
||||
if (isDev) console.log(`[WS] Reconnecting in ${delay}ms (attempt ${reconnectAttemptsRef.current + 1})`)
|
||||
|
||||
reconnectTimeoutRef.current = setTimeout(() => {
|
||||
reconnectAttemptsRef.current++
|
||||
@@ -131,10 +133,10 @@ export function useWebSocket(options: UseWebSocketOptions = {}) {
|
||||
}
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('[WS] Error:', error)
|
||||
if (isDev) console.error('[WS] Error:', error)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[WS] Failed to connect:', e)
|
||||
if (isDev) console.error('[WS] Failed to connect:', e)
|
||||
}
|
||||
}, [accessToken, isAuthenticated, cleanup])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user