feat: migrate front_minimal from Next.js to Vite + React SPA

- package.json: replace next scripts with vite dev/build/preview,
  add react-router-dom + vite/plugin-react/svgr devDeps, remove next + @mui/material-nextjs
- vite.config.js: add NEXT_PUBLIC_* → process.env define map for backward compat,
  add rollup manual chunks (mui, fullcalendar), loadEnv support
- front_minimal/.env: add VITE_* prefix vars alongside legacy NEXT_PUBLIC_*
- routes/sections.jsx: replace 691-line template routes with 160-line platform-only router
- routes/paths.js: trim to platform paths only (no mock IDs, no template pages)
- app.jsx: remove CheckoutProvider (not needed)
- theme-provider.jsx: remove AppRouterCacheProvider from @mui/material-nextjs
- routes/hooks: replace next/navigation re-exports with react-router-dom wrappers
  (useRouter → useNavigate adapter, useSearchParams, usePathname, useParams)
- routes/components/router-link.jsx: Link from react-router-dom
- sections: replace all next/navigation imports with react-router-dom
- analytics-view, my-progress-view: replace next/dynamic with direct import (no SSR)
- Remove all 'use client' directives (231 files) — not needed in Vite SPA
- Build: vite build ✓ in ~8s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dev Server 2026-03-09 17:04:53 +03:00
parent f679f0c0f4
commit b55c8dc602
38 changed files with 251 additions and 855 deletions

13
front_minimal/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/favicon/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Platform</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@ -1,22 +1,20 @@
{ {
"name": "@minimal-kit/next-js", "name": "platform-frontend",
"author": "Minimals", "author": "Platform",
"version": "6.0.1", "version": "1.0.0",
"description": "Next & JavaScript", "description": "Platform frontend — Vite + React",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -p 3032", "dev": "vite --port 3032",
"start": "next start -p 3032", "build": "vite build",
"build": "next build", "preview": "vite preview --port 3032",
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"",
"fm:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"", "fm:check": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"",
"fm:fix": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"", "fm:fix": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
"rm:all": "rm -rf node_modules .next out dist build", "rm:all": "rm -rf node_modules dist .vite",
"re:start": "yarn rm:all && yarn install && yarn dev", "re:start": "yarn rm:all && yarn install && yarn dev",
"re:build": "yarn rm:all && yarn install && yarn build", "re:build": "yarn rm:all && yarn install && yarn build"
"re:build-npm": "npm run rm:all && npm install && npm run build",
"start:out": "npx serve@latest out -p 3032"
}, },
"dependencies": { "dependencies": {
"@auth0/auth0-react": "^2.2.4", "@auth0/auth0-react": "^2.2.4",
@ -45,7 +43,6 @@
"@livekit/components-styles": "^1.2.0", "@livekit/components-styles": "^1.2.0",
"@mui/lab": "^5.0.0-alpha.170", "@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@mui/material-nextjs": "^5.15.11",
"@mui/x-data-grid": "^7.7.0", "@mui/x-data-grid": "^7.7.0",
"@mui/x-date-pickers": "^7.7.0", "@mui/x-date-pickers": "^7.7.0",
"@mui/x-tree-view": "^7.7.0", "@mui/x-tree-view": "^7.7.0",
@ -81,7 +78,6 @@
"lowlight": "^3.1.0", "lowlight": "^3.1.0",
"mapbox-gl": "^3.4.0", "mapbox-gl": "^3.4.0",
"mui-one-time-password-input": "^2.0.2", "mui-one-time-password-input": "^2.0.2",
"next": "^14.2.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-apexcharts": "^1.4.1", "react-apexcharts": "^1.4.1",
@ -108,8 +104,9 @@
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"devDependencies": { "devDependencies": {
"@svgr/webpack": "^8.1.0",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.7.0",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
@ -122,6 +119,9 @@
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-unused-imports": "^3.2.0", "eslint-plugin-unused-imports": "^3.2.0",
"prettier": "^3.3.2", "prettier": "^3.3.2",
"typescript": "^5.4.5" "react-router-dom": "^6.30.3",
"typescript": "^5.4.5",
"vite": "^5.4.21",
"vite-plugin-svgr": "^4.5.0"
} }
} }

View File

