diff --git a/package-lock.json b/package-lock.json
index ad1da57..6b0a30b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.2.0",
"@mui/material": "^7.2.0",
+ "framer-motion": "^12.23.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-icons": "^5.5.0",
@@ -2862,6 +2863,33 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/framer-motion": {
+ "version": "12.23.3",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.3.tgz",
+ "integrity": "sha512-llmLkf44zuIZOPSrE4bl4J0UTg6bav+rlKEfMRKgvDMXqBrUtMg6cspoQeRVK3nqRLxTmAJhfGXk39UDdZD7Kw==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.23.2",
+ "motion-utils": "^12.23.2",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3258,6 +3286,21 @@
"node": "*"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.23.2",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.2.tgz",
+ "integrity": "sha512-73j6xDHX/NvVh5L5oS1ouAVnshsvmApOq4F3VZo5MkYSD/YVsVLal4Qp9wvVgJM9uU2bLZyc0Sn8B9c/MMKk4g==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.23.2"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.23.2",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.2.tgz",
+ "integrity": "sha512-cIEXlBlXAOUyiAtR0S+QPQUM9L3Diz23Bo+zM420NvSd/oPQJwg6U+rT+WRTpp0rizMsBGQOsAwhWIfglUcZfA==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -3926,6 +3969,12 @@
"typescript": ">=4.8.4"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index 8df1524..0ea0e34 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.2.0",
"@mui/material": "^7.2.0",
+ "framer-motion": "^12.23.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-icons": "^5.5.0",
diff --git a/src/pages/admin/AdminMainPage.tsx b/src/pages/admin/AdminMainPage.tsx
index 5a7f163..852aec1 100644
--- a/src/pages/admin/AdminMainPage.tsx
+++ b/src/pages/admin/AdminMainPage.tsx
@@ -1,45 +1,43 @@
-import { Box, Typography, Container } from '@mui/material';
-import Vehicle from './Vehicle';
-import Personal from './Personal';
-import { Navigate } from 'react-router-dom';
-import Divider from '../../components/Divider';
+import { Box, Typography, Container } from "@mui/material";
+import Vehicle from "./Vehicle";
+import Personal from "./Personal";
+import { Navigate } from "react-router-dom";
+import Divider from "../../components/Divider";
const AdminMainPage = () => {
- const isAuth = localStorage.getItem('token') !== null;
-
+ const isAuth = localStorage.getItem("token") !== null;
+
// Перенаправление на страницу логина, если пользователь не авторизован
if (!isAuth) {
return ;
}
return (
-
-
+
+
-
-
+ >
-
-
-
+
+
+
-
-
+ >
diff --git a/src/pages/admin/Vehicle.tsx b/src/pages/admin/Vehicle.tsx
index f7c7ab4..ea6c576 100644
--- a/src/pages/admin/Vehicle.tsx
+++ b/src/pages/admin/Vehicle.tsx
@@ -1,20 +1,20 @@
-import React, { useState, useEffect } from 'react';
-import {
- Box,
- Typography,
- Button,
- TextField,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableRow,
- Paper,
- Dialog,
- DialogActions,
- DialogContent,
- DialogTitle,
+import React, { useState, useEffect } from "react";
+import {
+ Box,
+ Typography,
+ Button,
+ TextField,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ Paper,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogTitle,
IconButton,
Grid,
CircularProgress,
@@ -33,31 +33,30 @@ import {
MenuItem,
Select,
InputLabel,
- FormControl
-} from '@mui/material';
-import EditIcon from '@mui/icons-material/Edit';
-import DeleteIcon from '@mui/icons-material/Delete';
-import AddIcon from '@mui/icons-material/Add';
-import SearchIcon from '@mui/icons-material/Search';
-import ViewListIcon from '@mui/icons-material/ViewList';
-import ViewModuleIcon from '@mui/icons-material/ViewModule';
-import DirectionsCarIcon from '@mui/icons-material/DirectionsCar';
-import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
-import SpeedIcon from '@mui/icons-material/Speed';
-import AttachMoneyIcon from '@mui/icons-material/AttachMoney';
-import { useAuth } from '../../context/AuthContext';
-import {
- fetchCars,
- createCar,
- updateCar,
- deleteCar,
+ FormControl,
+} from "@mui/material";
+import EditIcon from "@mui/icons-material/Edit";
+import DeleteIcon from "@mui/icons-material/Delete";
+import AddIcon from "@mui/icons-material/Add";
+import SearchIcon from "@mui/icons-material/Search";
+import ViewListIcon from "@mui/icons-material/ViewList";
+import ViewModuleIcon from "@mui/icons-material/ViewModule";
+import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
+import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
+import SpeedIcon from "@mui/icons-material/Speed";
+import AttachMoneyIcon from "@mui/icons-material/AttachMoney";
+import { useAuth } from "../../context/AuthContext";
+import {
+ fetchCars,
+ createCar,
+ updateCar,
+ deleteCar,
getImageUrl,
-} from '../../utils/api';
-import type { Car } from '../../utils/api';
+} from "../../utils/api";
+import type { Car } from "../../utils/api";
// Определяем типы здесь, так как они не экспортируются из api.ts
-
interface CarsResponse {
cars: Car[];
total: number;
@@ -67,38 +66,57 @@ const Vehicle = () => {
const { token } = useAuth();
const [cars, setCars] = useState([]);
const [loading, setLoading] = useState(true);
- const [error, setError] = useState('');
+ const [error, setError] = useState("");
const [totalCars, setTotalCars] = useState(0);
- const [viewMode, setViewMode] = useState<'list' | 'grid'>('grid');
- const [searchQuery, setSearchQuery] = useState('');
-
+ const [viewMode, setViewMode] = useState<"list" | "grid">("grid");
+ const [searchQuery, setSearchQuery] = useState("");
+
// Состояния для модальных окон
const [openCreateDialog, setOpenCreateDialog] = useState(false);
const [openEditDialog, setOpenEditDialog] = useState(false);
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
-
+
// Состояние для выбранного автомобиля
const [selectedCar, setSelectedCar] = useState(null);
-
+
// Состояния для формы
const [formData, setFormData] = useState({
- name: '',
- year: '',
- mileage: '',
- price: '',
- base_price: '',
- country_of_origin: 'Россия',
- drive_type: 'AWD',
- engine_type: 'бензиновый',
- engine_capacity: '',
- engine_power: '',
- electric_motor_power: '',
- hybrid_type: 'не гибрид',
- power_ratio: 'не применимо',
+ name: "",
+ year: "",
+ mileage: "",
+ price: "",
+ base_price: "",
+ country_of_origin: "Россия",
+ drive_type: "AWD",
+ engine_type: "бензиновый",
+ engine_capacity: "",
+ engine_power: "",
+ electric_motor_power: "",
+ hybrid_type: "не гибрид",
+ power_ratio: "не применимо",
});
const [imageFile, setImageFile] = useState(null);
- const [imagePreview, setImagePreview] = useState('');
-
+ const [imagePreview, setImagePreview] = useState("");
+
+ const translateWheelDrive = (wheelDrive: string) => {
+ switch (wheelDrive) {
+ case "4WD":
+ return "Четырехколесный";
+ case "AWD":
+ return "Полный";
+ case "RWD":
+ return "Задний";
+ case "FWD":
+ return "Передний";
+ case "передний":
+ return "Передний";
+ case "задний":
+ return "Задний";
+ case "полный":
+ return "Полный";
+ }
+ };
+
// Загрузка списка автомобилей
const loadCars = async () => {
setLoading(true);
@@ -106,35 +124,129 @@ const Vehicle = () => {
const data: CarsResponse = await fetchCars();
setCars(data.cars);
setTotalCars(data.total);
- setError('');
+ setError("");
} catch (err) {
- setError('Не удалось загрузить список автомобилей');
+ setError("Не удалось загрузить список автомобилей");
console.error(err);
} finally {
setLoading(false);
}
};
-
+
useEffect(() => {
loadCars();
}, []);
-
+
// Фильтрация автомобилей по поисковому запросу
- const filteredCars = cars.filter(car =>
- car.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
- car.year.toString().includes(searchQuery) ||
- car.price.toString().includes(searchQuery)
+ const filteredCars = cars.filter(
+ (car) =>
+ car.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ car.year.toString().includes(searchQuery) ||
+ car.price.toString().includes(searchQuery)
);
-
+
// Обработчики для формы
const handleInputChange = (e: React.ChangeEvent) => {
const { name, value } = e.target;
- setFormData({
+ const updatedData = {
...formData,
- [name]: value
- });
+ [name]: value,
+ };
+
+ // Если изменилась базовая цена или параметры, влияющие на расчет
+ if (
+ name === "base_price" ||
+ name === "year" ||
+ name === "engine_power" ||
+ name === "engine_capacity" ||
+ name === "engine_type" ||
+ name === "hybrid_type" ||
+ name === "electric_motor_power"
+ ) {
+ // Расчет таможенных платежей
+ const basePrice = parseFloat(updatedData.base_price) || 0;
+ let customDuty = 0;
+ let exciseTax = 0;
+ let vat = 0;
+ let utilityFee = 0;
+
+ // Получаем числовые значения
+ const year = parseInt(updatedData.year) || new Date().getFullYear();
+ const engineCapacity = parseFloat(updatedData.engine_capacity) || 0;
+ const enginePower = parseFloat(updatedData.engine_power) || 0;
+ const currentYear = new Date().getFullYear();
+ const age = currentYear - year;
+
+ // Расчет пошлины в зависимости от возраста
+ if (updatedData.engine_type === "электрический") {
+ customDuty = 0; // Пошлина 0% для электромобилей
+ } else {
+ // Определяем коэффициент для возраста
+ let ageCoef = 0.54; // По умолчанию для авто < 3 лет
+
+ if (age > 5) {
+ ageCoef = 0.48;
+ // Для авто старше 5 лет используем фиксированную ставку
+ const dutyPerCm3 = 2.5 * 100; // примерный курс евро * 2.5 евро за см3
+ const dutyFixed = engineCapacity * dutyPerCm3;
+ customDuty = Math.max(dutyFixed, basePrice * ageCoef);
+ } else if (age >= 3) {
+ ageCoef = 0.48;
+ customDuty = basePrice * ageCoef;
+ } else {
+ customDuty = basePrice * ageCoef;
+ }
+ }
+
+ // Расчет акциза в зависимости от мощности
+ if (updatedData.engine_type !== "электрический") {
+ if (enginePower <= 90) {
+ exciseTax = 0;
+ } else if (enginePower <= 150) {
+ exciseTax = enginePower * 53;
+ } else if (enginePower <= 200) {
+ exciseTax = enginePower * 511;
+ } else if (enginePower <= 300) {
+ exciseTax = enginePower * 836;
+ } else if (enginePower <= 400) {
+ exciseTax = enginePower * 1425;
+ } else {
+ exciseTax = enginePower * 1475;
+ }
+ }
+
+ // НДС 20%
+ vat = (basePrice + customDuty + exciseTax) * 0.2;
+
+ // Утилизационный сбор
+ utilityFee = updatedData.engine_type === "электрический" ? 3400 : 5000;
+
+ // Итоговая цена
+ const totalFees = customDuty + exciseTax + vat + utilityFee;
+ const calculatedPrice = Math.round(basePrice + totalFees);
+
+ // Обновляем цену в форме
+ updatedData.price = calculatedPrice.toString();
+ }
+
+ setFormData(updatedData);
};
-
+
+ // Обработчик для select полей
+ const handleSelectChange = (
+ e: React.ChangeEvent<{ name?: string; value: unknown }>
+ ) => {
+ const name = e.target.name as string;
+ const value = e.target.value as string;
+
+ // Используем тот же обработчик, что и для текстовых полей
+ const event = {
+ target: { name, value },
+ } as React.ChangeEvent;
+
+ handleInputChange(event);
+ };
+
const handleImageChange = (e: React.ChangeEvent) => {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
@@ -142,58 +254,58 @@ const Vehicle = () => {
setImagePreview(URL.createObjectURL(file));
}
};
-
+
// Открытие диалога создания
const handleOpenCreateDialog = () => {
setFormData({
- name: '',
- year: '',
- mileage: '',
- price: '',
- base_price: '',
- country_of_origin: 'Россия',
- drive_type: 'AWD',
- engine_type: 'бензиновый',
- engine_capacity: '',
- engine_power: '',
- electric_motor_power: '',
- hybrid_type: 'не гибрид',
- power_ratio: 'не применимо',
+ name: "",
+ year: "",
+ mileage: "",
+ price: "",
+ base_price: "",
+ country_of_origin: "Россия",
+ drive_type: "AWD",
+ engine_type: "бензиновый",
+ engine_capacity: "",
+ engine_power: "",
+ electric_motor_power: "",
+ hybrid_type: "не гибрид",
+ power_ratio: "не применимо",
});
setImageFile(null);
- setImagePreview('');
+ setImagePreview("");
setOpenCreateDialog(true);
};
-
+
// Открытие диалога редактирования
const handleOpenEditDialog = (car: Car) => {
setSelectedCar(car);
setFormData({
- name: car.name,
- year: car.year.toString(),
- mileage: car.mileage.toString(),
- price: car.price.toString(),
- base_price: car.base_price?.toString() || '',
- country_of_origin: car.country_of_origin || 'Россия',
- drive_type: car.drive_type || 'AWD',
- engine_type: car.engine_type || 'бензиновый',
- engine_capacity: car.engine_capacity?.toString() || '',
- engine_power: car.engine_power?.toString() || '',
- electric_motor_power: car.electric_motor_power?.toString() || '',
- hybrid_type: car.hybrid_type || 'не гибрид',
- power_ratio: car.power_ratio || 'не применимо',
- });
+ name: car.name,
+ year: car.year.toString(),
+ mileage: car.mileage.toString(),
+ price: car.price.toString(),
+ base_price: car.base_price?.toString() || "",
+ country_of_origin: car.country_of_origin || "Россия",
+ drive_type: car.drive_type || "AWD",
+ engine_type: car.engine_type || "бензиновый",
+ engine_capacity: car.engine_capacity?.toString() || "",
+ engine_power: car.engine_power?.toString() || "",
+ electric_motor_power: car.electric_motor_power?.toString() || "",
+ hybrid_type: car.hybrid_type || "не гибрид",
+ power_ratio: car.power_ratio || "не применимо",
+ });
setImagePreview(getImageUrl(car.image));
setImageFile(null);
setOpenEditDialog(true);
};
-
+
// Открытие диалога удаления
const handleOpenDeleteDialog = (car: Car) => {
setSelectedCar(car);
setOpenDeleteDialog(true);
};
-
+
// Закрытие диалогов
const handleCloseDialogs = () => {
setOpenCreateDialog(false);
@@ -201,40 +313,9 @@ const Vehicle = () => {
setOpenDeleteDialog(false);
setSelectedCar(null);
};
-
+
// Создание автомобиля
const handleCreateCar = async () => {
- try {
- const carData = {
- name: formData.name,
- year: parseInt(formData.year),
- mileage: parseInt(formData.mileage),
- price: parseInt(formData.price),
- base_price: parseInt(formData.base_price),
- country_of_origin: formData.country_of_origin,
- drive_type: formData.drive_type,
- engine_type: formData.engine_type,
- engine_capacity: formData.engine_capacity ? parseInt(formData.engine_capacity) : undefined,
- engine_power: formData.engine_power ? parseInt(formData.engine_power) : undefined,
- electric_motor_power: formData.electric_motor_power ? parseInt(formData.electric_motor_power) : undefined,
- hybrid_type: formData.hybrid_type || 'не гибрид',
- power_ratio: formData.power_ratio || 'не применимо',
- image: ''
- };
-
- await createCar(carData, imageFile || undefined);
- handleCloseDialogs();
- loadCars();
- } catch (err) {
- setError('Не удалось создать автомобиль');
- console.error(err);
- }
- };
-
- // Обновление автомобиля
- const handleUpdateCar = async () => {
- if (!selectedCar) return;
-
try {
const carData = {
name: formData.name,
@@ -245,144 +326,205 @@ const Vehicle = () => {
country_of_origin: formData.country_of_origin,
drive_type: formData.drive_type,
engine_type: formData.engine_type,
- engine_capacity: formData.engine_capacity ? parseInt(formData.engine_capacity) : undefined,
- engine_power: formData.engine_power ? parseInt(formData.engine_power) : undefined,
- electric_motor_power: formData.electric_motor_power ? parseInt(formData.electric_motor_power) : undefined,
- hybrid_type: formData.hybrid_type || 'не гибрид',
- power_ratio: formData.power_ratio || 'не применимо',
+ engine_capacity: formData.engine_capacity
+ ? parseInt(formData.engine_capacity)
+ : undefined,
+ engine_power: formData.engine_power
+ ? parseInt(formData.engine_power)
+ : undefined,
+ electric_motor_power: formData.electric_motor_power
+ ? parseInt(formData.electric_motor_power)
+ : undefined,
+ hybrid_type: formData.hybrid_type || "не гибрид",
+ power_ratio: formData.power_ratio || "не применимо",
+ image: "",
};
-
+
+ await createCar(carData, imageFile || undefined);
+ handleCloseDialogs();
+ loadCars();
+ } catch (err) {
+ setError("Не удалось создать автомобиль");
+ console.error(err);
+ }
+ };
+
+ // Обновление автомобиля
+ const handleUpdateCar = async () => {
+ if (!selectedCar) return;
+
+ try {
+ const carData = {
+ name: formData.name,
+ year: parseInt(formData.year),
+ mileage: parseInt(formData.mileage),
+ price: parseInt(formData.price),
+ base_price: parseInt(formData.base_price),
+ country_of_origin: formData.country_of_origin,
+ drive_type: formData.drive_type,
+ engine_type: formData.engine_type,
+ engine_capacity: formData.engine_capacity
+ ? parseInt(formData.engine_capacity)
+ : undefined,
+ engine_power: formData.engine_power
+ ? parseInt(formData.engine_power)
+ : undefined,
+ electric_motor_power: formData.electric_motor_power
+ ? parseInt(formData.electric_motor_power)
+ : undefined,
+ hybrid_type: formData.hybrid_type || "не гибрид",
+ power_ratio: formData.power_ratio || "не применимо",
+ };
+
await updateCar(selectedCar.id, carData, imageFile || undefined);
handleCloseDialogs();
loadCars();
} catch (err) {
- setError('Не удалось обновить автомобиль');
+ setError("Не удалось обновить автомобиль");
console.error(err);
}
};
-
+
// Удаление автомобиля
const handleDeleteCar = async () => {
if (!selectedCar) return;
-
+
try {
await deleteCar(selectedCar.id);
handleCloseDialogs();
loadCars();
} catch (err) {
- setError('Не удалось удалить автомобиль');
+ setError("Не удалось удалить автомобиль");
console.error(err);
}
};
-
+
// Валидация формы
const isFormValid = () => {
return (
- formData.name.trim() !== '' &&
- !isNaN(parseInt(formData.year)) &&
- !isNaN(parseInt(formData.mileage)) &&
+ formData.name.trim() !== "" &&
+ !isNaN(parseInt(formData.year)) &&
+ !isNaN(parseInt(formData.mileage)) &&
!isNaN(parseInt(formData.price)) &&
!isNaN(parseInt(formData.base_price)) &&
- formData.country_of_origin.trim() !== '' &&
- formData.drive_type.trim() !== '' &&
- formData.engine_type.trim() !== ''
+ formData.country_of_origin.trim() !== "" &&
+ formData.drive_type.trim() !== "" &&
+ formData.engine_type.trim() !== ""
);
};
-
+
// Форматирование цены
const formatPrice = (price: number) => {
- return new Intl.NumberFormat('ru-RU', {
- style: 'currency',
- currency: 'RUB',
- maximumFractionDigits: 0
+ return new Intl.NumberFormat("ru-RU", {
+ style: "currency",
+ currency: "RUB",
+ maximumFractionDigits: 0,
}).format(price);
};
-
+
// Рендер таблицы
const renderTable = () => (
-
-
+
- ID
- Изображение
- Название
- Год
- Пробег
- Цена
- Действия
+
+ ID
+
+
+ Изображение
+
+
+ Название
+
+
+ Год
+
+
+ Пробег
+
+
+ Цена
+
+
+ Действия
+
{filteredCars.map((car) => (
-
{car.id}
-
- {car.name}
+ {car.name}
- }
- label={car.year}
- size="small"
- sx={{ bgcolor: '#e8f5e9', color: '#2e7d32' }}
+ }
+ label={car.year}
+ size="small"
+ sx={{ bgcolor: "#e8f5e9", color: "#2e7d32" }}
/>
- }
- label={`${car.mileage} км`}
- size="small"
- sx={{ bgcolor: '#e3f2fd', color: '#1565c0' }}
+ }
+ label={`${car.mileage} км`}
+ size="small"
+ sx={{ bgcolor: "#e3f2fd", color: "#1565c0" }}
/>
- }
- label={formatPrice(car.price)}
- size="small"
- sx={{ bgcolor: '#fce4ec', color: '#c2185b' }}
+ }
+ label={formatPrice(car.price)}
+ size="small"
+ sx={{ bgcolor: "#fce4ec", color: "#c2185b" }}
/>
-
- handleOpenEditDialog(car)}
+
+ handleOpenEditDialog(car)}
color="primary"
- sx={{
+ sx={{
color: "black",
- '&:hover': {
- color: '#C27664',
- bgcolor: "transparent"
+ "&:hover": {
+ color: "#C27664",
+ bgcolor: "transparent",
},
transition: "all 0.2s ease",
}}
@@ -390,14 +532,18 @@ const Vehicle = () => {
-
- handleOpenDeleteDialog(car)}
+
+ handleOpenDeleteDialog(car)}
color="error"
- sx={{
- '&:hover': {
- color: '#C27664',
- bgcolor: 'transparent',
+ sx={{
+ "&:hover": {
+ color: "#C27664",
+ bgcolor: "transparent",
},
transition: "all 0.2s ease",
}}
@@ -412,25 +558,25 @@ const Vehicle = () => {
);
-
+
// Рендер сетки карточек
const renderGrid = () => (
{filteredCars.map((car) => (
-
{
height="160"
image={getImageUrl(car.image)}
alt={car.name}
- sx={{ objectFit: 'cover',
+ sx={{
+ objectFit: "cover",
userSelect: "none",
pointerEvents: "none",
}}
/>
-
+
{car.name}
-
-
-
+
+
+
-
+
Год выпуска: {car.year}
-
-
+
+
-
+
Пробег: {car.mileage} км
-
-
+
+
-
+
Цена: {formatPrice(car.price)}
-
+
-
-
-
- }
onClick={() => handleOpenDeleteDialog(car)}
- sx={{
- color: 'rgb(214, 74, 74)',
- '&:hover': { color: 'rgba(150, 0, 0, 1)', bgcolor: 'transparent' },
+ sx={{
+ color: "rgb(214, 74, 74)",
+ "&:hover": {
+ color: "rgba(150, 0, 0, 1)",
+ bgcolor: "transparent",
+ },
transition: "all 0.2s ease",
fontFamily: "Unbounded",
fontWeight: "bold",
@@ -511,36 +690,45 @@ const Vehicle = () => {
))}
);
-
+
return (
-
+
{/* Заголовок и кнопки управления */}
-
-
-
-
-
+
+
+
+
Управление автомобилями
-
-
-
+ }
sx={{
@@ -558,20 +746,20 @@ const Vehicle = () => {
-
+
{/* Панель поиска и переключения вида */}
-
{
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
size="small"
- sx={{
+ sx={{
minWidth: 300,
- '& .MuiOutlinedInput-root': {
- borderRadius: "1vw"
- }
+ "& .MuiOutlinedInput-root": {
+ borderRadius: "1vw",
+ },
}}
InputProps={{
startAdornment: (
@@ -594,98 +782,126 @@ const Vehicle = () => {
),
}}
/>
-
-
-
+
+
+
Всего: {totalCars} автомобилей
-
- setViewMode(newValue)}
sx={{
- '& .MuiTab-root': { minWidth: 'auto' },
- '& .Mui-selected': { color: '#C27664 !important' },
- '& .MuiTabs-indicator': { backgroundColor: '#C27664' }
+ "& .MuiTab-root": { minWidth: "auto" },
+ "& .Mui-selected": { color: "#C27664 !important" },
+ "& .MuiTabs-indicator": { backgroundColor: "#C27664" },
}}
>
- }
- value="list"
- sx={{ minWidth: 'auto' }}
+ }
+ value="list"
+ sx={{ minWidth: "auto" }}
/>
- }
+ }
value="grid"
- sx={{ minWidth: 'auto' }}
+ sx={{ minWidth: "auto" }}
/>
-
+
{/* Сообщения об ошибках */}
{error && (
{error}
)}
-
+
{/* Индикатор загрузки */}
{loading ? (
-
-
-
- ) : filteredCars.length === 0 ? (
-
-
+
+
+ ) : filteredCars.length === 0 ? (
+
+
Автомобили не найдены
-
+
Попробуйте изменить параметры поиска или добавьте новый автомобиль
+ ) : // Отображение списка автомобилей в зависимости от выбранного режима
+ viewMode === "list" ? (
+ renderTable()
) : (
- // Отображение списка автомобилей в зависимости от выбранного режима
- viewMode === 'list' ? renderTable() : renderGrid()
+ renderGrid()
)}
-
+
{/* Диалог создания автомобиля */}
-
-
+
{/* Диалог редактирования автомобиля */}
-
-
+
{/* Диалог удаления автомобиля */}
-