- Color
+ Цвет
{options.colors.map((option) => (
@@ -74,7 +74,7 @@ export function NavOptions({ options, value, onClickOption, hideNavColor, hideNa
);
return (
-
+
{!hideNavLayout && renderLayout}
{!hideNavColor && renderColor}
@@ -247,12 +247,11 @@ export function ColorOption({ option, selected, sx, ...other }) {
component="span"
sx={{
lineHeight: '18px',
- textTransform: 'capitalize',
fontWeight: 'fontWeightSemiBold',
fontSize: (theme) => theme.typography.pxToRem(13),
}}
>
- {option}
+ {{ integrate: 'Встроен', apparent: 'Явный' }[option] ?? option}
);
diff --git a/front_minimal/src/components/settings/drawer/presets-options.jsx b/front_minimal/src/components/settings/drawer/presets-options.jsx
index b5f9b8e..53ba3d8 100644
--- a/front_minimal/src/components/settings/drawer/presets-options.jsx
+++ b/front_minimal/src/components/settings/drawer/presets-options.jsx
@@ -11,7 +11,7 @@ import { SvgColor } from '../../svg-color';
export function PresetsOptions({ value, options, onClickOption }) {
return (
-
+
{options.map((option) => {
const selected = value === option.name;
diff --git a/front_minimal/src/components/settings/drawer/settings-drawer.jsx b/front_minimal/src/components/settings/drawer/settings-drawer.jsx
index 6545bd3..8215dc7 100644
--- a/front_minimal/src/components/settings/drawer/settings-drawer.jsx
+++ b/front_minimal/src/components/settings/drawer/settings-drawer.jsx
@@ -1,195 +1,13 @@
-'use client';
-import Box from '@mui/material/Box';
-import Stack from '@mui/material/Stack';
-import Badge from '@mui/material/Badge';
-import Tooltip from '@mui/material/Tooltip';
-import IconButton from '@mui/material/IconButton';
-import Typography from '@mui/material/Typography';
import Drawer, { drawerClasses } from '@mui/material/Drawer';
import { useTheme, useColorScheme } from '@mui/material/styles';
-import COLORS from 'src/theme/core/colors.json';
import { paper, varAlpha } from 'src/theme/styles';
-import { defaultFont } from 'src/theme/core/typography';
-import PRIMARY_COLOR from 'src/theme/with-settings/primary-color.json';
-import { Iconify } from '../../iconify';
-import { BaseOption } from './base-option';
-import { NavOptions } from './nav-options';
-import { Scrollbar } from '../../scrollbar';
-import { FontOptions } from './font-options';
import { useSettingsContext } from '../context';
-import { PresetsOptions } from './presets-options';
-import { defaultSettings } from '../config-settings';
-import { FullScreenButton } from './fullscreen-button';
-// ----------------------------------------------------------------------
-
-export function SettingsDrawer({
- sx,
- hideFont,
- hideCompact,
- hidePresets,
- hideNavColor,
- hideContrast,
- hideNavLayout,
- hideDirection,
- hideColorScheme,
-}) {
- const theme = useTheme();
-
- const settings = useSettingsContext();
-
- const { mode, setMode } = useColorScheme();
-
- const renderHead = (
-
-
- Settings
-
-
-
-
-
- {
- settings.onReset();
- setMode(defaultSettings.colorScheme);
- }}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- );
-
- const renderMode = (
- {
- settings.onUpdateField('colorScheme', mode === 'light' ? 'dark' : 'light');
- setMode(mode === 'light' ? 'dark' : 'light');
- }}
- />
- );
-
- const renderContrast = (
-
- settings.onUpdateField('contrast', settings.contrast === 'default' ? 'hight' : 'default')
- }
- />
- );
-
- const renderRTL = (
-
- settings.onUpdateField('direction', settings.direction === 'ltr' ? 'rtl' : 'ltr')
- }
- />
- );
-
- const renderCompact = (
- settings.onUpdateField('compactLayout', !settings.compactLayout)}
- />
- );
-
- const renderPresets = (
- settings.onUpdateField('primaryColor', newValue)}
- options={[
- { name: 'default', value: COLORS.primary.main },
- { name: 'cyan', value: PRIMARY_COLOR.cyan.main },
- { name: 'purple', value: PRIMARY_COLOR.purple.main },
- { name: 'blue', value: PRIMARY_COLOR.blue.main },
- { name: 'orange', value: PRIMARY_COLOR.orange.main },
- { name: 'red', value: PRIMARY_COLOR.red.main },
- ]}
- />
- );
-
- const renderNav = (
- settings.onUpdateField('navColor', newValue),
- layout: (newValue) => settings.onUpdateField('navLayout', newValue),
- }}
- options={{
- colors: ['integrate', 'apparent'],
- layouts: ['vertical', 'horizontal', 'mini'],
- }}
- hideNavColor={hideNavColor}
- hideNavLayout={hideNavLayout}
- />
- );
-
- const renderFont = (
- settings.onUpdateField('fontFamily', newValue)}
- options={[defaultFont, 'Inter', 'DM Sans', 'Nunito Sans']}
- />
- );
-
- return (
-
- {renderHead}
-
-
-
-
- {!hideColorScheme && renderMode}
- {!hideContrast && renderContrast}
- {!hideDirection && renderRTL}
- {!hideCompact && renderCompact}
-
- {!(hideNavLayout && hideNavColor) && renderNav}
- {!hidePresets && renderPresets}
- {!hideFont && renderFont}
-
-
-
- );
+// Drawer больше не нужен — все настройки зафиксированы.
+// Оставляем пустой экспорт для совместимости.
+export function SettingsDrawer() {
+ return null;
}
diff --git a/front_minimal/src/components/snackbar/snackbar.jsx b/front_minimal/src/components/snackbar/snackbar.jsx
index cc95e49..0f8ff8c 100644
--- a/front_minimal/src/components/snackbar/snackbar.jsx
+++ b/front_minimal/src/components/snackbar/snackbar.jsx
@@ -1,4 +1,3 @@
-'use client';
import Portal from '@mui/material/Portal';
diff --git a/front_minimal/src/components/walktour/walktour-tooltip.jsx b/front_minimal/src/components/walktour/walktour-tooltip.jsx
index 588513f..90f924e 100644
--- a/front_minimal/src/components/walktour/walktour-tooltip.jsx
+++ b/front_minimal/src/components/walktour/walktour-tooltip.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/hooks/use-boolean.js b/front_minimal/src/hooks/use-boolean.js
index b927874..a551ade 100644
--- a/front_minimal/src/hooks/use-boolean.js
+++ b/front_minimal/src/hooks/use-boolean.js
@@ -1,4 +1,3 @@
-'use client';
import { useMemo, useState, useCallback } from 'react';
diff --git a/front_minimal/src/hooks/use-local-storage.js b/front_minimal/src/hooks/use-local-storage.js
index 1c6c7d7..5f0a72a 100644
--- a/front_minimal/src/hooks/use-local-storage.js
+++ b/front_minimal/src/hooks/use-local-storage.js
@@ -6,24 +6,17 @@ import { localStorageGetItem } from 'src/utils/storage-available';
// ----------------------------------------------------------------------
export function useLocalStorage(key, initialState) {
- const [state, set] = useState(initialState);
-
const multiValue = initialState && typeof initialState === 'object';
+ // Read localStorage synchronously on first render — no useEffect, no flash
+ const [state, set] = useState(() => {
+ const stored = getStorage(key);
+ if (!stored) return initialState;
+ return multiValue ? { ...initialState, ...stored } : stored;
+ });
+
const canReset = !isEqual(state, initialState);
- useEffect(() => {
- const restoredValue = getStorage(key);
-
- if (restoredValue) {
- if (multiValue) {
- set((prevValue) => ({ ...prevValue, ...restoredValue }));
- } else {
- set(restoredValue);
- }
- }
- }, [key, multiValue]);
-
const setState = useCallback(
(updateState) => {
if (multiValue) {
diff --git a/front_minimal/src/hooks/use-scroll-offset-top.js b/front_minimal/src/hooks/use-scroll-offset-top.js
index 727c6b8..479d48b 100644
--- a/front_minimal/src/hooks/use-scroll-offset-top.js
+++ b/front_minimal/src/hooks/use-scroll-offset-top.js
@@ -1,4 +1,3 @@
-'use client';
import { useScroll, useMotionValueEvent } from 'framer-motion';
import { useRef, useMemo, useState, useCallback } from 'react';
diff --git a/front_minimal/src/layouts/auth-centered/layout.jsx b/front_minimal/src/layouts/auth-centered/layout.jsx
index 9116ed0..05b098f 100644
--- a/front_minimal/src/layouts/auth-centered/layout.jsx
+++ b/front_minimal/src/layouts/auth-centered/layout.jsx
@@ -1,4 +1,3 @@
-'use client';
import Alert from '@mui/material/Alert';
diff --git a/front_minimal/src/layouts/auth-split/layout.jsx b/front_minimal/src/layouts/auth-split/layout.jsx
index d8873b3..7115d03 100644
--- a/front_minimal/src/layouts/auth-split/layout.jsx
+++ b/front_minimal/src/layouts/auth-split/layout.jsx
@@ -1,4 +1,3 @@
-'use client';
import Alert from '@mui/material/Alert';
@@ -38,6 +37,7 @@ export function AuthSplitLayout({ sx, section, children }) {
searchbar: false,
workspaces: false,
menuButton: false,
+ helpLink: false,
localization: false,
notifications: false,
}}
@@ -77,26 +77,6 @@ export function AuthSplitLayout({ sx, section, children }) {
path: paths.auth.jwt.signIn,
icon: `${CONFIG.site.basePath}/assets/icons/platforms/ic-jwt.svg`,
},
- {
- label: 'Firebase',
- path: paths.auth.firebase.signIn,
- icon: `${CONFIG.site.basePath}/assets/icons/platforms/ic-firebase.svg`,
- },
- {
- label: 'Amplify',
- path: paths.auth.amplify.signIn,
- icon: `${CONFIG.site.basePath}/assets/icons/platforms/ic-amplify.svg`,
- },
- {
- label: 'Auth0',
- path: paths.auth.auth0.signIn,
- icon: `${CONFIG.site.basePath}/assets/icons/platforms/ic-auth0.svg`,
- },
- {
- label: 'Supabase',
- path: paths.auth.supabase.signIn,
- icon: `${CONFIG.site.basePath}/assets/icons/platforms/ic-supabase.svg`,
- },
]}
/>
{children}
diff --git a/front_minimal/src/layouts/auth-split/section.jsx b/front_minimal/src/layouts/auth-split/section.jsx
index 03d48e8..ffcc3db 100644
--- a/front_minimal/src/layouts/auth-split/section.jsx
+++ b/front_minimal/src/layouts/auth-split/section.jsx
@@ -16,9 +16,9 @@ export function Section({
method,
layoutQuery,
methods,
- title = 'Manage the job',
+ title = 'Добро пожаловать',
imgUrl = `${CONFIG.site.basePath}/assets/illustrations/illustration-dashboard.webp`,
- subtitle = 'More effectively with optimized workflows.',
+ subtitle = 'Платформа для онлайн-обучения и работы с репетиторами.',
...other
}) {
const theme = useTheme();
diff --git a/front_minimal/src/layouts/components/account-drawer.jsx b/front_minimal/src/layouts/components/account-drawer.jsx
index b8293ca..67fbd04 100644
--- a/front_minimal/src/layouts/components/account-drawer.jsx
+++ b/front_minimal/src/layouts/components/account-drawer.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/layouts/components/contacts-popover.jsx b/front_minimal/src/layouts/components/contacts-popover.jsx
index b0b805a..d8c513c 100644
--- a/front_minimal/src/layouts/components/contacts-popover.jsx
+++ b/front_minimal/src/layouts/components/contacts-popover.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/layouts/components/language-popover.jsx b/front_minimal/src/layouts/components/language-popover.jsx
index 9361de4..2bca3e5 100644
--- a/front_minimal/src/layouts/components/language-popover.jsx
+++ b/front_minimal/src/layouts/components/language-popover.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
import { useCallback } from 'react';
diff --git a/front_minimal/src/layouts/components/nav-upgrade.jsx b/front_minimal/src/layouts/components/nav-upgrade.jsx
index 30f7d49..5145d91 100644
--- a/front_minimal/src/layouts/components/nav-upgrade.jsx
+++ b/front_minimal/src/layouts/components/nav-upgrade.jsx
@@ -36,9 +36,9 @@ export function NavUpgrade({ sx, ...other }) {
const [sub, setSub] = useState(undefined); // undefined = loading, null = no sub
useEffect(() => {
- if (!user) return;
+ if (!user?.id) return;
fetchActiveSubscription().then(setSub);
- }, [user]);
+ }, [user?.id]);
const displayName = user
? `${user.first_name || ''} ${user.last_name || ''}`.trim() || user.email
diff --git a/front_minimal/src/layouts/components/notifications-drawer/index.jsx b/front_minimal/src/layouts/components/notifications-drawer/index.jsx
index 40e2fed..251303a 100644
--- a/front_minimal/src/layouts/components/notifications-drawer/index.jsx
+++ b/front_minimal/src/layouts/components/notifications-drawer/index.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
import { useState, useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/layouts/components/searchbar/index.jsx b/front_minimal/src/layouts/components/searchbar/index.jsx
index c4477c3..0640169 100644
--- a/front_minimal/src/layouts/components/searchbar/index.jsx
+++ b/front_minimal/src/layouts/components/searchbar/index.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
import parse from 'autosuggest-highlight/parse';
diff --git a/front_minimal/src/layouts/components/settings-button.jsx b/front_minimal/src/layouts/components/settings-button.jsx
index 99f3ee0..9c2bd8b 100644
--- a/front_minimal/src/layouts/components/settings-button.jsx
+++ b/front_minimal/src/layouts/components/settings-button.jsx
@@ -1,45 +1,87 @@
-'use client';
-import { m } from 'framer-motion';
+import { useState, useCallback } from 'react';
-import Badge from '@mui/material/Badge';
-import SvgIcon from '@mui/material/SvgIcon';
+import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
+import { useColorScheme } from '@mui/material/styles';
+
+import { CONFIG } from 'src/config-global';
+import { Iconify } from 'src/components/iconify';
+import { SvgColor, svgColorClasses } from 'src/components/svg-color';
import { useSettingsContext } from 'src/components/settings/context';
// ----------------------------------------------------------------------
-export function SettingsButton({ sx, ...other }) {
- const settings = useSettingsContext();
+function FullScreenButton() {
+ const [fullscreen, setFullscreen] = useState(false);
+
+ const onToggle = useCallback(() => {
+ if (!document.fullscreenElement) {
+ document.documentElement.requestFullscreen();
+ setFullscreen(true);
+ } else if (document.exitFullscreen) {
+ document.exitFullscreen();
+ setFullscreen(false);
+ }
+ }, []);
return (
-
-
-
- {/* https://icon-sets.iconify.design/solar/settings-bold-duotone/ */}
-
-
-
-
-
+
+
+ `linear-gradient(135deg, ${theme.vars.palette.grey[500]} 0%, ${theme.vars.palette.grey[600]} 100%)`,
+ ...(fullscreen && {
+ background: (theme) =>
+ `linear-gradient(135deg, ${theme.vars.palette.primary.light} 0%, ${theme.vars.palette.primary.main} 100%)`,
+ }),
+ },
+ }}
+ >
+
+
+
+ );
+}
+
+// ----------------------------------------------------------------------
+
+export function SettingsButton({ sx, ...other }) {
+ const settings = useSettingsContext();
+ const { mode, setMode } = useColorScheme();
+
+ const isDark = mode === 'dark' || settings.colorScheme === 'dark';
+
+ const handleToggle = () => {
+ const next = isDark ? 'light' : 'dark';
+ settings.onUpdateField('colorScheme', next);
+ setMode(next);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ >
);
}
diff --git a/front_minimal/src/layouts/components/workspaces-popover.jsx b/front_minimal/src/layouts/components/workspaces-popover.jsx
index 84ca8bb..c65ac97 100644
--- a/front_minimal/src/layouts/components/workspaces-popover.jsx
+++ b/front_minimal/src/layouts/components/workspaces-popover.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/layouts/core/header-base.jsx b/front_minimal/src/layouts/core/header-base.jsx
index 69407cc..2d717d4 100644
--- a/front_minimal/src/layouts/core/header-base.jsx
+++ b/front_minimal/src/layouts/core/header-base.jsx
@@ -131,7 +131,7 @@ export function HeaderBase({
color="inherit"
sx={{ typography: 'subtitle2' }}
>
- Need help?
+ Нужна помощь?
)}
diff --git a/front_minimal/src/layouts/core/layout-section.jsx b/front_minimal/src/layouts/core/layout-section.jsx
index b56e4c4..b7ad6dc 100644
--- a/front_minimal/src/layouts/core/layout-section.jsx
+++ b/front_minimal/src/layouts/core/layout-section.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import GlobalStyles from '@mui/material/GlobalStyles';
diff --git a/front_minimal/src/layouts/dashboard/layout.jsx b/front_minimal/src/layouts/dashboard/layout.jsx
index 8744d47..870c992 100644
--- a/front_minimal/src/layouts/dashboard/layout.jsx
+++ b/front_minimal/src/layouts/dashboard/layout.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useMemo } from 'react';
@@ -42,14 +41,39 @@ export function DashboardLayout({ sx, children, data }) {
const layoutQuery = 'lg';
- const navData = data?.nav ?? getNavData(user?.role);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const navData = useMemo(() => data?.nav ?? getNavData(user?.role), [data?.nav, user?.role]);
const isNavMini = settings.navLayout === 'mini';
-
- const isNavHorizontal = settings.navLayout === 'horizontal';
-
+ const isNavHorizontal = false; // горизонтальная навигация отключена
const isNavVertical = isNavMini || settings.navLayout === 'vertical';
+ const headerData = useMemo(
+ () => ({
+ nav: navData,
+ langs: allLangs,
+ account: _account,
+ contacts: _contacts,
+ workspaces: _workspaces,
+ notifications: _notifications,
+ }),
+ [navData]
+ );
+
+ const headerSlotsDisplay = useMemo(
+ () => ({
+ signIn: false,
+ purchase: false,
+ helpLink: false,
+ searchbar: false,
+ localization: false,
+ contacts: false,
+ workspaces: false,
+ account: false,
+ }),
+ []
+ );
+
return (
<>
diff --git a/front_minimal/src/layouts/dashboard/main.jsx b/front_minimal/src/layouts/dashboard/main.jsx
index b4f984e..9d31856 100644
--- a/front_minimal/src/layouts/dashboard/main.jsx
+++ b/front_minimal/src/layouts/dashboard/main.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import { useTheme } from '@mui/material/styles';
@@ -6,8 +5,6 @@ import Container from '@mui/material/Container';
import { layoutClasses } from 'src/layouts/classes';
-import { useSettingsContext } from 'src/components/settings';
-
// ----------------------------------------------------------------------
export function Main({ children, isNavHorizontal, sx, ...other }) {
@@ -36,14 +33,12 @@ export function Main({ children, isNavHorizontal, sx, ...other }) {
export function DashboardContent({ sx, children, disablePadding, maxWidth = 'lg', ...other }) {
const theme = useTheme();
- const settings = useSettingsContext();
-
const layoutQuery = 'lg';
return (
-
-
-);
+root.render();
diff --git a/front_minimal/src/routes/components/router-link.jsx b/front_minimal/src/routes/components/router-link.jsx
index 18dd053..a5d5095 100644
--- a/front_minimal/src/routes/components/router-link.jsx
+++ b/front_minimal/src/routes/components/router-link.jsx
@@ -1 +1,7 @@
-export { Link as RouterLink } from 'react-router-dom';
+import { forwardRef } from 'react';
+import { Link } from 'react-router-dom';
+
+// Bridge component: MUI passes `href` prop, react-router-dom Link uses `to`
+export const RouterLink = forwardRef(({ href, to, ...other }, ref) => (
+
+));
diff --git a/front_minimal/src/routes/hooks/use-search-params.js b/front_minimal/src/routes/hooks/use-search-params.js
index 7426398..0157ee5 100644
--- a/front_minimal/src/routes/hooks/use-search-params.js
+++ b/front_minimal/src/routes/hooks/use-search-params.js
@@ -1 +1,7 @@
-export { useSearchParams } from 'react-router-dom';
+import { useSearchParams as useRRSearchParams } from 'react-router-dom';
+
+// Next.js-compatible wrapper: returns searchParams object directly (not a tuple)
+export function useSearchParams() {
+ const [searchParams] = useRRSearchParams();
+ return searchParams;
+}
diff --git a/front_minimal/src/routes/sections.jsx b/front_minimal/src/routes/sections.jsx
index c0394e6..d7c17b4 100644
--- a/front_minimal/src/routes/sections.jsx
+++ b/front_minimal/src/routes/sections.jsx
@@ -7,7 +7,7 @@ import { GuestGuard } from 'src/auth/guard/guest-guard';
import { AuthSplitLayout } from 'src/layouts/auth-split';
import { DashboardLayout } from 'src/layouts/dashboard';
-import { SplashScreen } from 'src/components/loading-screen';
+import { LoadingScreen } from 'src/components/loading-screen';
// ----------------------------------------------------------------------
// Auth
@@ -102,12 +102,8 @@ const Page404 = lazy(() =>
// ----------------------------------------------------------------------
-function Loading() {
- return ;
-}
-
function S({ children }) {
- return }>{children};
+ return }>{children};
}
function DashboardLayoutWrapper() {
diff --git a/front_minimal/src/sections/_examples/extra/animate-view/view.jsx b/front_minimal/src/sections/_examples/extra/animate-view/view.jsx
index 212f11b..5cb5a11 100644
--- a/front_minimal/src/sections/_examples/extra/animate-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/animate-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
diff --git a/front_minimal/src/sections/_examples/extra/carousel-view/view.jsx b/front_minimal/src/sections/_examples/extra/carousel-view/view.jsx
index 2f32200..ecd3e56 100644
--- a/front_minimal/src/sections/_examples/extra/carousel-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/carousel-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/chart-view/view.jsx b/front_minimal/src/sections/_examples/extra/chart-view/view.jsx
index 130e271..eac78a4 100644
--- a/front_minimal/src/sections/_examples/extra/chart-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/chart-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/dnd-view/view.jsx b/front_minimal/src/sections/_examples/extra/dnd-view/view.jsx
index c68521e..bc68770 100644
--- a/front_minimal/src/sections/_examples/extra/dnd-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/dnd-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/editor-view/view.jsx b/front_minimal/src/sections/_examples/extra/editor-view/view.jsx
index e13248a..d671459 100644
--- a/front_minimal/src/sections/_examples/extra/editor-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/editor-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/form-validation-view/view.jsx b/front_minimal/src/sections/_examples/extra/form-validation-view/view.jsx
index f139e73..9d7cb58 100644
--- a/front_minimal/src/sections/_examples/extra/form-validation-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/form-validation-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/form-wizard-view/view.jsx b/front_minimal/src/sections/_examples/extra/form-wizard-view/view.jsx
index b1e7762..f035842 100644
--- a/front_minimal/src/sections/_examples/extra/form-wizard-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/form-wizard-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/image-view/view.jsx b/front_minimal/src/sections/_examples/extra/image-view/view.jsx
index 59837e1..e7910a3 100644
--- a/front_minimal/src/sections/_examples/extra/image-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/image-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/_examples/extra/label-view/view.jsx b/front_minimal/src/sections/_examples/extra/label-view/view.jsx
index 95888cd..09f9a60 100644
--- a/front_minimal/src/sections/_examples/extra/label-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/label-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Tooltip from '@mui/material/Tooltip';
diff --git a/front_minimal/src/sections/_examples/extra/lightbox-view/view.jsx b/front_minimal/src/sections/_examples/extra/lightbox-view/view.jsx
index c122636..00553f0 100644
--- a/front_minimal/src/sections/_examples/extra/lightbox-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/lightbox-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/map-view/view.jsx b/front_minimal/src/sections/_examples/extra/map-view/view.jsx
index 88aef0b..c421f6e 100644
--- a/front_minimal/src/sections/_examples/extra/map-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/map-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import dynamic from 'next/dynamic';
diff --git a/front_minimal/src/sections/_examples/extra/markdown-view/view.jsx b/front_minimal/src/sections/_examples/extra/markdown-view/view.jsx
index 4e733df..9331fac 100644
--- a/front_minimal/src/sections/_examples/extra/markdown-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/markdown-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/mega-menu-view/horizontal.jsx b/front_minimal/src/sections/_examples/extra/mega-menu-view/horizontal.jsx
index 95d56be..ca59c7c 100644
--- a/front_minimal/src/sections/_examples/extra/mega-menu-view/horizontal.jsx
+++ b/front_minimal/src/sections/_examples/extra/mega-menu-view/horizontal.jsx
@@ -1,4 +1,3 @@
-'use client';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
diff --git a/front_minimal/src/sections/_examples/extra/mega-menu-view/mobile.jsx b/front_minimal/src/sections/_examples/extra/mega-menu-view/mobile.jsx
index 1dbc7e9..8813e11 100644
--- a/front_minimal/src/sections/_examples/extra/mega-menu-view/mobile.jsx
+++ b/front_minimal/src/sections/_examples/extra/mega-menu-view/mobile.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/_examples/extra/mega-menu-view/view.jsx b/front_minimal/src/sections/_examples/extra/mega-menu-view/view.jsx
index e525aaf..dfdec8e 100644
--- a/front_minimal/src/sections/_examples/extra/mega-menu-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/mega-menu-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/multi-language-view/view.jsx b/front_minimal/src/sections/_examples/extra/multi-language-view/view.jsx
index ef5f6e4..e0fdaca 100644
--- a/front_minimal/src/sections/_examples/extra/multi-language-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/multi-language-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import dayjs from 'dayjs';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/navigation-bar-view/view.jsx b/front_minimal/src/sections/_examples/extra/navigation-bar-view/view.jsx
index d092c38..3336ce4 100644
--- a/front_minimal/src/sections/_examples/extra/navigation-bar-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/navigation-bar-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/organizational-chart-view/view.jsx b/front_minimal/src/sections/_examples/extra/organizational-chart-view/view.jsx
index fd2222b..df0b99e 100644
--- a/front_minimal/src/sections/_examples/extra/organizational-chart-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/organizational-chart-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Stack from '@mui/material/Stack';
import { useTheme } from '@mui/material/styles';
diff --git a/front_minimal/src/sections/_examples/extra/scroll-progress-view/view.jsx b/front_minimal/src/sections/_examples/extra/scroll-progress-view/view.jsx
index 3e3032a..9e8637f 100644
--- a/front_minimal/src/sections/_examples/extra/scroll-progress-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/scroll-progress-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
diff --git a/front_minimal/src/sections/_examples/extra/scrollbar-view/view.jsx b/front_minimal/src/sections/_examples/extra/scrollbar-view/view.jsx
index 0ebabf4..f56192a 100644
--- a/front_minimal/src/sections/_examples/extra/scrollbar-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/scrollbar-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
diff --git a/front_minimal/src/sections/_examples/extra/snackbar-view/view.jsx b/front_minimal/src/sections/_examples/extra/snackbar-view/view.jsx
index 620b73f..139a7f3 100644
--- a/front_minimal/src/sections/_examples/extra/snackbar-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/snackbar-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/_examples/extra/upload-view/view.jsx b/front_minimal/src/sections/_examples/extra/upload-view/view.jsx
index 0923250..9db6b3c 100644
--- a/front_minimal/src/sections/_examples/extra/upload-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/upload-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/utilities-view/copy-to-clipboard.jsx b/front_minimal/src/sections/_examples/extra/utilities-view/copy-to-clipboard.jsx
index c878302..e7b0b51 100644
--- a/front_minimal/src/sections/_examples/extra/utilities-view/copy-to-clipboard.jsx
+++ b/front_minimal/src/sections/_examples/extra/utilities-view/copy-to-clipboard.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/extra/utilities-view/view.jsx b/front_minimal/src/sections/_examples/extra/utilities-view/view.jsx
index 232d0b4..43b6aa5 100644
--- a/front_minimal/src/sections/_examples/extra/utilities-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/utilities-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/extra/walktour-view/view.jsx b/front_minimal/src/sections/_examples/extra/walktour-view/view.jsx
index dcbd63c..3203084 100644
--- a/front_minimal/src/sections/_examples/extra/walktour-view/view.jsx
+++ b/front_minimal/src/sections/_examples/extra/walktour-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/_examples/foundation/colors-view/view.jsx b/front_minimal/src/sections/_examples/foundation/colors-view/view.jsx
index 8920881..5c22332 100644
--- a/front_minimal/src/sections/_examples/foundation/colors-view/view.jsx
+++ b/front_minimal/src/sections/_examples/foundation/colors-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/_examples/foundation/grid-view/view.jsx b/front_minimal/src/sections/_examples/foundation/grid-view/view.jsx
index 599e3b5..dddc2b4 100644
--- a/front_minimal/src/sections/_examples/foundation/grid-view/view.jsx
+++ b/front_minimal/src/sections/_examples/foundation/grid-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/foundation/icons-view/view.jsx b/front_minimal/src/sections/_examples/foundation/icons-view/view.jsx
index 1d0fdbd..f321b64 100644
--- a/front_minimal/src/sections/_examples/foundation/icons-view/view.jsx
+++ b/front_minimal/src/sections/_examples/foundation/icons-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Link from '@mui/material/Link';
import Tooltip from '@mui/material/Tooltip';
diff --git a/front_minimal/src/sections/_examples/foundation/shadows-view/view.jsx b/front_minimal/src/sections/_examples/foundation/shadows-view/view.jsx
index 2055b2e..2a69ca1 100644
--- a/front_minimal/src/sections/_examples/foundation/shadows-view/view.jsx
+++ b/front_minimal/src/sections/_examples/foundation/shadows-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
diff --git a/front_minimal/src/sections/_examples/foundation/typography-view/view.jsx b/front_minimal/src/sections/_examples/foundation/typography-view/view.jsx
index 5d77869..ea6b7a8 100644
--- a/front_minimal/src/sections/_examples/foundation/typography-view/view.jsx
+++ b/front_minimal/src/sections/_examples/foundation/typography-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
diff --git a/front_minimal/src/sections/_examples/mui/accordion-view/view.jsx b/front_minimal/src/sections/_examples/mui/accordion-view/view.jsx
index ab886af..36c8370 100644
--- a/front_minimal/src/sections/_examples/mui/accordion-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/accordion-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/alert-view/view.jsx b/front_minimal/src/sections/_examples/mui/alert-view/view.jsx
index 80ac355..78f8a81 100644
--- a/front_minimal/src/sections/_examples/mui/alert-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/alert-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/_examples/mui/autocomplete-view/view.jsx b/front_minimal/src/sections/_examples/mui/autocomplete-view/view.jsx
index d11b0f6..14feb5b 100644
--- a/front_minimal/src/sections/_examples/mui/autocomplete-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/autocomplete-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/avatar-view/view.jsx b/front_minimal/src/sections/_examples/mui/avatar-view/view.jsx
index e863d05..d785d0b 100644
--- a/front_minimal/src/sections/_examples/mui/avatar-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/avatar-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Badge from '@mui/material/Badge';
import Avatar from '@mui/material/Avatar';
diff --git a/front_minimal/src/sections/_examples/mui/badge-view/view.jsx b/front_minimal/src/sections/_examples/mui/badge-view/view.jsx
index c3ea701..8d8fbc6 100644
--- a/front_minimal/src/sections/_examples/mui/badge-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/badge-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Badge from '@mui/material/Badge';
diff --git a/front_minimal/src/sections/_examples/mui/breadcrumbs-view/view.jsx b/front_minimal/src/sections/_examples/mui/breadcrumbs-view/view.jsx
index cdafae0..c40b92a 100644
--- a/front_minimal/src/sections/_examples/mui/breadcrumbs-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/breadcrumbs-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/_examples/mui/button-view/view.jsx b/front_minimal/src/sections/_examples/mui/button-view/view.jsx
index 1e3f364..64c8b50 100644
--- a/front_minimal/src/sections/_examples/mui/button-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/button-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/checkbox-view/view.jsx b/front_minimal/src/sections/_examples/mui/checkbox-view/view.jsx
index 909ac47..5ec8371 100644
--- a/front_minimal/src/sections/_examples/mui/checkbox-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/checkbox-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/chip-view/view.jsx b/front_minimal/src/sections/_examples/mui/chip-view/view.jsx
index e90d551..e564ed1 100644
--- a/front_minimal/src/sections/_examples/mui/chip-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/chip-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/data-grid-view/view.jsx b/front_minimal/src/sections/_examples/mui/data-grid-view/view.jsx
index 847e59c..60893b2 100644
--- a/front_minimal/src/sections/_examples/mui/data-grid-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/data-grid-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Link from '@mui/material/Link';
diff --git a/front_minimal/src/sections/_examples/mui/dialog-view/view.jsx b/front_minimal/src/sections/_examples/mui/dialog-view/view.jsx
index b9e042b..5eb785a 100644
--- a/front_minimal/src/sections/_examples/mui/dialog-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/dialog-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/list-view/view.jsx b/front_minimal/src/sections/_examples/mui/list-view/view.jsx
index 380ec37..7775d9d 100644
--- a/front_minimal/src/sections/_examples/mui/list-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/list-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/menu-view/view.jsx b/front_minimal/src/sections/_examples/mui/menu-view/view.jsx
index 39721df..9b0a090 100644
--- a/front_minimal/src/sections/_examples/mui/menu-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/menu-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/pagination-view/view.jsx b/front_minimal/src/sections/_examples/mui/pagination-view/view.jsx
index 66cd70a..1e76251 100644
--- a/front_minimal/src/sections/_examples/mui/pagination-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/pagination-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/picker-view/view.jsx b/front_minimal/src/sections/_examples/mui/picker-view/view.jsx
index d04f168..48efc22 100644
--- a/front_minimal/src/sections/_examples/mui/picker-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/picker-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/popover-view/view.jsx b/front_minimal/src/sections/_examples/mui/popover-view/view.jsx
index 1ce0628..c91a59a 100644
--- a/front_minimal/src/sections/_examples/mui/popover-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/popover-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useRef, useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/progress-view/view.jsx b/front_minimal/src/sections/_examples/mui/progress-view/view.jsx
index a70c97e..518e1ef 100644
--- a/front_minimal/src/sections/_examples/mui/progress-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/progress-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useRef, useState, useEffect } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/radio-button-view/view.jsx b/front_minimal/src/sections/_examples/mui/radio-button-view/view.jsx
index bfea7a9..ca512c1 100644
--- a/front_minimal/src/sections/_examples/mui/radio-button-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/radio-button-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/rating-view/view.jsx b/front_minimal/src/sections/_examples/mui/rating-view/view.jsx
index cd40fd4..f59bed6 100644
--- a/front_minimal/src/sections/_examples/mui/rating-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/rating-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/slider-view/view.jsx b/front_minimal/src/sections/_examples/mui/slider-view/view.jsx
index a0b68dd..91da144 100644
--- a/front_minimal/src/sections/_examples/mui/slider-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/slider-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/stepper-view/view.jsx b/front_minimal/src/sections/_examples/mui/stepper-view/view.jsx
index 9b2d764..bb74351 100644
--- a/front_minimal/src/sections/_examples/mui/stepper-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/stepper-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/switch-view/view.jsx b/front_minimal/src/sections/_examples/mui/switch-view/view.jsx
index a36df5f..b7a5ae1 100644
--- a/front_minimal/src/sections/_examples/mui/switch-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/switch-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Switch from '@mui/material/Switch';
import FormGroup from '@mui/material/FormGroup';
diff --git a/front_minimal/src/sections/_examples/mui/table-view/view.jsx b/front_minimal/src/sections/_examples/mui/table-view/view.jsx
index 0869a34..252ae36 100644
--- a/front_minimal/src/sections/_examples/mui/table-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/table-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/tabs-view/view.jsx b/front_minimal/src/sections/_examples/mui/tabs-view/view.jsx
index ed15b6e..7c94b20 100644
--- a/front_minimal/src/sections/_examples/mui/tabs-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/tabs-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { Fragment } from 'react';
diff --git a/front_minimal/src/sections/_examples/mui/textfield-view/view.jsx b/front_minimal/src/sections/_examples/mui/textfield-view/view.jsx
index 4eb4f0e..de088d0 100644
--- a/front_minimal/src/sections/_examples/mui/textfield-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/textfield-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/timeline-view/view.jsx b/front_minimal/src/sections/_examples/mui/timeline-view/view.jsx
index a1cb3cf..5e97a81 100644
--- a/front_minimal/src/sections/_examples/mui/timeline-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/timeline-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Paper from '@mui/material/Paper';
import Timeline from '@mui/lab/Timeline';
diff --git a/front_minimal/src/sections/_examples/mui/tooltip-view/view.jsx b/front_minimal/src/sections/_examples/mui/tooltip-view/view.jsx
index 386c613..cb621e6 100644
--- a/front_minimal/src/sections/_examples/mui/tooltip-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/tooltip-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/sections/_examples/mui/transfer-list-view/view.jsx b/front_minimal/src/sections/_examples/mui/transfer-list-view/view.jsx
index 153cfdf..8c0135b 100644
--- a/front_minimal/src/sections/_examples/mui/transfer-list-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/transfer-list-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/mui/tree-view/view.jsx b/front_minimal/src/sections/_examples/mui/tree-view/view.jsx
index 19fc4d7..a4ed231 100644
--- a/front_minimal/src/sections/_examples/mui/tree-view/view.jsx
+++ b/front_minimal/src/sections/_examples/mui/tree-view/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/_examples/view.jsx b/front_minimal/src/sections/_examples/view.jsx
index c17c571..ee03c6c 100644
--- a/front_minimal/src/sections/_examples/view.jsx
+++ b/front_minimal/src/sections/_examples/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/sections/about/view/about-view.jsx b/front_minimal/src/sections/about/view/about-view.jsx
index 35f7f1e..02b4a96 100644
--- a/front_minimal/src/sections/about/view/about-view.jsx
+++ b/front_minimal/src/sections/about/view/about-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { AboutHero } from '../about-hero';
import { AboutWhat } from '../about-what';
diff --git a/front_minimal/src/sections/account/view/user-account-view.jsx b/front_minimal/src/sections/account/view/user-account-view.jsx
index 26c3b8e..48e4a03 100644
--- a/front_minimal/src/sections/account/view/user-account-view.jsx
+++ b/front_minimal/src/sections/account/view/user-account-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Tab from '@mui/material/Tab';
import Tabs from '@mui/material/Tabs';
diff --git a/front_minimal/src/sections/auth-demo/centered/centered-reset-password-view.jsx b/front_minimal/src/sections/auth-demo/centered/centered-reset-password-view.jsx
index cf45b08..da23543 100644
--- a/front_minimal/src/sections/auth-demo/centered/centered-reset-password-view.jsx
+++ b/front_minimal/src/sections/auth-demo/centered/centered-reset-password-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/centered/centered-sign-in-view.jsx b/front_minimal/src/sections/auth-demo/centered/centered-sign-in-view.jsx
index 622e26e..53e5107 100644
--- a/front_minimal/src/sections/auth-demo/centered/centered-sign-in-view.jsx
+++ b/front_minimal/src/sections/auth-demo/centered/centered-sign-in-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/centered/centered-sign-up-view.jsx b/front_minimal/src/sections/auth-demo/centered/centered-sign-up-view.jsx
index 8b980e9..76069d2 100644
--- a/front_minimal/src/sections/auth-demo/centered/centered-sign-up-view.jsx
+++ b/front_minimal/src/sections/auth-demo/centered/centered-sign-up-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/centered/centered-update-password-view.jsx b/front_minimal/src/sections/auth-demo/centered/centered-update-password-view.jsx
index 7cc3a5c..7fa674c 100644
--- a/front_minimal/src/sections/auth-demo/centered/centered-update-password-view.jsx
+++ b/front_minimal/src/sections/auth-demo/centered/centered-update-password-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/centered/centered-verify-view.jsx b/front_minimal/src/sections/auth-demo/centered/centered-verify-view.jsx
index e568a1e..21dda86 100644
--- a/front_minimal/src/sections/auth-demo/centered/centered-verify-view.jsx
+++ b/front_minimal/src/sections/auth-demo/centered/centered-verify-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/split/split-reset-password-view.jsx b/front_minimal/src/sections/auth-demo/split/split-reset-password-view.jsx
index 01bc19a..2e31786 100644
--- a/front_minimal/src/sections/auth-demo/split/split-reset-password-view.jsx
+++ b/front_minimal/src/sections/auth-demo/split/split-reset-password-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/split/split-sign-in-view.jsx b/front_minimal/src/sections/auth-demo/split/split-sign-in-view.jsx
index 5b71de1..bd7a2b9 100644
--- a/front_minimal/src/sections/auth-demo/split/split-sign-in-view.jsx
+++ b/front_minimal/src/sections/auth-demo/split/split-sign-in-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/split/split-sign-up-view.jsx b/front_minimal/src/sections/auth-demo/split/split-sign-up-view.jsx
index d52c012..74c7a63 100644
--- a/front_minimal/src/sections/auth-demo/split/split-sign-up-view.jsx
+++ b/front_minimal/src/sections/auth-demo/split/split-sign-up-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/split/split-update-password-view.jsx b/front_minimal/src/sections/auth-demo/split/split-update-password-view.jsx
index 47e5f1c..a247f12 100644
--- a/front_minimal/src/sections/auth-demo/split/split-update-password-view.jsx
+++ b/front_minimal/src/sections/auth-demo/split/split-update-password-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth-demo/split/split-verify-view.jsx b/front_minimal/src/sections/auth-demo/split/split-verify-view.jsx
index 26fe9e0..360ac53 100644
--- a/front_minimal/src/sections/auth-demo/split/split-verify-view.jsx
+++ b/front_minimal/src/sections/auth-demo/split/split-verify-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { z as zod } from 'zod';
import { useForm } from 'react-hook-form';
diff --git a/front_minimal/src/sections/auth/jwt/jwt-reset-password-view.jsx b/front_minimal/src/sections/auth/jwt/jwt-reset-password-view.jsx
index 7dcab21..d7134ff 100644
--- a/front_minimal/src/sections/auth/jwt/jwt-reset-password-view.jsx
+++ b/front_minimal/src/sections/auth/jwt/jwt-reset-password-view.jsx
@@ -4,8 +4,6 @@ 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 'react-router-dom';
-
import Link from '@mui/material/Link';
import Alert from '@mui/material/Alert';
import Stack from '@mui/material/Stack';
@@ -15,7 +13,7 @@ import LoadingButton from '@mui/lab/LoadingButton';
import InputAdornment from '@mui/material/InputAdornment';
import { paths } from 'src/routes/paths';
-import { useRouter } from 'src/routes/hooks';
+import { useRouter, useSearchParams } from 'src/routes/hooks';
import { RouterLink } from 'src/routes/components';
import { useBoolean } from 'src/hooks/use-boolean';
diff --git a/front_minimal/src/sections/auth/jwt/jwt-sign-in-view.jsx b/front_minimal/src/sections/auth/jwt/jwt-sign-in-view.jsx
index 7db6236..a5fb65a 100644
--- a/front_minimal/src/sections/auth/jwt/jwt-sign-in-view.jsx
+++ b/front_minimal/src/sections/auth/jwt/jwt-sign-in-view.jsx
@@ -13,7 +13,7 @@ import LoadingButton from '@mui/lab/LoadingButton';
import InputAdornment from '@mui/material/InputAdornment';
import { paths } from 'src/routes/paths';
-import { useRouter } from 'src/routes/hooks';
+import { useRouter, useSearchParams } from 'src/routes/hooks';
import { RouterLink } from 'src/routes/components';
import { useBoolean } from 'src/hooks/use-boolean';
@@ -41,6 +41,7 @@ export const SignInSchema = zod.object({
export function JwtSignInView() {
const router = useRouter();
+ const searchParams = useSearchParams();
const { checkUserSession } = useAuthContext();
@@ -48,9 +49,11 @@ export function JwtSignInView() {
const password = useBoolean();
+ const returnTo = searchParams.get('returnTo') || paths.dashboard.root;
+
const defaultValues = {
- email: 'mentor@demo.uchill.online',
- password: 'demo123456',
+ email: '',
+ password: '',
};
const methods = useForm({
@@ -67,8 +70,7 @@ export function JwtSignInView() {
try {
await signInWithPassword({ email: data.email, password: data.password });
await checkUserSession?.();
-
- router.refresh();
+ router.replace(returnTo);
} catch (error) {
console.error(error);
setErrorMsg(error instanceof Error ? error.message : error);
@@ -77,15 +79,15 @@ export function JwtSignInView() {
const renderHead = (
- Sign in to your account
+ Войти в аккаунт
- {`Don't have an account?`}
+ Нет аккаунта?
- Get started
+ Зарегистрироваться
@@ -93,7 +95,7 @@ export function JwtSignInView() {
const renderForm = (
-
+
- Forgot password?
+ Забыли пароль?
- Sign in
+ Войти
);
@@ -142,12 +144,6 @@ export function JwtSignInView() {
<>
{renderHead}
-
- Use {defaultValues.email}
- {' with password '}
- {defaultValues.password}
-
-
{!!errorMsg && (
{errorMsg}
diff --git a/front_minimal/src/sections/auth/jwt/jwt-sign-up-view.jsx b/front_minimal/src/sections/auth/jwt/jwt-sign-up-view.jsx
index e215824..e9a23f9 100644
--- a/front_minimal/src/sections/auth/jwt/jwt-sign-up-view.jsx
+++ b/front_minimal/src/sections/auth/jwt/jwt-sign-up-view.jsx
@@ -1,7 +1,7 @@
import { z as zod } from 'zod';
-import { useState } from 'react';
-import { useForm } from 'react-hook-form';
+import { useState, useCallback, useEffect, useRef } from 'react';
+import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import Link from '@mui/material/Link';
@@ -10,8 +10,11 @@ import Stack from '@mui/material/Stack';
import MenuItem from '@mui/material/MenuItem';
import Checkbox from '@mui/material/Checkbox';
import IconButton from '@mui/material/IconButton';
+import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
+import Autocomplete from '@mui/material/Autocomplete';
import FormControlLabel from '@mui/material/FormControlLabel';
+import CircularProgress from '@mui/material/CircularProgress';
import LoadingButton from '@mui/lab/LoadingButton';
import InputAdornment from '@mui/material/InputAdornment';
@@ -26,32 +29,95 @@ import { Form, Field } from 'src/components/hook-form';
import { signUp } from 'src/auth/context/jwt';
import { useAuthContext } from 'src/auth/hooks';
+import { searchCities } from 'src/utils/profile-api';
// ----------------------------------------------------------------------
export const SignUpSchema = zod
.object({
- firstName: zod.string().min(1, { message: 'First name is required!' }),
- lastName: zod.string().min(1, { message: 'Last name is required!' }),
+ firstName: zod.string().min(1, { message: 'Введите имя!' }),
+ lastName: zod.string().min(1, { message: 'Введите фамилию!' }),
email: zod
.string()
- .min(1, { message: 'Email is required!' })
- .email({ message: 'Email must be a valid email address!' }),
- role: zod.enum(['mentor', 'client', 'parent'], { message: 'Role is required!' }),
- city: zod.string().min(1, { message: 'City is required!' }),
+ .min(1, { message: 'Введите email!' })
+ .email({ message: 'Введите корректный email!' }),
+ role: zod.enum(['mentor', 'client', 'parent'], { message: 'Выберите роль!' }),
+ city: zod.string().min(1, { message: 'Введите город!' }),
password: zod
.string()
- .min(1, { message: 'Password is required!' })
- .min(6, { message: 'Password must be at least 6 characters!' }),
- passwordConfirm: zod.string().min(1, { message: 'Please confirm your password!' }),
+ .min(1, { message: 'Введите пароль!' })
+ .min(8, { message: 'Пароль должен содержать минимум 8 символов!' }),
+ passwordConfirm: zod.string().min(1, { message: 'Подтвердите пароль!' }),
})
.refine((data) => data.password === data.passwordConfirm, {
- message: 'Passwords do not match!',
+ message: 'Пароли не совпадают!',
path: ['passwordConfirm'],
});
// ----------------------------------------------------------------------
+function CityAutocomplete({ value, onChange, error, helperText }) {
+ const [inputValue, setInputValue] = useState(value || '');
+ const [options, setOptions] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const timerRef = useRef(null);
+
+ const fetch = useCallback(async (query) => {
+ if (!query || query.length < 2) { setOptions([]); return; }
+ setLoading(true);
+ try {
+ const res = await searchCities(query, 30);
+ setOptions(res.map((c) => (typeof c === 'string' ? c : c.name || c.city || String(c))));
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ clearTimeout(timerRef.current);
+ timerRef.current = setTimeout(() => fetch(inputValue), 350);
+ return () => clearTimeout(timerRef.current);
+ }, [inputValue, fetch]);
+
+ return (
+ {
+ setInputValue(val);
+ onChange(val);
+ }}
+ onChange={(_, val) => {
+ if (val) { setInputValue(val); onChange(val); }
+ }}
+ noOptionsText="Города не найдены"
+ loadingText="Поиск..."
+ renderInput={(params) => (
+
+ {loading ? : null}
+ {params.InputProps.endAdornment}
+ >
+ ),
+ }}
+ />
+ )}
+ />
+ );
+}
+
+// ----------------------------------------------------------------------
+
export function JwtSignUpView() {
const { checkUserSession } = useAuthContext();
const router = useRouter();
@@ -79,13 +145,14 @@ export function JwtSignUpView() {
});
const {
+ control,
handleSubmit,
formState: { isSubmitting },
} = methods;
const onSubmit = handleSubmit(async (data) => {
if (!consent) {
- setErrorMsg('Please agree to the Terms of Service and Privacy Policy.');
+ setErrorMsg('Необходимо согласиться с условиями использования и политикой конфиденциальности.');
return;
}
@@ -102,31 +169,31 @@ export function JwtSignUpView() {
if (result?.requiresVerification) {
setSuccessMsg(
- `A confirmation email has been sent to ${data.email}. Please follow the link to verify your account.`
+ `Письмо с подтверждением отправлено на ${data.email}. Пройдите по ссылке в письме для активации аккаунта.`
);
return;
}
await checkUserSession?.();
- router.refresh();
+ router.replace(paths.dashboard.root);
} catch (error) {
console.error(error);
- const msg = error?.response?.data?.message || error?.response?.data?.detail || (error instanceof Error ? error.message : 'Registration error. Please check your data.');
+ const msg = error?.response?.data?.message || error?.response?.data?.detail || (error instanceof Error ? error.message : 'Ошибка регистрации. Проверьте введённые данные.');
setErrorMsg(msg);
}
});
const renderHead = (
- Get started absolutely free
+ Создать аккаунт
- Already have an account?
+ Уже есть аккаунт?
- Sign in
+ Войти
@@ -139,7 +206,7 @@ export function JwtSignUpView() {
{successMsg}
- Back to sign in
+ Вернуться ко входу
>
@@ -149,24 +216,35 @@ export function JwtSignUpView() {
const renderForm = (
-
-
+
+
-
+
-
-
-
-
+
+
+
+
-
+ (
+
+ )}
+ />
setConsent(e.target.checked)} />}
label={
- I agree to the{' '}
+ Я соглашаюсь с{' '}
- Terms of service
+ Условиями использования
{' '}
- and{' '}
+ и{' '}
- Privacy policy
+ Политикой конфиденциальности
}
@@ -220,9 +298,9 @@ export function JwtSignUpView() {
type="submit"
variant="contained"
loading={isSubmitting}
- loadingIndicator="Creating account..."
+ loadingIndicator="Создание аккаунта..."
>
- Create account
+ Зарегистрироваться
);
diff --git a/front_minimal/src/sections/auth/jwt/jwt-verify-email-view.jsx b/front_minimal/src/sections/auth/jwt/jwt-verify-email-view.jsx
index 627b9d6..8b686dd 100644
--- a/front_minimal/src/sections/auth/jwt/jwt-verify-email-view.jsx
+++ b/front_minimal/src/sections/auth/jwt/jwt-verify-email-view.jsx
@@ -1,7 +1,7 @@
'use client';
import { useState, useEffect, Suspense } from 'react';
-import { useSearchParams } from 'react-router-dom';
+import { useSearchParams } from 'src/routes/hooks';
import Link from '@mui/material/Link';
import Alert from '@mui/material/Alert';
diff --git a/front_minimal/src/sections/blank/view.jsx b/front_minimal/src/sections/blank/view.jsx
index e9b39ae..8ca99f1 100644
--- a/front_minimal/src/sections/blank/view.jsx
+++ b/front_minimal/src/sections/blank/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
diff --git a/front_minimal/src/sections/blog/view/post-create-view.jsx b/front_minimal/src/sections/blog/view/post-create-view.jsx
index 8a7cbe3..3d0eaf0 100644
--- a/front_minimal/src/sections/blog/view/post-create-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/blog/view/post-details-home-view.jsx b/front_minimal/src/sections/blog/view/post-details-home-view.jsx
index 31f43e0..8cc9e33 100644
--- a/front_minimal/src/sections/blog/view/post-details-home-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-details-home-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/blog/view/post-details-view.jsx b/front_minimal/src/sections/blog/view/post-details-view.jsx
index 58f5858..4b57893 100644
--- a/front_minimal/src/sections/blog/view/post-details-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/sections/blog/view/post-edit-view.jsx b/front_minimal/src/sections/blog/view/post-edit-view.jsx
index e65b881..631e53c 100644
--- a/front_minimal/src/sections/blog/view/post-edit-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/blog/view/post-list-home-view.jsx b/front_minimal/src/sections/blog/view/post-list-home-view.jsx
index 6c05068..654012a 100644
--- a/front_minimal/src/sections/blog/view/post-list-home-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-list-home-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/blog/view/post-list-view.jsx b/front_minimal/src/sections/blog/view/post-list-view.jsx
index 684caf2..9e613d6 100644
--- a/front_minimal/src/sections/blog/view/post-list-view.jsx
+++ b/front_minimal/src/sections/blog/view/post-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/board/view/board-view.jsx b/front_minimal/src/sections/board/view/board-view.jsx
index eba18fc..7054c45 100644
--- a/front_minimal/src/sections/board/view/board-view.jsx
+++ b/front_minimal/src/sections/board/view/board-view.jsx
@@ -1,5 +1,5 @@
import { useRef, useEffect, useState, useCallback } from 'react';
-import { useSearchParams } from 'react-router-dom';
+import { useSearchParams } from 'src/routes/hooks';
import { useRouter } from 'src/routes/hooks';
diff --git a/front_minimal/src/sections/calendar/view/calendar-view.jsx b/front_minimal/src/sections/calendar/view/calendar-view.jsx
index e881785..8ce1d78 100644
--- a/front_minimal/src/sections/calendar/view/calendar-view.jsx
+++ b/front_minimal/src/sections/calendar/view/calendar-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
diff --git a/front_minimal/src/sections/chat/view/chat-platform-view.jsx b/front_minimal/src/sections/chat/view/chat-platform-view.jsx
index 47a4666..c425c60 100644
--- a/front_minimal/src/sections/chat/view/chat-platform-view.jsx
+++ b/front_minimal/src/sections/chat/view/chat-platform-view.jsx
@@ -34,8 +34,11 @@ import {
getConversations,
markMessagesAsRead,
getChatMessagesByUuid,
+ normalizeChat,
} from 'src/utils/chat-api';
+import { getStudents, getMyMentors } from 'src/utils/students-api';
+
import { DashboardContent } from 'src/layouts/dashboard';
import { Iconify } from 'src/components/iconify';
@@ -121,12 +124,21 @@ function NewChatDialog({ open, onClose, onCreated }) {
return () => clearTimeout(timer);
}, [query, handleSearch]);
- const handleCreate = async (userId) => {
+ const handleCreate = async (user) => {
try {
setCreating(true);
setError(null);
- const chat = await createChat(userId);
- onCreated(chat);
+ const rawChat = await createChat(user.id);
+ const enriched = {
+ ...rawChat,
+ other_participant: rawChat?.other_participant ?? {
+ id: user.id,
+ first_name: user.first_name,
+ last_name: user.last_name,
+ avatar_url: user.avatar_url || user.avatar || null,
+ },
+ };
+ onCreated(enriched);
onClose();
} catch (e) {
setError(e?.response?.data?.detail || e?.message || 'Ошибка создания чата');
@@ -172,7 +184,7 @@ function NewChatDialog({ open, onClose, onCreated }) {
return (
handleCreate(u.id)}
+ onClick={() => handleCreate(u)}
disabled={creating}
sx={{ borderRadius: 1 }}
>
@@ -197,10 +209,13 @@ function NewChatDialog({ open, onClose, onCreated }) {
// ----------------------------------------------------------------------
-function ChatList({ chats, selectedUuid, onSelect, onNew, loading }) {
+function ChatList({ chats, selectedUuid, onSelect, onNew, loading, contacts, onStartChat, startingId }) {
const [q, setQ] = useState('');
- const filtered = chats.filter((c) => {
+ // ID пользователей у которых уже есть чат
+ const existingParticipantIds = new Set(chats.map((c) => c.participant_id).filter(Boolean));
+
+ const filteredChats = chats.filter((c) => {
if (!q.trim()) return true;
const qq = q.toLowerCase();
return (
@@ -209,6 +224,14 @@ function ChatList({ chats, selectedUuid, onSelect, onNew, loading }) {
);
});
+ const filteredContacts = contacts.filter((c) => {
+ if (existingParticipantIds.has(c.id)) return false;
+ if (!q.trim()) return true;
+ const qq = q.toLowerCase();
+ const name = `${c.first_name || ''} ${c.last_name || ''}`.toLowerCase();
+ return name.includes(qq) || (c.email || '').toLowerCase().includes(qq);
+ });
+
return (
- ) : filtered.length === 0 ? (
-
- {q ? 'Не найдено' : 'Нет чатов'}
-
) : (
-
- {filtered.map((chat) => {
- const selected = !!selectedUuid && chat.uuid === selectedUuid;
- return (
- onSelect(chat)}
- sx={{ py: 1.25, px: 1.5 }}
+ <>
+ {/* Существующие чаты */}
+ {filteredChats.length > 0 && (
+
+ {filteredChats.map((chat) => {
+ const selected = !!selectedUuid && chat.uuid === selectedUuid;
+ return (
+ onSelect(chat)}
+ sx={{ py: 1.25, px: 1.5 }}
+ >
+
+ {getInitials(chat.participant_name)}
+
+
+
+ {chat.participant_name || 'Чат'}
+
+ {!!chat.unread_count && (
+
+ )}
+
+ }
+ secondary={
+
+ {stripHtml(chat.last_message || '')}
+
+ }
+ primaryTypographyProps={{ component: 'div' }}
+ secondaryTypographyProps={{ component: 'div' }}
+ />
+
+ );
+ })}
+
+ )}
+
+ {/* Контакты без чата */}
+ {filteredContacts.length > 0 && (
+ <>
+ 0 ? 1.5 : 1, pb: 0.5, display: 'block', color: 'text.disabled' }}
>
-
- {getInitials(chat.participant_name)}
-
-
-
- {chat.participant_name || 'Чат'}
-
- {!!chat.unread_count && (
-
+ Контакты
+
+
+ {filteredContacts.map((contact) => {
+ const name = `${contact.first_name || ''} ${contact.last_name || ''}`.trim() || contact.email || '—';
+ const isStarting = startingId === contact.id;
+ return (
+ onStartChat(contact)}
+ disabled={isStarting}
+ sx={{ py: 1.25, px: 1.5, opacity: isStarting ? 0.6 : 1 }}
+ >
+
+ {getInitials(name)}
+
+
+ {name}
+
+ }
+ secondary={
+
+ {isStarting ? 'Создание чата...' : 'Начать диалог'}
+
+ }
+ primaryTypographyProps={{ component: 'div' }}
+ secondaryTypographyProps={{ component: 'div' }}
+ />
+ {isStarting ? (
+
+ ) : (
+
)}
-
- }
- secondary={
-
- {stripHtml(chat.last_message || '')}
-
- }
- primaryTypographyProps={{ component: 'div' }}
- secondaryTypographyProps={{ component: 'div' }}
- />
-
- );
- })}
-
+
+ );
+ })}
+
+ >
+ )}
+
+ {filteredChats.length === 0 && filteredContacts.length === 0 && (
+
+
+
+ {q ? 'Ничего не найдено' : 'Нет чатов и контактов'}
+
+
+ )}
+ >
)}
@@ -307,6 +389,7 @@ function ChatWindow({ chat, currentUserId, onBack }) {
const [hasMore, setHasMore] = useState(false);
const [text, setText] = useState('');
const [sending, setSending] = useState(false);
+ const [sendError, setSendError] = useState(null);
const listRef = useRef(null);
const markedRef = useRef(new Set());
const lastSentRef = useRef(null);
@@ -447,6 +530,7 @@ function ChatWindow({ chat, currentUserId, onBack }) {
if (!chat || !text.trim() || sending) return;
const content = text.trim();
setText('');
+ setSendError(null);
setSending(true);
try {
const msg = await sendMessage(chat.id, content);
@@ -459,8 +543,10 @@ function ChatWindow({ chat, currentUserId, onBack }) {
if (el) el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
});
});
- } catch {
+ } catch (e) {
setText(content);
+ const errMsg = e?.response?.data?.error?.message || e?.response?.data?.detail || e?.message || 'Ошибка отправки';
+ setSendError(errMsg);
} finally {
setSending(false);
}
@@ -620,6 +706,11 @@ function ChatWindow({ chat, currentUserId, onBack }) {
{/* Input */}
+ {sendError && (
+ setSendError(null)} sx={{ mx: 1.5, mt: 1, borderRadius: 1 }}>
+ {sendError}
+
+ )}
{
try {
- const res = await getConversations({ page_size: 50 });
- setChats(res.results);
+ setLoading(true);
+ const [chatsRes, contactsRes] = await Promise.allSettled([
+ getConversations({ page_size: 100 }),
+ user?.role === 'mentor'
+ ? getStudents({ page_size: 100 }).then((r) => r.results.map((s) => ({ ...s.user, id: s.user?.id })).filter(Boolean))
+ : getMyMentors().then((list) => (Array.isArray(list) ? list : [])),
+ ]);
+
+ if (chatsRes.status === 'fulfilled') setChats(chatsRes.value.results ?? []);
+ if (contactsRes.status === 'fulfilled') setContacts(contactsRes.value ?? []);
} catch (e) {
- setError(e?.response?.data?.detail || e?.message || 'Ошибка загрузки чатов');
+ setError(e?.response?.data?.detail || e?.message || 'Ошибка загрузки');
} finally {
setLoading(false);
}
- }, []);
+ }, [user?.role]);
useEffect(() => {
load();
}, [load]);
- const handleChatCreated = (chat) => {
+ const handleChatCreated = useCallback((rawChat) => {
+ const chat = normalizeChat(rawChat);
setChats((prev) => {
const exists = prev.some((c) => c.uuid === chat.uuid || c.id === chat.id);
if (exists) return prev;
return [chat, ...prev];
});
setSelectedChat(chat);
- };
+ }, []);
+
+ const handleStartChat = useCallback(async (contact) => {
+ const existing = chats.find((c) => c.participant_id === contact.id);
+ if (existing) { setSelectedChat(existing); return; }
+ try {
+ setStartingId(contact.id);
+ const rawChat = await createChat(contact.id);
+ // Если бэкенд не вернул other_participant — заполняем из данных контакта,
+ // чтобы normalizeChat правильно выставил participant_id и имя
+ const enriched = {
+ ...rawChat,
+ other_participant: rawChat?.other_participant ?? {
+ id: contact.id,
+ first_name: contact.first_name,
+ last_name: contact.last_name,
+ avatar_url: contact.avatar_url || contact.avatar || null,
+ },
+ };
+ handleChatCreated(enriched);
+ } catch (e) {
+ setError(e?.response?.data?.detail || e?.message || 'Ошибка создания чата');
+ } finally {
+ setStartingId(null);
+ }
+ }, [chats, handleChatCreated]);
return (
@@ -704,9 +831,12 @@ export function ChatPlatformView() {
setNewChatOpen(true)}
+ onStartChat={handleStartChat}
+ startingId={startingId}
loading={loading}
/>
diff --git a/front_minimal/src/sections/chat/view/chat-view.jsx b/front_minimal/src/sections/chat/view/chat-view.jsx
index 0e057b3..959fabf 100644
--- a/front_minimal/src/sections/chat/view/chat-view.jsx
+++ b/front_minimal/src/sections/chat/view/chat-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/sections/checkout/context/checkout-provider.jsx b/front_minimal/src/sections/checkout/context/checkout-provider.jsx
index 768f4ff..79804ba 100644
--- a/front_minimal/src/sections/checkout/context/checkout-provider.jsx
+++ b/front_minimal/src/sections/checkout/context/checkout-provider.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useMemo, Suspense, useEffect, useCallback, createContext } from 'react';
diff --git a/front_minimal/src/sections/checkout/context/use-checkout-context.jsx b/front_minimal/src/sections/checkout/context/use-checkout-context.jsx
index 004436b..1fbe110 100644
--- a/front_minimal/src/sections/checkout/context/use-checkout-context.jsx
+++ b/front_minimal/src/sections/checkout/context/use-checkout-context.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useContext } from 'react';
diff --git a/front_minimal/src/sections/checkout/view/checkout-view.jsx b/front_minimal/src/sections/checkout/view/checkout-view.jsx
index 3ad0874..5e00bb4 100644
--- a/front_minimal/src/sections/checkout/view/checkout-view.jsx
+++ b/front_minimal/src/sections/checkout/view/checkout-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useEffect } from 'react';
diff --git a/front_minimal/src/sections/children/view/children-progress-view.jsx b/front_minimal/src/sections/children/view/children-progress-view.jsx
index 83fcfac..942d245 100644
--- a/front_minimal/src/sections/children/view/children-progress-view.jsx
+++ b/front_minimal/src/sections/children/view/children-progress-view.jsx
@@ -1,8 +1,7 @@
'use client';
-import { useState, useEffect, useCallback } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import { useRouter } from 'src/routes/hooks';
+import { useState, useEffect, useCallback } from 'react';
+import { useRouter, useSearchParams } from 'src/routes/hooks';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
@@ -10,14 +9,14 @@ import Stack from '@mui/material/Stack';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
-import CardContent from '@mui/material/CardContent';
+import CardContent from '@mui/material/CardContent';
import CircularProgress from '@mui/material/CircularProgress';
import { paths } from 'src/routes/paths';
import axios from 'src/utils/axios';
-import { DashboardContent } from 'src/layouts/dashboard';
+import { DashboardContent } from 'src/layouts/dashboard';
import { Iconify } from 'src/components/iconify';
import { CustomBreadcrumbs } from 'src/components/custom-breadcrumbs';
diff --git a/front_minimal/src/sections/coming-soon/view.jsx b/front_minimal/src/sections/coming-soon/view.jsx
index d68fac1..19dd42e 100644
--- a/front_minimal/src/sections/coming-soon/view.jsx
+++ b/front_minimal/src/sections/coming-soon/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/contact/view/contact-view.jsx b/front_minimal/src/sections/contact/view/contact-view.jsx
index 0aa06c3..0acb592 100644
--- a/front_minimal/src/sections/contact/view/contact-view.jsx
+++ b/front_minimal/src/sections/contact/view/contact-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
diff --git a/front_minimal/src/sections/error/403-view.jsx b/front_minimal/src/sections/error/403-view.jsx
index 3ef7917..eaeb3b6 100644
--- a/front_minimal/src/sections/error/403-view.jsx
+++ b/front_minimal/src/sections/error/403-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/sections/error/500-view.jsx b/front_minimal/src/sections/error/500-view.jsx
index e16dbd6..06b1e35 100644
--- a/front_minimal/src/sections/error/500-view.jsx
+++ b/front_minimal/src/sections/error/500-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/sections/error/not-found-view.jsx b/front_minimal/src/sections/error/not-found-view.jsx
index 80e31e4..80e8e2d 100644
--- a/front_minimal/src/sections/error/not-found-view.jsx
+++ b/front_minimal/src/sections/error/not-found-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { m } from 'framer-motion';
diff --git a/front_minimal/src/sections/faqs/view/faqs-view.jsx b/front_minimal/src/sections/faqs/view/faqs-view.jsx
index 91c8cf0..0741726 100644
--- a/front_minimal/src/sections/faqs/view/faqs-view.jsx
+++ b/front_minimal/src/sections/faqs/view/faqs-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
diff --git a/front_minimal/src/sections/file-manager/view/file-manager-view.jsx b/front_minimal/src/sections/file-manager/view/file-manager-view.jsx
index a68ebff..20d694d 100644
--- a/front_minimal/src/sections/file-manager/view/file-manager-view.jsx
+++ b/front_minimal/src/sections/file-manager/view/file-manager-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/home/view/home-view.jsx b/front_minimal/src/sections/home/view/home-view.jsx
index dfea790..8c4fbe8 100644
--- a/front_minimal/src/sections/home/view/home-view.jsx
+++ b/front_minimal/src/sections/home/view/home-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/invoice/view/invoice-create-view.jsx b/front_minimal/src/sections/invoice/view/invoice-create-view.jsx
index 79f79d1..1722530 100644
--- a/front_minimal/src/sections/invoice/view/invoice-create-view.jsx
+++ b/front_minimal/src/sections/invoice/view/invoice-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/invoice/view/invoice-details-view.jsx b/front_minimal/src/sections/invoice/view/invoice-details-view.jsx
index 78f447d..349038b 100644
--- a/front_minimal/src/sections/invoice/view/invoice-details-view.jsx
+++ b/front_minimal/src/sections/invoice/view/invoice-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/invoice/view/invoice-edit-view.jsx b/front_minimal/src/sections/invoice/view/invoice-edit-view.jsx
index 333f99f..87d932c 100644
--- a/front_minimal/src/sections/invoice/view/invoice-edit-view.jsx
+++ b/front_minimal/src/sections/invoice/view/invoice-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/invoice/view/invoice-list-view.jsx b/front_minimal/src/sections/invoice/view/invoice-list-view.jsx
index 9d70298..0b129e8 100644
--- a/front_minimal/src/sections/invoice/view/invoice-list-view.jsx
+++ b/front_minimal/src/sections/invoice/view/invoice-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/job/view/job-create-view.jsx b/front_minimal/src/sections/job/view/job-create-view.jsx
index 5e40c28..08c321c 100644
--- a/front_minimal/src/sections/job/view/job-create-view.jsx
+++ b/front_minimal/src/sections/job/view/job-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/job/view/job-details-view.jsx b/front_minimal/src/sections/job/view/job-details-view.jsx
index 54734f1..b828f08 100644
--- a/front_minimal/src/sections/job/view/job-details-view.jsx
+++ b/front_minimal/src/sections/job/view/job-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/job/view/job-edit-view.jsx b/front_minimal/src/sections/job/view/job-edit-view.jsx
index 905a269..03fcbb8 100644
--- a/front_minimal/src/sections/job/view/job-edit-view.jsx
+++ b/front_minimal/src/sections/job/view/job-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/job/view/job-list-view.jsx b/front_minimal/src/sections/job/view/job-list-view.jsx
index d6664e9..85b88b1 100644
--- a/front_minimal/src/sections/job/view/job-list-view.jsx
+++ b/front_minimal/src/sections/job/view/job-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/kanban/view/kanban-view.jsx b/front_minimal/src/sections/kanban/view/kanban-view.jsx
index b307052..2c9cafa 100644
--- a/front_minimal/src/sections/kanban/view/kanban-view.jsx
+++ b/front_minimal/src/sections/kanban/view/kanban-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useRef, useState, useEffect, useCallback } from 'react';
import {
diff --git a/front_minimal/src/sections/mail/view/mail-view.jsx b/front_minimal/src/sections/mail/view/mail-view.jsx
index 006e5e9..f31eaf2 100644
--- a/front_minimal/src/sections/mail/view/mail-view.jsx
+++ b/front_minimal/src/sections/mail/view/mail-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/sections/maintenance/view.jsx b/front_minimal/src/sections/maintenance/view.jsx
index c5e50ea..4986bc8 100644
--- a/front_minimal/src/sections/maintenance/view.jsx
+++ b/front_minimal/src/sections/maintenance/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/order/view/order-details-view.jsx b/front_minimal/src/sections/order/view/order-details-view.jsx
index edc19fb..4ecf751 100644
--- a/front_minimal/src/sections/order/view/order-details-view.jsx
+++ b/front_minimal/src/sections/order/view/order-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/order/view/order-list-view.jsx b/front_minimal/src/sections/order/view/order-list-view.jsx
index 7a592b5..0bcdd9c 100644
--- a/front_minimal/src/sections/order/view/order-list-view.jsx
+++ b/front_minimal/src/sections/order/view/order-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/overview/analytics/view/overview-analytics-view.jsx b/front_minimal/src/sections/overview/analytics/view/overview-analytics-view.jsx
index 8c5fe85..8e0b981 100644
--- a/front_minimal/src/sections/overview/analytics/view/overview-analytics-view.jsx
+++ b/front_minimal/src/sections/overview/analytics/view/overview-analytics-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Grid from '@mui/material/Unstable_Grid2';
import Typography from '@mui/material/Typography';
diff --git a/front_minimal/src/sections/overview/app/view/overview-app-view.jsx b/front_minimal/src/sections/overview/app/view/overview-app-view.jsx
index 212363d..03342da 100644
--- a/front_minimal/src/sections/overview/app/view/overview-app-view.jsx
+++ b/front_minimal/src/sections/overview/app/view/overview-app-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/overview/banking/view/overview-banking-view.jsx b/front_minimal/src/sections/overview/banking/view/overview-banking-view.jsx
index e295ede..734268d 100644
--- a/front_minimal/src/sections/overview/banking/view/overview-banking-view.jsx
+++ b/front_minimal/src/sections/overview/banking/view/overview-banking-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Unstable_Grid2';
diff --git a/front_minimal/src/sections/overview/booking/view/overview-booking-view.jsx b/front_minimal/src/sections/overview/booking/view/overview-booking-view.jsx
index 99e2958..d225ac4 100644
--- a/front_minimal/src/sections/overview/booking/view/overview-booking-view.jsx
+++ b/front_minimal/src/sections/overview/booking/view/overview-booking-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Unstable_Grid2';
diff --git a/front_minimal/src/sections/overview/client/view/overview-client-view.jsx b/front_minimal/src/sections/overview/client/view/overview-client-view.jsx
index 0e3712e..8bd5d5e 100644
--- a/front_minimal/src/sections/overview/client/view/overview-client-view.jsx
+++ b/front_minimal/src/sections/overview/client/view/overview-client-view.jsx
@@ -7,13 +7,16 @@ import Card from '@mui/material/Card';
import Stack from '@mui/material/Stack';
import Divider from '@mui/material/Divider';
import Avatar from '@mui/material/Avatar';
+import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
import LinearProgress from '@mui/material/LinearProgress';
import { useTheme } from '@mui/material/styles';
+import { useRouter } from 'src/routes/hooks';
import { fDateTime } from 'src/utils/format-time';
import { getClientDashboard, getChildDashboard } from 'src/utils/dashboard-api';
+import { createLiveKitRoom } from 'src/utils/livekit-api';
import { DashboardContent } from 'src/layouts/dashboard';
import { useAuthContext } from 'src/auth/hooks';
import { CONFIG } from 'src/config-global';
@@ -46,10 +49,30 @@ const formatDateTime = (str) => {
// ----------------------------------------------------------------------
function LessonItem({ lesson }) {
+ const router = useRouter();
+ const [joining, setJoining] = useState(false);
+
const mentorName = lesson.mentor
? `${lesson.mentor.first_name || ''} ${lesson.mentor.last_name || ''}`.trim() || 'Ментор'
: 'Ментор';
+ const now = new Date();
+ const startTime = new Date(lesson.start_time);
+ const diffMin = (startTime - now) / 60000;
+ const canJoin = diffMin < 11 && diffMin > -90;
+
+ const handleJoin = async () => {
+ try {
+ setJoining(true);
+ const res = await createLiveKitRoom(lesson.id);
+ const token = res?.access_token || res?.token;
+ router.push(`/video-call?token=${token}&lesson_id=${lesson.id}`);
+ } catch (err) {
+ console.error('Join error:', err);
+ setJoining(false);
+ }
+ };
+
return (
-
- {formatDateTime(lesson.start_time)}
-
+ {canJoin ? (
+ }
+ sx={{ flexShrink: 0, minWidth: 110 }}
+ >
+ {joining ? '...' : 'Подключиться'}
+
+ ) : (
+
+ {formatDateTime(lesson.start_time)}
+
+ )}
);
}
diff --git a/front_minimal/src/sections/overview/course/view/overview-course-view.jsx b/front_minimal/src/sections/overview/course/view/overview-course-view.jsx
index 16ac280..736e14d 100644
--- a/front_minimal/src/sections/overview/course/view/overview-course-view.jsx
+++ b/front_minimal/src/sections/overview/course/view/overview-course-view.jsx
@@ -1,16 +1,18 @@
-'use client';
import { useState, useEffect, useMemo, useCallback } from 'react';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
+import Chip from '@mui/material/Chip';
import Button from '@mui/material/Button';
import Avatar from '@mui/material/Avatar';
import Stack from '@mui/material/Stack';
+import Divider from '@mui/material/Divider';
import { useTheme } from '@mui/material/styles';
import { cardClasses } from '@mui/material/Card';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
+import { useRouter } from 'src/routes/hooks';
import { CONFIG } from 'src/config-global';
import { varAlpha } from 'src/theme/styles';
import { DashboardContent } from 'src/layouts/dashboard';
@@ -19,9 +21,11 @@ import { fDateTime } from 'src/utils/format-time';
import { fNumber } from 'src/utils/format-number';
import { AvatarShape } from 'src/assets/illustrations';
import { Image } from 'src/components/image';
+import { Iconify } from 'src/components/iconify';
// Статический импорт API
import { getMentorDashboard, getMentorIncome } from 'src/utils/dashboard-api';
+import { createLiveKitRoom } from 'src/utils/livekit-api';
import { CourseProgress } from '../course-progress';
import { CourseMyAccount } from '../course-my-account';
@@ -30,6 +34,128 @@ import { CourseWidgetSummary } from '../course-widget-summary';
// ----------------------------------------------------------------------
+function lessonTimeLabel(startTime) {
+ if (!startTime) return '—';
+ const d = new Date(startTime);
+ const today = new Date();
+ const tomorrow = new Date(today);
+ tomorrow.setDate(today.getDate() + 1);
+ const time = d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
+ if (d.toDateString() === today.toDateString()) return `Сегодня, ${time}`;
+ if (d.toDateString() === tomorrow.toDateString()) return `Завтра, ${time}`;
+ return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });
+}
+
+function UpcomingLessonCard({ lesson }) {
+ const router = useRouter();
+ const [joining, setJoining] = useState(false);
+
+ const now = new Date();
+ const startTime = new Date(lesson.start_time);
+ const diffMin = (startTime - now) / 60000;
+ const canJoin = diffMin < 11 && diffMin > -90;
+
+ const handleJoin = async () => {
+ try {
+ setJoining(true);
+ const res = await createLiveKitRoom(lesson.id);
+ const token = res?.access_token || res?.token;
+ router.push(`/video-call?token=${token}&lesson_id=${lesson.id}`);
+ } catch (err) {
+ console.error('Join error:', err);
+ setJoining(false);
+ }
+ };
+
+ const clientName = lesson.client?.name ||
+ `${lesson.client?.first_name || ''} ${lesson.client?.last_name || ''}`.trim() ||
+ 'Ученик';
+ const clientAvatar = lesson.client?.avatar || lesson.client?.avatar_url || '';
+ const clientInitial = (clientName[0] || 'У').toUpperCase();
+ const subject = lesson.title || lesson.subject || 'Занятие';
+ const timeLabel = lessonTimeLabel(lesson.start_time);
+
+ return (
+ `2px solid ${t.palette.success.main}`,
+ outlineOffset: '-2px',
+ }),
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: (t) => t.customShadows?.z16 || '0 8px 24px rgba(0,0,0,0.12)',
+ },
+ }}
+ >
+
+ {clientInitial}
+
+
+
+ {clientName}
+
+
+
+ {subject}
+
+
+
+
+
+ {timeLabel}
+
+
+
+ {canJoin ? (
+ }
+ >
+ {joining ? 'Подключение...' : 'Подключиться'}
+
+ ) : (
+
+ )}
+
+ );
+}
+
+// ----------------------------------------------------------------------
+
export function OverviewCourseView() {
const theme = useTheme();
const { user } = useAuthContext();
@@ -39,14 +165,14 @@ export function OverviewCourseView() {
const [loading, setLoading] = useState(true);
const [period, setPeriod] = useState('Месяц');
- // Фильтр активных уроков
+ // Уроки, к которым можно подключиться (< 11 мин до начала или не более 90 мин с начала)
const activeLessons = useMemo(() => {
const upcoming = stats?.upcoming_lessons || [];
const NOW = new Date();
return upcoming.filter((lesson) => {
const startTime = new Date(lesson.start_time);
const diffInMinutes = (startTime.getTime() - NOW.getTime()) / 60000;
- return diffInMinutes <= 10 && diffInMinutes > -60;
+ return diffInMinutes < 11 && diffInMinutes > -90;
});
}, [stats]);
@@ -188,11 +314,25 @@ export function OverviewCourseView() {
- {/* Активные уроки */}
-
- Активные уроки
- {activeLessons.length > 0 ? activeLessons.slice(0, 2).map((l) => renderCard(l, 'lesson')) : (
- Нет текущих уроков
+ {/* Ближайшие уроки */}
+
+
+ Ближайшие уроки
+ {activeLessons.length > 0 && (
+
+ )}
+
+ {(stats?.upcoming_lessons || []).length > 0 ? (
+
+ {stats.upcoming_lessons.slice(0, 3).map((lesson) => (
+
+ ))}
+
+ ) : (
+
+
+ Нет запланированных занятий
+
)}
diff --git a/front_minimal/src/sections/overview/e-commerce/view/overview-ecommerce-view.jsx b/front_minimal/src/sections/overview/e-commerce/view/overview-ecommerce-view.jsx
index e7402f9..d838511 100644
--- a/front_minimal/src/sections/overview/e-commerce/view/overview-ecommerce-view.jsx
+++ b/front_minimal/src/sections/overview/e-commerce/view/overview-ecommerce-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Button from '@mui/material/Button';
import { useTheme } from '@mui/material/styles';
diff --git a/front_minimal/src/sections/overview/file/view/overview-file-view.jsx b/front_minimal/src/sections/overview/file/view/overview-file-view.jsx
index a502c0a..7d515cb 100644
--- a/front_minimal/src/sections/overview/file/view/overview-file-view.jsx
+++ b/front_minimal/src/sections/overview/file/view/overview-file-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/payment/payment-methods.jsx b/front_minimal/src/sections/payment/payment-methods.jsx
index 7a559a4..893d4da 100644
--- a/front_minimal/src/sections/payment/payment-methods.jsx
+++ b/front_minimal/src/sections/payment/payment-methods.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/payment/view/payment-view.jsx b/front_minimal/src/sections/payment/view/payment-view.jsx
index 75b6c88..6aa0879 100644
--- a/front_minimal/src/sections/payment/view/payment-view.jsx
+++ b/front_minimal/src/sections/payment/view/payment-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Container from '@mui/material/Container';
diff --git a/front_minimal/src/sections/permission/view.jsx b/front_minimal/src/sections/permission/view.jsx
index bccceb5..268ed67 100644
--- a/front_minimal/src/sections/permission/view.jsx
+++ b/front_minimal/src/sections/permission/view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/pricing/view/pricing-view.jsx b/front_minimal/src/sections/pricing/view/pricing-view.jsx
index 5adffdb..caa1a8e 100644
--- a/front_minimal/src/sections/pricing/view/pricing-view.jsx
+++ b/front_minimal/src/sections/pricing/view/pricing-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
diff --git a/front_minimal/src/sections/product/product-skeleton.jsx b/front_minimal/src/sections/product/product-skeleton.jsx
index 9a0f991..736f879 100644
--- a/front_minimal/src/sections/product/product-skeleton.jsx
+++ b/front_minimal/src/sections/product/product-skeleton.jsx
@@ -1,4 +1,3 @@
-'use client';
import Stack from '@mui/material/Stack';
import Paper from '@mui/material/Paper';
diff --git a/front_minimal/src/sections/product/view/product-create-view.jsx b/front_minimal/src/sections/product/view/product-create-view.jsx
index 8be141f..9b046e8 100644
--- a/front_minimal/src/sections/product/view/product-create-view.jsx
+++ b/front_minimal/src/sections/product/view/product-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/product/view/product-details-view.jsx b/front_minimal/src/sections/product/view/product-details-view.jsx
index 5064783..82702d5 100644
--- a/front_minimal/src/sections/product/view/product-details-view.jsx
+++ b/front_minimal/src/sections/product/view/product-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/sections/product/view/product-edit-view.jsx b/front_minimal/src/sections/product/view/product-edit-view.jsx
index 4781f59..89fdc3d 100644
--- a/front_minimal/src/sections/product/view/product-edit-view.jsx
+++ b/front_minimal/src/sections/product/view/product-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/product/view/product-list-view.jsx b/front_minimal/src/sections/product/view/product-list-view.jsx
index e7a4674..ae3af83 100644
--- a/front_minimal/src/sections/product/view/product-list-view.jsx
+++ b/front_minimal/src/sections/product/view/product-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useEffect, useCallback } from 'react';
diff --git a/front_minimal/src/sections/product/view/product-shop-details-view.jsx b/front_minimal/src/sections/product/view/product-shop-details-view.jsx
index 7e9c5e1..504bcdc 100644
--- a/front_minimal/src/sections/product/view/product-shop-details-view.jsx
+++ b/front_minimal/src/sections/product/view/product-shop-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
diff --git a/front_minimal/src/sections/product/view/product-shop-view.jsx b/front_minimal/src/sections/product/view/product-shop-view.jsx
index ac124f9..cab9e79 100644
--- a/front_minimal/src/sections/product/view/product-shop-view.jsx
+++ b/front_minimal/src/sections/product/view/product-shop-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/students/view/students-view.jsx b/front_minimal/src/sections/students/view/students-view.jsx
index 9a11205..b2c1d1f 100644
--- a/front_minimal/src/sections/students/view/students-view.jsx
+++ b/front_minimal/src/sections/students/view/students-view.jsx
@@ -5,6 +5,8 @@ import { useState, useEffect, useCallback } from 'react';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
+import Chip from '@mui/material/Chip';
+import Grid from '@mui/material/Grid';
import Tabs from '@mui/material/Tabs';
import List from '@mui/material/List';
import Stack from '@mui/material/Stack';
@@ -26,7 +28,7 @@ import InputAdornment from '@mui/material/InputAdornment';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import CircularProgress from '@mui/material/CircularProgress';
-import { paths } from 'src/routes/paths';
+import { paths } from 'src/routes/paths';
import {
getStudents,
@@ -39,13 +41,13 @@ import {
rejectInvitationAsStudent,
confirmInvitationAsStudent,
getMentorshipRequestsPending,
-} from 'src/utils/students-api';
+} from 'src/utils/students-api';
import { CONFIG } from 'src/config-global';
-import { DashboardContent } from 'src/layouts/dashboard';
+import { DashboardContent } from 'src/layouts/dashboard';
import { Iconify } from 'src/components/iconify';
-import { CustomBreadcrumbs } from 'src/components/custom-breadcrumbs';
+import { CustomBreadcrumbs } from 'src/components/custom-breadcrumbs';
import { useAuthContext } from 'src/auth/hooks';
@@ -99,7 +101,7 @@ function MentorStudentList({ onRefresh }) {
if (loading) return ;
return (
-
+
{error}}
{filtered.length === 0 ? (
-
- {search ? 'Ничего не найдено' : 'Нет учеников'}
-
+
+
+
+ {search ? 'Ничего не найдено' : 'Нет учеников'}
+
+
) : (
-
+
{filtered.map((s) => {
const u = s.user || {};
+ const name = `${u.first_name || ''} ${u.last_name || ''}`.trim() || u.email || '—';
return (
-
-
-
+
+ t.customShadows?.z16 || '0 8px 24px rgba(0,0,0,0.12)',
+ },
+ }}
+ >
+
{initials(u.first_name, u.last_name)}
-
-
- {s.total_lessons != null && (
-
- {s.total_lessons} уроков
+
+
+ {name}
- )}
-
+
+ {u.email || ''}
+
+
+
+ {s.total_lessons != null && (
+ }
+ />
+ )}
+ {s.subject && (
+
+ )}
+
+
+
);
})}
-
+
)}
);
@@ -309,31 +346,59 @@ function ClientMentorList() {
.finally(() => setLoading(false));
}, []);
- if (loading) return ;
+ if (loading) return ;
+
+ if (mentors.length === 0) {
+ return (
+
+
+ Нет подключённых менторов
+
+ );
+ }
return (
-
- Мои менторы
- {mentors.length === 0 ? (
- Нет подключённых менторов
- ) : (
-
- {mentors.map((m) => (
-
-
-
- {initials(m.first_name, m.last_name)}
-
-
-
-
- ))}
-
- )}
-
+
+ {mentors.map((m) => {
+ const name = `${m.first_name || ''} ${m.last_name || ''}`.trim() || m.email || '—';
+ return (
+
+ t.customShadows?.z16 || '0 8px 24px rgba(0,0,0,0.12)',
+ },
+ }}
+ >
+
+ {initials(m.first_name, m.last_name)}
+
+
+ {name}
+
+
+ {m.email || ''}
+
+
+
+ );
+ })}
+
);
}
diff --git a/front_minimal/src/sections/tour/view/tour-create-view.jsx b/front_minimal/src/sections/tour/view/tour-create-view.jsx
index 714e294..a3f48b3 100644
--- a/front_minimal/src/sections/tour/view/tour-create-view.jsx
+++ b/front_minimal/src/sections/tour/view/tour-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/tour/view/tour-details-view.jsx b/front_minimal/src/sections/tour/view/tour-details-view.jsx
index 9fb6e04..812c79f 100644
--- a/front_minimal/src/sections/tour/view/tour-details-view.jsx
+++ b/front_minimal/src/sections/tour/view/tour-details-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/tour/view/tour-edit-view.jsx b/front_minimal/src/sections/tour/view/tour-edit-view.jsx
index d164f5c..3359886 100644
--- a/front_minimal/src/sections/tour/view/tour-edit-view.jsx
+++ b/front_minimal/src/sections/tour/view/tour-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/tour/view/tour-list-view.jsx b/front_minimal/src/sections/tour/view/tour-list-view.jsx
index 572bbd5..a8c4a60 100644
--- a/front_minimal/src/sections/tour/view/tour-list-view.jsx
+++ b/front_minimal/src/sections/tour/view/tour-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/user/profile-followers.jsx b/front_minimal/src/sections/user/profile-followers.jsx
index 0dc1a59..4864b05 100644
--- a/front_minimal/src/sections/user/profile-followers.jsx
+++ b/front_minimal/src/sections/user/profile-followers.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/user/profile-home.jsx b/front_minimal/src/sections/user/profile-home.jsx
index 9c65f4b..56fd5da 100644
--- a/front_minimal/src/sections/user/profile-home.jsx
+++ b/front_minimal/src/sections/user/profile-home.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useRef } from 'react';
diff --git a/front_minimal/src/sections/user/view/user-cards-view.jsx b/front_minimal/src/sections/user/view/user-cards-view.jsx
index b53b64a..a70d210 100644
--- a/front_minimal/src/sections/user/view/user-cards-view.jsx
+++ b/front_minimal/src/sections/user/view/user-cards-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import Button from '@mui/material/Button';
diff --git a/front_minimal/src/sections/user/view/user-create-view.jsx b/front_minimal/src/sections/user/view/user-create-view.jsx
index 5ad5df5..7c5e947 100644
--- a/front_minimal/src/sections/user/view/user-create-view.jsx
+++ b/front_minimal/src/sections/user/view/user-create-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/user/view/user-edit-view.jsx b/front_minimal/src/sections/user/view/user-edit-view.jsx
index adb7e54..94ef42c 100644
--- a/front_minimal/src/sections/user/view/user-edit-view.jsx
+++ b/front_minimal/src/sections/user/view/user-edit-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { paths } from 'src/routes/paths';
diff --git a/front_minimal/src/sections/user/view/user-list-view.jsx b/front_minimal/src/sections/user/view/user-list-view.jsx
index d4baa8d..8911a95 100644
--- a/front_minimal/src/sections/user/view/user-list-view.jsx
+++ b/front_minimal/src/sections/user/view/user-list-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/user/view/user-profile-view.jsx b/front_minimal/src/sections/user/view/user-profile-view.jsx
index 1c3213b..973aa15 100644
--- a/front_minimal/src/sections/user/view/user-profile-view.jsx
+++ b/front_minimal/src/sections/user/view/user-profile-view.jsx
@@ -1,4 +1,3 @@
-'use client';
import { useState, useCallback } from 'react';
diff --git a/front_minimal/src/sections/video-call/view/video-call-view.jsx b/front_minimal/src/sections/video-call/view/video-call-view.jsx
index b0e9052..6675b2d 100644
--- a/front_minimal/src/sections/video-call/view/video-call-view.jsx
+++ b/front_minimal/src/sections/video-call/view/video-call-view.jsx
@@ -5,8 +5,7 @@ import 'src/styles/livekit-components.css';
import { createPortal } from 'react-dom';
import { isTrackReference } from '@livekit/components-core';
-import { useSearchParams } from 'react-router-dom';
-import { useRouter } from 'src/routes/hooks';
+import { useRouter, useSearchParams } from 'src/routes/hooks';
import { useRef, useState, useEffect, Component } from 'react';
import { Track, RoomEvent, VideoPresets } from 'livekit-client';
import {
diff --git a/front_minimal/src/theme/color-scheme-script.js b/front_minimal/src/theme/color-scheme-script.js
index e780bd1..59da447 100644
--- a/front_minimal/src/theme/color-scheme-script.js
+++ b/front_minimal/src/theme/color-scheme-script.js
@@ -1,4 +1,3 @@
-'use client';
import { getInitColorSchemeScript as _getInitColorSchemeScript } from '@mui/material/styles';
diff --git a/front_minimal/src/theme/theme-provider.jsx b/front_minimal/src/theme/theme-provider.jsx
index 91e3531..d95e234 100644
--- a/front_minimal/src/theme/theme-provider.jsx
+++ b/front_minimal/src/theme/theme-provider.jsx
@@ -1,4 +1,5 @@
import CssBaseline from '@mui/material/CssBaseline';
+import GlobalStyles from '@mui/material/GlobalStyles';
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
import { useTranslate } from 'src/locales';
@@ -25,6 +26,41 @@ export function ThemeProvider({ children }) {
modeStorageKey={schemeConfig.modeStorageKey}
>
+ ({
+ /* Firefox */
+ '*': {
+ scrollbarWidth: 'thin',
+ scrollbarColor: `${theme.vars.palette.grey[400]} transparent`,
+ },
+ /* Webkit (Chrome, Safari, Edge) */
+ '*::-webkit-scrollbar': {
+ width: 6,
+ height: 6,
+ },
+ '*::-webkit-scrollbar-track': {
+ background: 'transparent',
+ },
+ '*::-webkit-scrollbar-thumb': {
+ background: theme.vars.palette.grey[400],
+ borderRadius: 99,
+ },
+ '*::-webkit-scrollbar-thumb:hover': {
+ background: theme.vars.palette.grey[500],
+ },
+ [theme.getColorSchemeSelector('dark')]: {
+ '*': {
+ scrollbarColor: `${theme.vars.palette.grey[700]} transparent`,
+ },
+ '*::-webkit-scrollbar-thumb': {
+ background: theme.vars.palette.grey[700],
+ },
+ '*::-webkit-scrollbar-thumb:hover': {
+ background: theme.vars.palette.grey[600],
+ },
+ },
+ })}
+ />
{children}
);
diff --git a/front_minimal/src/utils/chat-api.js b/front_minimal/src/utils/chat-api.js
index d33e727..8342e82 100644
--- a/front_minimal/src/utils/chat-api.js
+++ b/front_minimal/src/utils/chat-api.js
@@ -2,15 +2,34 @@ import axios from 'src/utils/axios';
// ----------------------------------------------------------------------
+export function normalizeChat(c) {
+ const other = c?.other_participant ?? {};
+ const name =
+ other.full_name ||
+ [other.first_name, other.last_name].filter(Boolean).join(' ') ||
+ c?.participant_name ||
+ 'Чат';
+ const lastText = c?.last_message?.content || c?.last_message?.text || c?.last_message || '';
+ return {
+ ...c,
+ participant_name: name,
+ participant_id: other.id ?? c?.other_user_id ?? c?.participant_id ?? null,
+ avatar_url: other.avatar_url || other.avatar || c?.avatar_url || null,
+ last_message: lastText,
+ unread_count: c?.my_participant?.unread_count ?? c?.unread_count ?? 0,
+ };
+}
+
export async function getConversations(params) {
const res = await axios.get('/chat/chats/', { params });
const {data} = res;
- if (Array.isArray(data)) return { count: data.length, next: null, previous: null, results: data };
+ const raw = Array.isArray(data) ? data : (data?.results ?? []);
+ const results = raw.map(normalizeChat);
return {
- count: data?.count ?? (data?.results?.length ?? 0),
+ count: Array.isArray(data) ? data.length : (data?.count ?? results.length),
next: data?.next ?? null,
previous: data?.previous ?? null,
- results: data?.results ?? [],
+ results,
};
}
@@ -19,9 +38,11 @@ export async function getChatById(uuid) {
return res.data;
}
-export async function createChat(participantId) {
- const res = await axios.post('/chat/chats/', { participants: [participantId] });
- return res.data;
+export async function createChat(userId) {
+ const res = await axios.post('/chat/chats/create_direct/', { user_id: userId });
+ const { data } = res;
+ if (data && typeof data === 'object' && 'data' in data && typeof data.data === 'object') return data.data;
+ return data;
}
export async function getChatMessagesByUuid(chatUuid, params) {
@@ -35,13 +56,20 @@ export async function getMessages(chatId, params) {
}
export async function sendMessage(chatId, content, file) {
- const formData = new FormData();
- formData.append('chat', String(chatId));
- formData.append('content', content);
- if (file) formData.append('file', file);
- const res = await axios.post('/chat/messages/', formData);
- const {data} = res;
- if (data && typeof data === 'object' && 'data' in data) return data.data;
+ let res;
+ if (file) {
+ const formData = new FormData();
+ formData.append('chat', String(chatId));
+ formData.append('content', content);
+ formData.append('file', file);
+ res = await axios.post('/chat/messages/', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ } else {
+ res = await axios.post('/chat/messages/', { chat: chatId, content });
+ }
+ const { data } = res;
+ if (data && typeof data === 'object' && 'data' in data && typeof data.data === 'object') return data.data;
return data;
}