@ -9,8 +9,6 @@ import { ProgressBar } from 'src/components/progress-bar';
import { MotionLazy } from 'src/components/animate/motion-lazy'; import { MotionLazy } from 'src/components/animate/motion-lazy';
import { SettingsDrawer, defaultSettings, SettingsProvider } from 'src/components/settings'; import { SettingsDrawer, defaultSettings, SettingsProvider } from 'src/components/settings';
import { CheckoutProvider } from 'src/sections/checkout/context';
import { AuthProvider } from 'src/auth/context/jwt'; import { AuthProvider } from 'src/auth/context/jwt';
import { Router } from 'src/routes/sections'; import { Router } from 'src/routes/sections';
@ -26,12 +24,10 @@ export default function App() {
<SettingsProvider settings={defaultSettings} caches="localStorage"> <SettingsProvider settings={defaultSettings} caches="localStorage">
<ThemeProvider> <ThemeProvider>
<MotionLazy> <MotionLazy>
<CheckoutProvider>
<Snackbar /> <Snackbar />
<ProgressBar /> <ProgressBar />
<SettingsDrawer /> <SettingsDrawer />
<Router /> <Router />
</CheckoutProvider>
</MotionLazy> </MotionLazy>
</ThemeProvider> </ThemeProvider>
</SettingsProvider> </SettingsProvider>

View File

@ -1,3 +1 @@
import RouterLink from 'next/link'; export { Link as RouterLink } from 'react-router-dom';
export { RouterLink };

View File

@ -1 +1 @@
export { useParams } from 'next/navigation'; export { useParams } from 'react-router-dom';

View File

@ -1 +1,5 @@
export { usePathname } from 'next/navigation'; import { useLocation } from 'react-router-dom';
export function usePathname() {
return useLocation().pathname;
}

View File

@ -1 +1,14 @@
export { useRouter } from 'next/navigation'; import { useNavigate } from 'react-router-dom';
// Thin wrapper matching Next.js useRouter API used in the codebase
export function useRouter() {
const navigate = useNavigate();
return {
push: (href) => navigate(href),
replace: (href) => navigate(href, { replace: true }),
back: () => navigate(-1),
forward: () => navigate(1),
refresh: () => window.location.reload(),
prefetch: () => {},
};
}

View File

@ -1 +1 @@
export { useSearchParams } from 'next/navigation'; export { useSearchParams } from 'react-router-dom';

View File

@ -1,16 +1,5 @@
import { paramCase } from 'src/utils/change-case';
import { _id, _postTitles } from 'src/_mock/assets';
// ----------------------------------------------------------------------
const MOCK_ID = _id[1];
const MOCK_TITLE = _postTitles[2];
const ROOTS = { const ROOTS = {
AUTH: '/auth', AUTH: '/auth',
AUTH_DEMO: '/auth-demo',
DASHBOARD: '/dashboard', DASHBOARD: '/dashboard',
}; };
@ -18,43 +7,10 @@ const ROOTS = {
export const paths = { export const paths = {
videoCall: '/video-call', videoCall: '/video-call',
comingSoon: '/coming-soon', page404: '/404',
maintenance: '/maintenance',
pricing: '/pricing', // Auth
payment: '/payment',
about: '/about-us',
contact: '/contact-us',
faqs: '/faqs',
page403: '/error/403',
page404: '/error/404',
page500: '/error/500',
components: '/components',
docs: 'https://docs.minimals.cc',
changelog: 'https://docs.minimals.cc/changelog',
zoneStore: 'https://mui.com/store/items/zone-landing-page/',
minimalStore: 'https://mui.com/store/items/minimal-dashboard/',
freeUI: 'https://mui.com/store/items/minimal-dashboard-free/',
figma: 'https://www.figma.com/design/cAPz4pYPtQEXivqe11EcDE/%5BPreview%5D-Minimal-Web.v6.0.0',
product: {
root: `/product`,
checkout: `/product/checkout`,
details: (id) => `/product/${id}`,
demo: { details: `/product/${MOCK_ID}` },
},
post: {
root: `/post`,
details: (title) => `/post/${paramCase(title)}`,
demo: { details: `/post/${paramCase(MOCK_TITLE)}` },
},
// AUTH
auth: { auth: {
amplify: {
signIn: `${ROOTS.AUTH}/amplify/sign-in`,
verify: `${ROOTS.AUTH}/amplify/verify`,
signUp: `${ROOTS.AUTH}/amplify/sign-up`,
updatePassword: `${ROOTS.AUTH}/amplify/update-password`,
resetPassword: `${ROOTS.AUTH}/amplify/reset-password`,
},
jwt: { jwt: {
signIn: `${ROOTS.AUTH}/jwt/sign-in`, signIn: `${ROOTS.AUTH}/jwt/sign-in`,
signUp: `${ROOTS.AUTH}/jwt/sign-up`, signUp: `${ROOTS.AUTH}/jwt/sign-up`,
@ -62,140 +18,25 @@ export const paths = {
resetPassword: `${ROOTS.AUTH}/jwt/reset-password`, resetPassword: `${ROOTS.AUTH}/jwt/reset-password`,
verifyEmail: `${ROOTS.AUTH}/jwt/verify-email`, verifyEmail: `${ROOTS.AUTH}/jwt/verify-email`,
}, },
firebase: {
signIn: `${ROOTS.AUTH}/firebase/sign-in`,
verify: `${ROOTS.AUTH}/firebase/verify`,
signUp: `${ROOTS.AUTH}/firebase/sign-up`,
resetPassword: `${ROOTS.AUTH}/firebase/reset-password`,
}, },
auth0: {
signIn: `${ROOTS.AUTH}/auth0/sign-in`, // Dashboard
},
supabase: {
signIn: `${ROOTS.AUTH}/supabase/sign-in`,
verify: `${ROOTS.AUTH}/supabase/verify`,
signUp: `${ROOTS.AUTH}/supabase/sign-up`,
updatePassword: `${ROOTS.AUTH}/supabase/update-password`,
resetPassword: `${ROOTS.AUTH}/supabase/reset-password`,
},
},
authDemo: {
split: {
signIn: `${ROOTS.AUTH_DEMO}/split/sign-in`,
signUp: `${ROOTS.AUTH_DEMO}/split/sign-up`,
resetPassword: `${ROOTS.AUTH_DEMO}/split/reset-password`,
updatePassword: `${ROOTS.AUTH_DEMO}/split/update-password`,
verify: `${ROOTS.AUTH_DEMO}/split/verify`,
},
centered: {
signIn: `${ROOTS.AUTH_DEMO}/centered/sign-in`,
signUp: `${ROOTS.AUTH_DEMO}/centered/sign-up`,
resetPassword: `${ROOTS.AUTH_DEMO}/centered/reset-password`,
updatePassword: `${ROOTS.AUTH_DEMO}/centered/update-password`,
verify: `${ROOTS.AUTH_DEMO}/centered/verify`,
},
},
// DASHBOARD
dashboard: { dashboard: {
root: ROOTS.DASHBOARD, root: ROOTS.DASHBOARD,
mail: `${ROOTS.DASHBOARD}/mail`,
chat: `${ROOTS.DASHBOARD}/chat`,
blank: `${ROOTS.DASHBOARD}/blank`,
kanban: `${ROOTS.DASHBOARD}/kanban`,
calendar: `${ROOTS.DASHBOARD}/schedule`, calendar: `${ROOTS.DASHBOARD}/schedule`,
homework: `${ROOTS.DASHBOARD}/homework`, homework: `${ROOTS.DASHBOARD}/homework`,
materials: `${ROOTS.DASHBOARD}/materials`, materials: `${ROOTS.DASHBOARD}/materials`,
students: `${ROOTS.DASHBOARD}/students`, students: `${ROOTS.DASHBOARD}/students`,
notifications: `${ROOTS.DASHBOARD}/notifications`, notifications: `${ROOTS.DASHBOARD}/notifications`,
board: `${ROOTS.DASHBOARD}/board`, board: `${ROOTS.DASHBOARD}/board`,
referrals: `${ROOTS.DASHBOARD}/referrals`,
profile: `${ROOTS.DASHBOARD}/profile`,
children: `${ROOTS.DASHBOARD}/children`,
childrenProgress: `${ROOTS.DASHBOARD}/children-progress`,
myProgress: `${ROOTS.DASHBOARD}/my-progress`,
payment: `${ROOTS.DASHBOARD}/payment-platform`,
chatPlatform: `${ROOTS.DASHBOARD}/chat-platform`, chatPlatform: `${ROOTS.DASHBOARD}/chat-platform`,
analytics: `${ROOTS.DASHBOARD}/analytics`, analytics: `${ROOTS.DASHBOARD}/analytics`,
feedback: `${ROOTS.DASHBOARD}/feedback`, feedback: `${ROOTS.DASHBOARD}/feedback`,
fileManager: `${ROOTS.DASHBOARD}/file-manager`, profile: `${ROOTS.DASHBOARD}/profile`,
permission: `${ROOTS.DASHBOARD}/permission`, referrals: `${ROOTS.DASHBOARD}/referrals`,
general: { payment: `${ROOTS.DASHBOARD}/payment-platform`,
app: `${ROOTS.DASHBOARD}/app`, children: `${ROOTS.DASHBOARD}/children`,
ecommerce: `${ROOTS.DASHBOARD}/ecommerce`, childrenProgress: `${ROOTS.DASHBOARD}/children-progress`,
analytics: `${ROOTS.DASHBOARD}/analytics`, myProgress: `${ROOTS.DASHBOARD}/my-progress`,
banking: `${ROOTS.DASHBOARD}/banking`,
booking: `${ROOTS.DASHBOARD}/booking`,
file: `${ROOTS.DASHBOARD}/file`,
course: `${ROOTS.DASHBOARD}/course`,
},
user: {
root: `${ROOTS.DASHBOARD}/user`,
new: `${ROOTS.DASHBOARD}/user/new`,
list: `${ROOTS.DASHBOARD}/user/list`,
cards: `${ROOTS.DASHBOARD}/user/cards`,
profile: `${ROOTS.DASHBOARD}/user/profile`,
account: `${ROOTS.DASHBOARD}/user/account`,
edit: (id) => `${ROOTS.DASHBOARD}/user/${id}/edit`,
demo: {
edit: `${ROOTS.DASHBOARD}/user/${MOCK_ID}/edit`,
},
},
product: {
root: `${ROOTS.DASHBOARD}/product`,
new: `${ROOTS.DASHBOARD}/product/new`,
details: (id) => `${ROOTS.DASHBOARD}/product/${id}`,
edit: (id) => `${ROOTS.DASHBOARD}/product/${id}/edit`,
demo: {
details: `${ROOTS.DASHBOARD}/product/${MOCK_ID}`,
edit: `${ROOTS.DASHBOARD}/product/${MOCK_ID}/edit`,
},
},
invoice: {
root: `${ROOTS.DASHBOARD}/invoice`,
new: `${ROOTS.DASHBOARD}/invoice/new`,
details: (id) => `${ROOTS.DASHBOARD}/invoice/${id}`,
edit: (id) => `${ROOTS.DASHBOARD}/invoice/${id}/edit`,
demo: {
details: `${ROOTS.DASHBOARD}/invoice/${MOCK_ID}`,
edit: `${ROOTS.DASHBOARD}/invoice/${MOCK_ID}/edit`,
},
},
post: {
root: `${ROOTS.DASHBOARD}/post`,
new: `${ROOTS.DASHBOARD}/post/new`,
details: (title) => `${ROOTS.DASHBOARD}/post/${paramCase(title)}`,
edit: (title) => `${ROOTS.DASHBOARD}/post/${paramCase(title)}/edit`,
demo: {
details: `${ROOTS.DASHBOARD}/post/${paramCase(MOCK_TITLE)}`,
edit: `${ROOTS.DASHBOARD}/post/${paramCase(MOCK_TITLE)}/edit`,
},
},
order: {
root: `${ROOTS.DASHBOARD}/order`,
details: (id) => `${ROOTS.DASHBOARD}/order/${id}`,
demo: {
details: `${ROOTS.DASHBOARD}/order/${MOCK_ID}`,
},
},
job: {
root: `${ROOTS.DASHBOARD}/job`,
new: `${ROOTS.DASHBOARD}/job/new`,
details: (id) => `${ROOTS.DASHBOARD}/job/${id}`,
edit: (id) => `${ROOTS.DASHBOARD}/job/${id}/edit`,
demo: {
details: `${ROOTS.DASHBOARD}/job/${MOCK_ID}`,
edit: `${ROOTS.DASHBOARD}/job/${MOCK_ID}/edit`,
},
},
tour: {
root: `${ROOTS.DASHBOARD}/tour`,
new: `${ROOTS.DASHBOARD}/tour/new`,
details: (id) => `${ROOTS.DASHBOARD}/tour/${id}`,
edit: (id) => `${ROOTS.DASHBOARD}/tour/${id}/edit`,
demo: {
details: `${ROOTS.DASHBOARD}/tour/${MOCK_ID}`,
edit: `${ROOTS.DASHBOARD}/tour/${MOCK_ID}/edit`,
},
},
}, },
}; };

View File

@ -10,7 +10,7 @@ import { DashboardLayout } from 'src/layouts/dashboard';
import { SplashScreen } from 'src/components/loading-screen'; import { SplashScreen } from 'src/components/loading-screen';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Auth - JWT // Auth
const JwtSignInView = lazy(() => const JwtSignInView = lazy(() =>
import('src/sections/auth/jwt/jwt-sign-in-view').then((m) => ({ default: m.JwtSignInView })) import('src/sections/auth/jwt/jwt-sign-in-view').then((m) => ({ default: m.JwtSignInView }))
@ -35,171 +35,70 @@ const JwtVerifyEmailView = lazy(() =>
); );
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Dashboard - Overview // Dashboard
const OverviewAnalyticsView = lazy(() => const DashboardView = lazy(() =>
import('src/sections/overview/analytics/view').then((m) => ({ import('src/app/dashboard/page').then((m) => ({ default: m.default }))
default: m.OverviewAnalyticsView,
}))
); );
const OverviewEcommerceView = lazy(() =>
import('src/sections/overview/e-commerce/view').then((m) => ({
default: m.OverviewEcommerceView,
}))
);
const OverviewBankingView = lazy(() =>
import('src/sections/overview/banking/view').then((m) => ({ default: m.OverviewBankingView }))
);
const OverviewBookingView = lazy(() =>
import('src/sections/overview/booking/view').then((m) => ({ default: m.OverviewBookingView }))
);
const OverviewFileView = lazy(() =>
import('src/sections/overview/file/view').then((m) => ({ default: m.OverviewFileView }))
);
const OverviewCourseView = lazy(() =>
import('src/sections/overview/course/view').then((m) => ({ default: m.OverviewCourseView }))
);
// Dashboard - Features
const CalendarView = lazy(() => const CalendarView = lazy(() =>
import('src/sections/calendar/view').then((m) => ({ default: m.CalendarView })) import('src/sections/calendar/view').then((m) => ({ default: m.CalendarView }))
); );
const ChatView = lazy(() => const HomeworkView = lazy(() =>
import('src/sections/chat/view').then((m) => ({ default: m.ChatView })) import('src/sections/homework/view').then((m) => ({ default: m.HomeworkView }))
); );
const MailView = lazy(() => const MaterialsView = lazy(() =>
import('src/sections/mail/view').then((m) => ({ default: m.MailView })) import('src/sections/materials/view').then((m) => ({ default: m.MaterialsView }))
); );
const KanbanView = lazy(() => const StudentsView = lazy(() =>
import('src/sections/kanban/view').then((m) => ({ default: m.KanbanView })) import('src/sections/students/view').then((m) => ({ default: m.StudentsView }))
); );
const FileManagerView = lazy(() => const NotificationsView = lazy(() =>
import('src/sections/file-manager/view').then((m) => ({ default: m.FileManagerView })) import('src/sections/notifications/view').then((m) => ({ default: m.NotificationsView }))
); );
const PermissionDeniedView = lazy(() => const BoardView = lazy(() =>
import('src/sections/permission/view').then((m) => ({ default: m.PermissionDeniedView })) import('src/sections/board/view').then((m) => ({ default: m.BoardView }))
); );
const BlankView = lazy(() => const ChatPlatformView = lazy(() =>
import('src/sections/blank/view').then((m) => ({ default: m.BlankView })) import('src/sections/chat/view').then((m) => ({ default: m.ChatPlatformView }))
);
const AnalyticsView = lazy(() =>
import('src/sections/analytics/view').then((m) => ({ default: m.AnalyticsView }))
);
const FeedbackView = lazy(() =>
import('src/sections/feedback/view').then((m) => ({ default: m.FeedbackView }))
);
const AccountPlatformView = lazy(() =>
import('src/sections/account-platform/view').then((m) => ({ default: m.AccountPlatformView }))
);
const ReferralsView = lazy(() =>
import('src/sections/referrals/view').then((m) => ({ default: m.ReferralsView }))
);
const PaymentPlatformView = lazy(() =>
import('src/sections/payment/view').then((m) => ({ default: m.PaymentPlatformView }))
);
const ChildrenView = lazy(() =>
import('src/sections/children/view').then((m) => ({ default: m.ChildrenView }))
);
const ChildrenProgressView = lazy(() =>
import('src/sections/children/view').then((m) => ({ default: m.ChildrenProgressView }))
);
const MyProgressView = lazy(() =>
import('src/sections/my-progress/view').then((m) => ({ default: m.MyProgressView }))
); );
// Dashboard - User // ----------------------------------------------------------------------
// Video call (fullscreen, no dashboard layout)
const UserProfileView = lazy(() => const VideoCallView = lazy(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserProfileView })) import('src/sections/video-call/view').then((m) => ({ default: m.VideoCallView }))
);
const UserListView = lazy(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserListView }))
);
const UserCardsView = lazy(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserCardsView }))
);
const UserCreateView = lazy(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserCreateView }))
);
const UserEditView = lazy(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserEditView }))
);
const AccountView = lazy(() =>
import('src/sections/account/view').then((m) => ({ default: m.AccountView }))
);
// Dashboard - Product
const ProductListView = lazy(() =>
import('src/sections/product/view').then((m) => ({ default: m.ProductListView }))
);
const ProductDetailsView = lazy(() =>
import('src/sections/product/view').then((m) => ({ default: m.ProductDetailsView }))
);
const ProductCreateView = lazy(() =>
import('src/sections/product/view').then((m) => ({ default: m.ProductCreateView }))
);
const ProductEditView = lazy(() =>
import('src/sections/product/view').then((m) => ({ default: m.ProductEditView }))
);
// Dashboard - Order
const OrderListView = lazy(() =>
import('src/sections/order/view').then((m) => ({ default: m.OrderListView }))
);
const OrderDetailsView = lazy(() =>
import('src/sections/order/view').then((m) => ({ default: m.OrderDetailsView }))
);
// Dashboard - Invoice
const InvoiceListView = lazy(() =>
import('src/sections/invoice/view').then((m) => ({ default: m.InvoiceListView }))
);
const InvoiceDetailsView = lazy(() =>
import('src/sections/invoice/view').then((m) => ({ default: m.InvoiceDetailsView }))
);
const InvoiceCreateView = lazy(() =>
import('src/sections/invoice/view').then((m) => ({ default: m.InvoiceCreateView }))
);
const InvoiceEditView = lazy(() =>
import('src/sections/invoice/view').then((m) => ({ default: m.InvoiceEditView }))
);
// Dashboard - Blog / Post
const PostListView = lazy(() =>
import('src/sections/blog/view').then((m) => ({ default: m.PostListView }))
);
const PostCreateView = lazy(() =>
import('src/sections/blog/view').then((m) => ({ default: m.PostCreateView }))
);
const PostDetailsView = lazy(() =>
import('src/sections/blog/view').then((m) => ({ default: m.PostDetailsView }))
);
const PostEditView = lazy(() =>
import('src/sections/blog/view').then((m) => ({ default: m.PostEditView }))
);
// Dashboard - Job
const JobListView = lazy(() =>
import('src/sections/job/view').then((m) => ({ default: m.JobListView }))
);
const JobDetailsView = lazy(() =>
import('src/sections/job/view').then((m) => ({ default: m.JobDetailsView }))
);
const JobCreateView = lazy(() =>
import('src/sections/job/view').then((m) => ({ default: m.JobCreateView }))
);
const JobEditView = lazy(() =>
import('src/sections/job/view').then((m) => ({ default: m.JobEditView }))
);
// Dashboard - Tour
const TourListView = lazy(() =>
import('src/sections/tour/view').then((m) => ({ default: m.TourListView }))
);
const TourDetailsView = lazy(() =>
import('src/sections/tour/view').then((m) => ({ default: m.TourDetailsView }))
);
const TourCreateView = lazy(() =>
import('src/sections/tour/view').then((m) => ({ default: m.TourCreateView }))
);
const TourEditView = lazy(() =>
import('src/sections/tour/view').then((m) => ({ default: m.TourEditView }))
); );
// ----------------------------------------------------------------------
// Error pages // Error pages
const Page403 = lazy(() =>
import('src/sections/error/403-view').then((m) => ({ default: m.View403 }))
);
const Page404 = lazy(() => const Page404 = lazy(() =>
import('src/sections/error/not-found-view').then((m) => ({ default: m.NotFoundView })) import('src/sections/error/not-found-view').then((m) => ({ default: m.NotFoundView }))
); );
const Page500 = lazy(() =>
import('src/sections/error/500-view').then((m) => ({ default: m.View500 }))
);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -207,6 +106,10 @@ function Loading() {
return <SplashScreen />; return <SplashScreen />;
} }
function S({ children }) {
return <Suspense fallback={<Loading />}>{children}</Suspense>;
}
function DashboardLayoutWrapper() { function DashboardLayoutWrapper() {
return ( return (
<AuthGuard> <AuthGuard>
@ -232,460 +135,57 @@ function AuthLayoutWrapper() {
export function Router() { export function Router() {
return useRoutes([ return useRoutes([
// Root redirect // Root redirect
{ { path: '/', element: <Navigate to="/dashboard" replace /> },
path: '/',
element: <Navigate to="/dashboard/analytics" replace />,
},
// Auth - JWT // Auth
{ {
path: 'auth/jwt', path: 'auth/jwt',
element: <AuthLayoutWrapper />, element: <AuthLayoutWrapper />,
children: [ children: [
{ { path: 'sign-in', element: <S><JwtSignInView /></S> },
path: 'sign-in', { path: 'sign-up', element: <S><JwtSignUpView /></S> },
element: ( { path: 'forgot-password', element: <S><JwtForgotPasswordView /></S> },
<Suspense fallback={<Loading />}> { path: 'reset-password', element: <S><JwtResetPasswordView /></S> },
<JwtSignInView />
</Suspense>
),
},
{
path: 'sign-up',
element: (
<Suspense fallback={<Loading />}>
<JwtSignUpView />
</Suspense>
),
},
{
path: 'forgot-password',
element: (
<Suspense fallback={<Loading />}>
<JwtForgotPasswordView />
</Suspense>
),
},
{
path: 'reset-password',
element: (
<Suspense fallback={<Loading />}>
<JwtResetPasswordView />
</Suspense>
),
},
], ],
}, },
// Verify email без GuestGuard
{ {
path: 'auth/jwt/verify-email', path: 'auth/jwt/verify-email',
element: ( element: (
<AuthSplitLayout> <AuthSplitLayout>
<Suspense fallback={<Loading />}> <S><JwtVerifyEmailView /></S>
<JwtVerifyEmailView />
</Suspense>
</AuthSplitLayout> </AuthSplitLayout>
), ),
}, },
// Video call fullscreen, no sidebar
{ path: 'video-call', element: <AuthGuard><S><VideoCallView /></S></AuthGuard> },
// Dashboard // Dashboard
{ {
path: 'dashboard', path: 'dashboard',
element: <DashboardLayoutWrapper />, element: <DashboardLayoutWrapper />,
children: [ children: [
{ index: true, element: <Navigate to="analytics" replace /> }, { index: true, element: <S><DashboardView /></S> },
{ path: 'schedule', element: <S><CalendarView /></S> },
// Overview { path: 'homework', element: <S><HomeworkView /></S> },
{ { path: 'materials', element: <S><MaterialsView /></S> },
path: 'analytics', { path: 'students', element: <S><StudentsView /></S> },
element: ( { path: 'notifications', element: <S><NotificationsView /></S> },
<Suspense fallback={<Loading />}> { path: 'board', element: <S><BoardView /></S> },
<OverviewAnalyticsView /> { path: 'chat-platform', element: <S><ChatPlatformView /></S> },
</Suspense> { path: 'analytics', element: <S><AnalyticsView /></S> },
), { path: 'feedback', element: <S><FeedbackView /></S> },
}, { path: 'profile', element: <S><AccountPlatformView /></S> },
{ { path: 'referrals', element: <S><ReferralsView /></S> },
path: 'ecommerce', { path: 'payment-platform', element: <S><PaymentPlatformView /></S> },
element: ( { path: 'children', element: <S><ChildrenView /></S> },
<Suspense fallback={<Loading />}> { path: 'children-progress', element: <S><ChildrenProgressView /></S> },
<OverviewEcommerceView /> { path: 'my-progress', element: <S><MyProgressView /></S> },
</Suspense>
),
},
{
path: 'banking',
element: (
<Suspense fallback={<Loading />}>
<OverviewBankingView />
</Suspense>
),
},
{
path: 'booking',
element: (
<Suspense fallback={<Loading />}>
<OverviewBookingView />
</Suspense>
),
},
{
path: 'file',
element: (
<Suspense fallback={<Loading />}>
<OverviewFileView />
</Suspense>
),
},
{
path: 'course',
element: (
<Suspense fallback={<Loading />}>
<OverviewCourseView />
</Suspense>
),
},
// Features
{
path: 'schedule',
element: (
<Suspense fallback={<Loading />}>
<CalendarView />
</Suspense>
),
},
{
path: 'chat',
element: (
<Suspense fallback={<Loading />}>
<ChatView />
</Suspense>
),
},
{
path: 'mail',
element: (
<Suspense fallback={<Loading />}>
<MailView />
</Suspense>
),
},
{
path: 'kanban',
element: (
<Suspense fallback={<Loading />}>
<KanbanView />
</Suspense>
),
},
{
path: 'file-manager',
element: (
<Suspense fallback={<Loading />}>
<FileManagerView />
</Suspense>
),
},
{
path: 'permission',
element: (
<Suspense fallback={<Loading />}>
<PermissionDeniedView />
</Suspense>
),
},
{
path: 'blank',
element: (
<Suspense fallback={<Loading />}>
<BlankView />
</Suspense>
),
},
// User
{
path: 'user',
children: [
{ index: true, element: <Navigate to="profile" replace /> },
{
path: 'profile',
element: (
<Suspense fallback={<Loading />}>
<UserProfileView />
</Suspense>
),
},
{
path: 'list',
element: (
<Suspense fallback={<Loading />}>
<UserListView />
</Suspense>
),
},
{
path: 'cards',
element: (
<Suspense fallback={<Loading />}>
<UserCardsView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<UserCreateView />
</Suspense>
),
},
{
path: ':id/edit',
element: (
<Suspense fallback={<Loading />}>
<UserEditView />
</Suspense>
),
},
{
path: 'account',
element: (
<Suspense fallback={<Loading />}>
<AccountView />
</Suspense>
),
},
], ],
}, },
// Product // Error / catch-all
{ { path: '404', element: <S><Page404 /></S> },
path: 'product',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<ProductListView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<ProductCreateView />
</Suspense>
),
},
{
path: ':id',
element: (
<Suspense fallback={<Loading />}>
<ProductDetailsView />
</Suspense>
),
},
{
path: ':id/edit',
element: (
<Suspense fallback={<Loading />}>
<ProductEditView />
</Suspense>
),
},
],
},
// Order
{
path: 'order',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<OrderListView />
</Suspense>
),
},
{
path: ':id',
element: (
<Suspense fallback={<Loading />}>
<OrderDetailsView />
</Suspense>
),
},
],
},
// Invoice
{
path: 'invoice',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<InvoiceListView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<InvoiceCreateView />
</Suspense>
),
},
{
path: ':id',
element: (
<Suspense fallback={<Loading />}>
<InvoiceDetailsView />
</Suspense>
),
},
{
path: ':id/edit',
element: (
<Suspense fallback={<Loading />}>
<InvoiceEditView />
</Suspense>
),
},
],
},
// Blog / Post
{
path: 'post',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<PostListView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<PostCreateView />
</Suspense>
),
},
{
path: ':title',
element: (
<Suspense fallback={<Loading />}>
<PostDetailsView />
</Suspense>
),
},
{
path: ':title/edit',
element: (
<Suspense fallback={<Loading />}>
<PostEditView />
</Suspense>
),
},
],
},
// Job
{
path: 'job',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<JobListView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<JobCreateView />
</Suspense>
),
},
{
path: ':id',
element: (
<Suspense fallback={<Loading />}>
<JobDetailsView />
</Suspense>
),
},
{
path: ':id/edit',
element: (
<Suspense fallback={<Loading />}>
<JobEditView />
</Suspense>
),
},
],
},
// Tour
{
path: 'tour',
children: [
{
index: true,
element: (
<Suspense fallback={<Loading />}>
<TourListView />
</Suspense>
),
},
{
path: 'new',
element: (
<Suspense fallback={<Loading />}>
<TourCreateView />
</Suspense>
),
},
{
path: ':id',
element: (
<Suspense fallback={<Loading />}>
<TourDetailsView />
</Suspense>
),
},
{
path: ':id/edit',
element: (
<Suspense fallback={<Loading />}>
<TourEditView />
</Suspense>
),
},
],
},
],
},
// Error pages
{ path: '403', element: <Suspense fallback={<Loading />}><Page403 /></Suspense> },
{ path: '404', element: <Suspense fallback={<Loading />}><Page404 /></Suspense> },
{ path: '500', element: <Suspense fallback={<Loading />}><Page500 /></Suspense> },
// Catch-all
{ path: '*', element: <Navigate to="/404" replace /> }, { path: '*', element: <Navigate to="/404" replace /> },
]); ]);
} }

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import dynamic from 'next/dynamic';
import { useState, useEffect, useCallback, useMemo } from 'react'; import { useState, useEffect, useCallback, useMemo } from 'react';
import Tab from '@mui/material/Tab'; import Tab from '@mui/material/Tab';
@ -27,7 +27,7 @@ import {
} from 'src/utils/analytics-api'; } from 'src/utils/analytics-api';
import { getMentorIncome } from 'src/utils/dashboard-api'; import { getMentorIncome } from 'src/utils/dashboard-api';
const ApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }); import ApexChart from 'react-apexcharts';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useCallback } from 'react'; import { useCallback } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useCallback } from 'react'; import { useCallback } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useAuth0 } from '@auth0/auth0-react'; import { useAuth0 } from '@auth0/auth0-react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';

