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",
"author": "Minimals",
"version": "6.0.1",
"description": "Next & JavaScript",
"name": "platform-frontend",
"author": "Platform",
"version": "1.0.0",
"description": "Platform frontend — Vite + React",
"private": true,
"scripts": {
"dev": "next dev -p 3032",
"start": "next start -p 3032",
"build": "next build",
"dev": "vite --port 3032",
"build": "vite build",
"preview": "vite preview --port 3032",
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"",
"fm:check": "prettier --check \"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: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"
"re:build": "yarn rm:all && yarn install && yarn build"
},
"dependencies": {
"@auth0/auth0-react": "^2.2.4",
@ -45,7 +43,6 @@
"@livekit/components-styles": "^1.2.0",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5.15.20",
"@mui/material-nextjs": "^5.15.11",
"@mui/x-data-grid": "^7.7.0",
"@mui/x-date-pickers": "^7.7.0",
"@mui/x-tree-view": "^7.7.0",
@ -81,7 +78,6 @@
"lowlight": "^3.1.0",
"mapbox-gl": "^3.4.0",
"mui-one-time-password-input": "^2.0.2",
"next": "^14.2.4",
"nprogress": "^0.2.0",
"react": "^18.3.1",
"react-apexcharts": "^1.4.1",
@ -108,8 +104,9 @@
"zod": "^3.23.8"
},
"devDependencies": {
"@svgr/webpack": "^8.1.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.7.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
@ -122,6 +119,9 @@
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-unused-imports": "^3.2.0",
"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 { SettingsDrawer, defaultSettings, SettingsProvider } from 'src/components/settings';
import { CheckoutProvider } from 'src/sections/checkout/context';
import { AuthProvider } from 'src/auth/context/jwt';
import { Router } from 'src/routes/sections';
@ -26,12 +24,10 @@ export default function App() {
<SettingsProvider settings={defaultSettings} caches="localStorage">
<ThemeProvider>
<MotionLazy>
<CheckoutProvider>
<Snackbar />
<ProgressBar />
<SettingsDrawer />
<Router />
</CheckoutProvider>
<Snackbar />
<ProgressBar />
<SettingsDrawer />
<Router />
</MotionLazy>
</ThemeProvider>
</SettingsProvider>

View File

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

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 = {
AUTH: '/auth',
AUTH_DEMO: '/auth-demo',
DASHBOARD: '/dashboard',
};
@ -18,43 +7,10 @@ const ROOTS = {
export const paths = {
videoCall: '/video-call',
comingSoon: '/coming-soon',
maintenance: '/maintenance',
pricing: '/pricing',
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
page404: '/404',
// 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: {
signIn: `${ROOTS.AUTH}/jwt/sign-in`,
signUp: `${ROOTS.AUTH}/jwt/sign-up`,
@ -62,140 +18,25 @@ export const paths = {
resetPassword: `${ROOTS.AUTH}/jwt/reset-password`,
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`,
},
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,
mail: `${ROOTS.DASHBOARD}/mail`,
chat: `${ROOTS.DASHBOARD}/chat`,
blank: `${ROOTS.DASHBOARD}/blank`,
kanban: `${ROOTS.DASHBOARD}/kanban`,
calendar: `${ROOTS.DASHBOARD}/schedule`,
homework: `${ROOTS.DASHBOARD}/homework`,
materials: `${ROOTS.DASHBOARD}/materials`,
students: `${ROOTS.DASHBOARD}/students`,
notifications: `${ROOTS.DASHBOARD}/notifications`,
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`,
analytics: `${ROOTS.DASHBOARD}/analytics`,
feedback: `${ROOTS.DASHBOARD}/feedback`,
fileManager: `${ROOTS.DASHBOARD}/file-manager`,
permission: `${ROOTS.DASHBOARD}/permission`,
general: {
app: `${ROOTS.DASHBOARD}/app`,
ecommerce: `${ROOTS.DASHBOARD}/ecommerce`,
analytics: `${ROOTS.DASHBOARD}/analytics`,
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`,
},
},
profile: `${ROOTS.DASHBOARD}/profile`,
referrals: `${ROOTS.DASHBOARD}/referrals`,
payment: `${ROOTS.DASHBOARD}/payment-platform`,
children: `${ROOTS.DASHBOARD}/children`,
childrenProgress: `${ROOTS.DASHBOARD}/children-progress`,
myProgress: `${ROOTS.DASHBOARD}/my-progress`,
},
};

View File

@ -10,7 +10,7 @@ import { DashboardLayout } from 'src/layouts/dashboard';
import { SplashScreen } from 'src/components/loading-screen';
// ----------------------------------------------------------------------
// Auth - JWT
// Auth
const JwtSignInView = lazy(() =>
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(() =>
import('src/sections/overview/analytics/view').then((m) => ({
default: m.OverviewAnalyticsView,
}))
const DashboardView = lazy(() =>
import('src/app/dashboard/page').then((m) => ({ default: m.default }))
);
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(() =>
import('src/sections/calendar/view').then((m) => ({ default: m.CalendarView }))
);
const ChatView = lazy(() =>
import('src/sections/chat/view').then((m) => ({ default: m.ChatView }))
const HomeworkView = lazy(() =>
import('src/sections/homework/view').then((m) => ({ default: m.HomeworkView }))
);
const MailView = lazy(() =>
import('src/sections/mail/view').then((m) => ({ default: m.MailView }))
const MaterialsView = lazy(() =>
import('src/sections/materials/view').then((m) => ({ default: m.MaterialsView }))
);
const KanbanView = lazy(() =>
import('src/sections/kanban/view').then((m) => ({ default: m.KanbanView }))
const StudentsView = lazy(() =>
import('src/sections/students/view').then((m) => ({ default: m.StudentsView }))
);
const FileManagerView = lazy(() =>
import('src/sections/file-manager/view').then((m) => ({ default: m.FileManagerView }))
const NotificationsView = lazy(() =>
import('src/sections/notifications/view').then((m) => ({ default: m.NotificationsView }))
);
const PermissionDeniedView = lazy(() =>
import('src/sections/permission/view').then((m) => ({ default: m.PermissionDeniedView }))
const BoardView = lazy(() =>
import('src/sections/board/view').then((m) => ({ default: m.BoardView }))
);
const BlankView = lazy(() =>
import('src/sections/blank/view').then((m) => ({ default: m.BlankView }))
const ChatPlatformView = lazy(() =>
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(() =>
import('src/sections/user/view').then((m) => ({ default: m.UserProfileView }))
);
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 }))
const VideoCallView = lazy(() =>
import('src/sections/video-call/view').then((m) => ({ default: m.VideoCallView }))
);
// ----------------------------------------------------------------------
// Error pages
const Page403 = lazy(() =>
import('src/sections/error/403-view').then((m) => ({ default: m.View403 }))
);
const Page404 = lazy(() =>
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 />;
}
function S({ children }) {
return <Suspense fallback={<Loading />}>{children}</Suspense>;
}
function DashboardLayoutWrapper() {
return (
<AuthGuard>
@ -232,460 +135,57 @@ function AuthLayoutWrapper() {
export function Router() {
return useRoutes([
// Root redirect
{
path: '/',
element: <Navigate to="/dashboard/analytics" replace />,
},
{ path: '/', element: <Navigate to="/dashboard" replace /> },
// Auth - JWT
// Auth
{
path: 'auth/jwt',
element: <AuthLayoutWrapper />,
children: [
{
path: 'sign-in',
element: (
<Suspense fallback={<Loading />}>
<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>
),
},
{ path: 'sign-in', element: <S><JwtSignInView /></S> },
{ path: 'sign-up', element: <S><JwtSignUpView /></S> },
{ path: 'forgot-password', element: <S><JwtForgotPasswordView /></S> },
{ path: 'reset-password', element: <S><JwtResetPasswordView /></S> },
],
},
// Verify email без GuestGuard
{
path: 'auth/jwt/verify-email',
element: (
<AuthSplitLayout>
<Suspense fallback={<Loading />}>
<JwtVerifyEmailView />
</Suspense>
<S><JwtVerifyEmailView /></S>
</AuthSplitLayout>
),
},
// Video call fullscreen, no sidebar
{ path: 'video-call', element: <AuthGuard><S><VideoCallView /></S></AuthGuard> },
// Dashboard
{
path: 'dashboard',
element: <DashboardLayoutWrapper />,
children: [
{ index: true, element: <Navigate to="analytics" replace /> },
// Overview
{
path: 'analytics',
element: (
<Suspense fallback={<Loading />}>
<OverviewAnalyticsView />
</Suspense>
),
},
{
path: 'ecommerce',
element: (
<Suspense fallback={<Loading />}>
<OverviewEcommerceView />
</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
{
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>
),
},
],
},
{ index: true, element: <S><DashboardView /></S> },
{ path: 'schedule', element: <S><CalendarView /></S> },
{ path: 'homework', element: <S><HomeworkView /></S> },
{ path: 'materials', element: <S><MaterialsView /></S> },
{ path: 'students', element: <S><StudentsView /></S> },
{ path: 'notifications', element: <S><NotificationsView /></S> },
{ path: 'board', element: <S><BoardView /></S> },
{ path: 'chat-platform', element: <S><ChatPlatformView /></S> },
{ 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: 'payment-platform', element: <S><PaymentPlatformView /></S> },
{ path: 'children', element: <S><ChildrenView /></S> },
{ path: 'children-progress', element: <S><ChildrenProgressView /></S> },
{ path: 'my-progress', element: <S><MyProgressView /></S> },
],
},
// 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
// Error / catch-all
{ path: '404', element: <S><Page404 /></S> },
{ path: '*', element: <Navigate to="/404" replace /> },
]);
}

View File

@ -1,6 +1,6 @@
'use client';
import dynamic from 'next/dynamic';
import { useState, useEffect, useCallback, useMemo } from 'react';
import Tab from '@mui/material/Tab';
@ -27,7 +27,7 @@ import {
} from 'src/utils/analytics-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 { useForm } from 'react-hook-form';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
'use client';
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 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 Stack from '@mui/material/Stack';

View File

@ -1,7 +1,8 @@
'use client';
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 Card from '@mui/material/Card';

View File

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

View File

@ -1,6 +1,6 @@
'use client';
import dynamic from 'next/dynamic';
import { useMemo, useState, useEffect, useCallback } from 'react';
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 { 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 { Track, RoomEvent, VideoPresets } from 'livekit-client';
import {

View File

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

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'],
},
},
},
},
};
});