View File

@ -4,7 +4,7 @@ import { z as zod } from 'zod';
import { useState, Suspense } from 'react'; import { useState, Suspense } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'react-router-dom';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import Alert from '@mui/material/Alert'; import Alert from '@mui/material/Alert';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import { useState, useEffect, Suspense } from 'react'; import { useState, useEffect, Suspense } from 'react';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'react-router-dom';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import Alert from '@mui/material/Alert'; import Alert from '@mui/material/Alert';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import { z as zod } from 'zod'; import { z as zod } from 'zod';
import { useState } from 'react'; import { useState } from 'react';

View File

@ -1,4 +1,3 @@
'use client';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';

View File

@ -1,7 +1,7 @@
'use client';
import { useRef, useEffect, useState, useCallback } from 'react'; import { useRef, useEffect, useState, useCallback } from 'react';
import { useSearchParams, useRouter } from 'next/navigation'; import { useSearchParams } from 'react-router-dom';
import { useRouter } from 'src/routes/hooks';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Card from '@mui/material/Card'; import Card from '@mui/material/Card';

View File

@ -7,7 +7,7 @@ import { useMemo, useState, useCallback } from 'react';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
import { useRouter } from 'next/navigation'; import { useRouter } from 'src/routes/hooks';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';

View File

@ -1,7 +1,8 @@
'use client'; 'use client';
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
import { useRouter, useSearchParams } from 'next/navigation'; import { useSearchParams } from 'react-router-dom';
import { useRouter } from 'src/routes/hooks';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Card from '@mui/material/Card'; import Card from '@mui/material/Card';

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { useRouter } from 'next/navigation'; import { useRouter } from 'src/routes/hooks';
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import dynamic from 'next/dynamic';
import { useMemo, useState, useEffect, useCallback } from 'react'; import { useMemo, useState, useEffect, useCallback } from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
@ -28,7 +28,7 @@ import { useAuthContext } from 'src/auth/hooks';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); import Chart from 'react-apexcharts';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@ -5,7 +5,8 @@ import 'src/styles/livekit-components.css';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { isTrackReference } from '@livekit/components-core'; import { isTrackReference } from '@livekit/components-core';
import { useRouter, useSearchParams } from 'next/navigation'; import { useSearchParams } from 'react-router-dom';
import { useRouter } from 'src/routes/hooks';
import { useRef, useState, useEffect, Component } from 'react'; import { useRef, useState, useEffect, Component } from 'react';
import { Track, RoomEvent, VideoPresets } from 'livekit-client'; import { Track, RoomEvent, VideoPresets } from 'livekit-client';
import { import {

View File

@ -1,7 +1,4 @@
'use client';
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter';
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
import { useTranslate } from 'src/locales'; import { useTranslate } from 'src/locales';
@ -22,7 +19,6 @@ export function ThemeProvider({ children }) {
const theme = createTheme(currentLang?.systemValue, settings); const theme = createTheme(currentLang?.systemValue, settings);
return ( return (
<AppRouterCacheProvider options={{ key: 'css' }}>
<CssVarsProvider <CssVarsProvider
theme={theme} theme={theme}
defaultMode={schemeConfig.defaultMode} defaultMode={schemeConfig.defaultMode}
@ -31,6 +27,5 @@ export function ThemeProvider({ children }) {
<CssBaseline /> <CssBaseline />
<RTL direction={settings.direction}>{children}</RTL> <RTL direction={settings.direction}>{children}</RTL>
</CssVarsProvider> </CssVarsProvider>
</AppRouterCacheProvider>
); );
} }

View File

@ -0,0 +1,51 @@
import path from 'path';
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
// ----------------------------------------------------------------------
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [
react(),
svgr({ svgrOptions: { icon: true } }),
],
resolve: {
alias: {
src: path.resolve(__dirname, './src'),
},
},
// Expose NEXT_PUBLIC_* vars as VITE_* for backward compatibility
define: {
'process.env.NEXT_PUBLIC_SERVER_URL': JSON.stringify(env.VITE_SERVER_URL || env.NEXT_PUBLIC_SERVER_URL || ''),
'process.env.NEXT_PUBLIC_API_URL': JSON.stringify(env.VITE_API_URL || env.NEXT_PUBLIC_API_URL || ''),
'process.env.NEXT_PUBLIC_WS_URL': JSON.stringify(env.VITE_WS_URL || env.NEXT_PUBLIC_WS_URL || ''),
'process.env.NEXT_PUBLIC_EXCALIDRAW_URL': JSON.stringify(env.VITE_EXCALIDRAW_URL || env.NEXT_PUBLIC_EXCALIDRAW_URL || ''),
'process.env.NEXT_PUBLIC_EXCALIDRAW_PATH': JSON.stringify(env.VITE_EXCALIDRAW_PATH || env.NEXT_PUBLIC_EXCALIDRAW_PATH || ''),
'process.env.NEXT_PUBLIC_EXCALIDRAW_PORT': JSON.stringify(env.VITE_EXCALIDRAW_PORT || env.NEXT_PUBLIC_EXCALIDRAW_PORT || '3001'),
'process.env.NEXT_PUBLIC_YJS_PORT': JSON.stringify(env.VITE_YJS_PORT || env.NEXT_PUBLIC_YJS_PORT || '1236'),
'process.env.NEXT_PUBLIC_LIVEKIT_URL': JSON.stringify(env.VITE_LIVEKIT_URL || env.NEXT_PUBLIC_LIVEKIT_URL || ''),
},
server: {
port: 3032,
host: true,
},
preview: {
port: 3032,
},
build: {
chunkSizeWarningLimit: 1600,
rollupOptions: {
output: {
manualChunks: {
mui: ['@mui/material', '@mui/lab'],
fullcalendar: ['@fullcalendar/core', '@fullcalendar/react'],
},
},
},
},
};
});