Files
autobro-front/src/pages/admin/Vehicle.tsx
aurinex f74949836a fix
2025-07-14 17:30:13 +05:00

2413 lines
83 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
Alert,
Card,
CardContent,
CardMedia,
CardActions,
Chip,
Divider,
InputAdornment,
Tooltip,
Fade,
Tabs,
Tab,
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,
getImageUrl,
} from "../../utils/api";
import type { Car } from "../../utils/api";
// Определяем типы здесь, так как они не экспортируются из api.ts
interface CarsResponse {
cars: Car[];
total: number;
}
const Vehicle = () => {
const { token } = useAuth();
const [cars, setCars] = useState<Car[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [totalCars, setTotalCars] = useState(0);
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<Car | null>(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: "не применимо",
});
const [imageFile, setImageFile] = useState<File | null>(null);
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);
try {
const data: CarsResponse = await fetchCars();
setCars(data.cars);
setTotalCars(data.total);
setError("");
} catch (err) {
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 handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
const updatedData = {
...formData,
[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<HTMLInputElement>;
handleInputChange(event);
};
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
setImageFile(file);
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: "не применимо",
});
setImageFile(null);
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 || "не применимо",
});
setImagePreview(getImageUrl(car.image));
setImageFile(null);
setOpenEditDialog(true);
};
// Открытие диалога удаления
const handleOpenDeleteDialog = (car: Car) => {
setSelectedCar(car);
setOpenDeleteDialog(true);
};
// Закрытие диалогов
const handleCloseDialogs = () => {
setOpenCreateDialog(false);
setOpenEditDialog(false);
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,
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("Не удалось обновить автомобиль");
console.error(err);
}
};
// Удаление автомобиля
const handleDeleteCar = async () => {
if (!selectedCar) return;
try {
await deleteCar(selectedCar.id);
handleCloseDialogs();
loadCars();
} catch (err) {
setError("Не удалось удалить автомобиль");
console.error(err);
}
};
// Валидация формы
const isFormValid = () => {
return (
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() !== ""
);
};
// Форматирование цены
const formatPrice = (price: number) => {
return new Intl.NumberFormat("ru-RU", {
style: "currency",
currency: "RUB",
maximumFractionDigits: 0,
}).format(price);
};
// Рендер таблицы
const renderTable = () => (
<TableContainer
component={Paper}
elevation={3}
sx={{
borderRadius: "1vw",
overflow: "hidden",
}}
>
<Table>
<TableHead sx={{ bgcolor: "#2D2D2D" }}>
<TableRow>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
ID
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Изображение
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Название
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Год
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Пробег
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Цена
</TableCell>
<TableCell sx={{ color: "white", fontWeight: "bold" }}>
Действия
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredCars.map((car) => (
<TableRow
key={car.id}
sx={{
"&:hover": {
backgroundColor: "#f5f5f5",
},
transition: "background-color 0.3s",
}}
>
<TableCell>{car.id}</TableCell>
<TableCell>
<Box
component="img"
src={getImageUrl(car.image)}
alt={car.name}
sx={{
width: "10vw",
height: "5vw",
objectFit: "cover",
borderRadius: "0.7vw",
boxShadow: "0 0.2vw 0.4vw rgba(0,0,0,0.1)",
userSelect: "none",
pointerEvents: "none",
}}
/>
</TableCell>
<TableCell sx={{ fontWeight: "medium" }}>{car.name}</TableCell>
<TableCell>
<Chip
icon={<CalendarTodayIcon />}
label={car.year}
size="small"
sx={{ bgcolor: "#e8f5e9", color: "#2e7d32" }}
/>
</TableCell>
<TableCell>
<Chip
icon={<SpeedIcon />}
label={`${car.mileage} км`}
size="small"
sx={{ bgcolor: "#e3f2fd", color: "#1565c0" }}
/>
</TableCell>
<TableCell>
<Chip
icon={<AttachMoneyIcon />}
label={formatPrice(car.price)}
size="small"
sx={{ bgcolor: "#fce4ec", color: "#c2185b" }}
/>
</TableCell>
<TableCell>
<Tooltip
arrow
TransitionComponent={Fade}
TransitionProps={{ timeout: 600 }}
>
<IconButton
onClick={() => handleOpenEditDialog(car)}
color="primary"
sx={{
color: "black",
"&:hover": {
color: "#C27664",
bgcolor: "transparent",
},
transition: "all 0.2s ease",
}}
>
<EditIcon />
</IconButton>
</Tooltip>
<Tooltip
arrow
TransitionComponent={Fade}
TransitionProps={{ timeout: 600 }}
>
<IconButton
onClick={() => handleOpenDeleteDialog(car)}
color="error"
sx={{
"&:hover": {
color: "#C27664",
bgcolor: "transparent",
},
transition: "all 0.2s ease",
}}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
// Рендер сетки карточек
const renderGrid = () => (
<Grid container spacing={3}>
{filteredCars.map((car) => (
<Grid item xs={12} sm={6} md={4} key={car.id}>
<Card
elevation={3}
sx={{
height: "100%",
display: "flex",
flexDirection: "column",
borderRadius: "1vw",
transition: "transform 0.3s, box-shadow 0.3s",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.15)",
"&:hover": {
transform: "translateY(-0.2vw)",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.1)",
},
}}
>
<CardMedia
component="img"
height="160"
image={getImageUrl(car.image)}
alt={car.name}
sx={{
objectFit: "cover",
userSelect: "none",
pointerEvents: "none",
}}
/>
<CardContent sx={{ pt: "0.5vw" }}>
<Typography
gutterBottom
variant="h6"
component="div"
sx={{
fontWeight: "bold",
mb: "0.5vw",
fontFamily: "Unbounded",
}}
>
{car.name}
</Typography>
<Box
sx={{ display: "flex", flexDirection: "column", gap: "0.5vw" }}
>
<Box
sx={{ display: "flex", alignItems: "center", gap: "0.5vw" }}
>
<CalendarTodayIcon fontSize="small" color="success" />
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
Год выпуска: <b>{car.year}</b>
</Typography>
</Box>
<Box
sx={{ display: "flex", alignItems: "center", gap: "0.5vw" }}
>
<SpeedIcon fontSize="small" color="primary" />
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
Пробег: <b>{car.mileage} км</b>
</Typography>
</Box>
<Box
sx={{ display: "flex", alignItems: "center", gap: "0.5vw" }}
>
<AttachMoneyIcon fontSize="small" color="secondary" />
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
Цена: <b>{formatPrice(car.price)}</b>
</Typography>
</Box>
</Box>
</CardContent>
<Divider />
<CardActions sx={{ justifyContent: "space-between", p: "1vw" }}>
<Button
size="small"
startIcon={<EditIcon />}
onClick={() => handleOpenEditDialog(car)}
sx={{
color: "black",
"&:hover": { color: "#C27664", bgcolor: "transparent" },
transition: "all 0.2s ease",
fontFamily: "Unbounded",
fontWeight: "bold",
fontSize: "0.8vw",
}}
>
Изменить
</Button>
<Button
size="small"
startIcon={<DeleteIcon />}
onClick={() => handleOpenDeleteDialog(car)}
sx={{
color: "rgb(214, 74, 74)",
"&:hover": {
color: "rgba(150, 0, 0, 1)",
bgcolor: "transparent",
},
transition: "all 0.2s ease",
fontFamily: "Unbounded",
fontWeight: "bold",
fontSize: "0.8vw",
}}
>
Удалить
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
);
return (
<Box>
{/* Заголовок и кнопки управления */}
<Paper
elevation={3}
sx={{
p: "2vw",
mb: "2vw",
borderRadius: "1vw",
background: "linear-gradient(to right, #2D2D2D, #3D3D3D)",
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexWrap: "wrap",
gap: "1vw",
}}
>
<Box sx={{ display: "flex", alignItems: "center", gap: "1vw" }}>
<DirectionsCarIcon sx={{ fontSize: "3.5vw", color: "#C27664" }} />
<Typography
variant="h5"
sx={{
fontFamily: "Unbounded",
fontWeight: "bold",
color: "white",
}}
>
Управление автомобилями
</Typography>
</Box>
<Box sx={{ display: "flex", gap: "1vw" }}>
<Button
variant="contained"
onClick={handleOpenCreateDialog}
startIcon={<AddIcon />}
sx={{
bgcolor: "#C27664",
color: "white",
textTransform: "none",
fontFamily: "Unbounded",
borderRadius: "1vw",
px: "2vw",
"&:hover": { bgcolor: "#945B4D" },
}}
>
Добавить автомобиль
</Button>
</Box>
</Box>
</Paper>
{/* Панель поиска и переключения вида */}
<Paper
elevation={2}
sx={{
p: "1.5vw",
mb: "2vw",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderRadius: "1vw",
flexWrap: "wrap",
gap: "1vw",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.15)",
}}
>
<TextField
placeholder="Поиск автомобилей..."
variant="outlined"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
size="small"
sx={{
minWidth: 300,
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="body2"
color="text.secondary"
sx={{ mr: "1vw", fontFamily: "Unbounded" }}
>
Всего: {totalCars} автомобилей
</Typography>
<Tabs
value={viewMode}
onChange={(_, newValue) => setViewMode(newValue)}
sx={{
"& .MuiTab-root": { minWidth: "auto" },
"& .Mui-selected": { color: "#C27664 !important" },
"& .MuiTabs-indicator": { backgroundColor: "#C27664" },
}}
>
<Tab
icon={<ViewListIcon />}
value="list"
sx={{ minWidth: "auto" }}
/>
<Tab
icon={<ViewModuleIcon />}
value="grid"
sx={{ minWidth: "auto" }}
/>
</Tabs>
</Box>
</Paper>
{/* Сообщения об ошибках */}
{error && (
<Alert severity="error" sx={{ mb: "1vw", borderRadius: "1vw" }}>
{error}
</Alert>
)}
{/* Индикатор загрузки */}
{loading ? (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
minHeight: "10vw",
}}
>
<CircularProgress sx={{ color: "#C27664" }} />
</Box>
) : filteredCars.length === 0 ? (
<Paper
elevation={2}
sx={{
p: "4vw",
textAlign: "center",
borderRadius: "1vw",
bgcolor: "#f9f9f9",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.15)",
}}
>
<Typography
variant="h6"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
Автомобили не найдены
</Typography>
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
Попробуйте изменить параметры поиска или добавьте новый автомобиль
</Typography>
</Paper>
) : // Отображение списка автомобилей в зависимости от выбранного режима
viewMode === "list" ? (
renderTable()
) : (
renderGrid()
)}
{/* Диалог создания автомобиля */}
<Dialog
open={openCreateDialog}
onClose={handleCloseDialogs}
maxWidth="md"
fullWidth
PaperProps={{
sx: { borderRadius: "1vw" },
}}
>
<DialogTitle
sx={{
fontFamily: "Unbounded",
bgcolor: "#2D2D2D",
color: "white",
display: "flex",
alignItems: "center",
gap: "1vw",
}}
>
<AddIcon /> Добавить автомобиль
</DialogTitle>
<DialogContent sx={{ mt: "1vw" }}>
<Grid container spacing={3}>
<Grid
component="div"
item
xs={12}
md={6}
style={{
display: "grid",
gridTemplateColumns: "repeat(2, 1fr)",
gap: "1vw",
}}
>
{/* <TextField
name="name"
label="Название автомобиля"
value={formData.name}
sx={{ label: { fontFamily: "Unbounded" }, input: { fontFamily: "Unbounded" } }}
onChange={handleInputChange}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<DirectionsCarIcon color="action" />
</InputAdornment>
),
}}
/> */}
<TextField
fullWidth
placeholder="Название автомобиля"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<DirectionsCarIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
{/* <TextField
name="year"
label="Год выпуска"
type="number"
value={formData.year}
sx={{ label: { fontFamily: "Unbounded" }, input: { fontFamily: "Unbounded" } }}
onChange={handleInputChange}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CalendarTodayIcon color="action" />
</InputAdornment>
),
}}
/> */}
<TextField
fullWidth
placeholder="Год выпуска"
value={formData.year}
onChange={(e) =>
setFormData({ ...formData, year: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CalendarTodayIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
{/* <TextField
name="mileage"
label="Пробег (км)"
type="number"
value={formData.mileage}
sx={{ label: { fontFamily: "Unbounded" }, input: { fontFamily: "Unbounded" } }}
onChange={handleInputChange}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SpeedIcon color="action" />
</InputAdornment>
),
}}
/> */}
{/* <TextField
name="price"
label="Цена (₽)"
type="number"
value={formData.price}
sx={{ label: { fontFamily: "Unbounded" }, input: { fontFamily: "Unbounded" } }}
onChange={handleInputChange}
fullWidth
margin="normal"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AttachMoneyIcon color="action" />
</InputAdornment>
),
}}
/> */}
<TextField
fullWidth
name="base_price"
placeholder="Базовая цена в рублях"
value={formData.base_price}
onChange={handleInputChange}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
</Typography>
</InputAdornment>
),
}}
/>
<TextField
fullWidth
placeholder="Итоговая цена в рублях"
value={formData.price}
disabled
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "#f5f5f5",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
</Typography>
</InputAdornment>
),
}}
/>
<TextField
fullWidth
placeholder="Пробег (км)"
value={formData.mileage}
onChange={(e) =>
setFormData({ ...formData, mileage: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SpeedIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Страна происхождения
</InputLabel>
<Select
value={formData.country_of_origin}
onChange={handleSelectChange}
displayEmpty
label="Страна происхождения"
name="country_of_origin"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="Россия">Россия</MenuItem>
<MenuItem value="Япония">Япония</MenuItem>
<MenuItem value="Китай">Китай</MenuItem>
<MenuItem value="США">США</MenuItem>
<MenuItem value="Германия">Германия</MenuItem>
<MenuItem value="Корея">Корея</MenuItem>
<MenuItem value="Италия">Италия</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип привода
</InputLabel>
<Select
value={formData.drive_type}
onChange={handleSelectChange}
displayEmpty
label="Тип привода"
name="drive_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="FWD">FWD</MenuItem>
<MenuItem value="RWD">RWD</MenuItem>
<MenuItem value="4WD">4WD</MenuItem>
<MenuItem value="AWD">AWD</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип двигателя
</InputLabel>
<Select
value={formData.engine_type}
onChange={(e) => {
const engineType = e.target.value as string;
const updatedFormData = {
...formData,
engine_type: engineType,
};
// Сбрасываем значения полей, которые не нужны для выбранного типа
if (
engineType === "бензиновый" ||
engineType === "дизельный"
) {
updatedFormData.electric_motor_power = "";
updatedFormData.hybrid_type = "не гибрид";
updatedFormData.power_ratio = "не применимо";
} else if (engineType === "электрический") {
updatedFormData.engine_capacity = "";
updatedFormData.engine_power = "";
updatedFormData.hybrid_type = "не гибрид";
}
setFormData(updatedFormData);
}}
displayEmpty
label="Тип двигателя"
name="engine_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
"& .hover": {
border: "0.1vw solid #C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="бензиновый">Бензиновый</MenuItem>
<MenuItem value="дизельный">Дизельный</MenuItem>
<MenuItem value="электрический">Электрический</MenuItem>
<MenuItem value="гибридный">Гибридный</MenuItem>
</Select>
</FormControl>
{/* Поле объёма двигателя - показываем для всех, кроме электрических */}
{formData.engine_type !== "электрический" && (
<TextField
fullWidth
placeholder="Объём двигателя"
value={formData.engine_capacity}
onChange={(e) =>
setFormData({
...formData,
engine_capacity: e.target.value,
})
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
см³
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Поле мощности двигателя - показываем для всех, кроме электрических */}
{formData.engine_type !== "электрический" && (
<TextField
fullWidth
placeholder="Мощность двигателя (л.с.)"
value={formData.engine_power}
onChange={(e) =>
setFormData({ ...formData, engine_power: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
л.с.
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Поле мощности электромотора - показываем только для электрических и гибридных */}
{(formData.engine_type === "электрический" ||
formData.engine_type === "гибридный") && (
<TextField
fullWidth
placeholder="Мощность электромотора (кВт)"
value={formData.electric_motor_power}
onChange={(e) =>
setFormData({
...formData,
electric_motor_power: e.target.value,
})
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
кВт
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Тип гибрида - показываем только для гибридов */}
{formData.engine_type === "гибридный" && (
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип гибрида
</InputLabel>
<Select
value={formData.hybrid_type}
onChange={(e) =>
setFormData({
...formData,
hybrid_type: e.target.value as string,
})
}
displayEmpty
label="Тип гибрида"
name="hybrid_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="мягкий">Мягкий гибрид (MHEV)</MenuItem>
<MenuItem value="полный">Полный гибрид (HEV)</MenuItem>
<MenuItem value="подключаемый">
Подключаемый гибрид (PHEV)
</MenuItem>
</Select>
</FormControl>
)}
{/* Соотношение мощности - показываем только для гибридов */}
{formData.engine_type === "гибридный" && (
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Соотношение мощности
</InputLabel>
<Select
value={formData.power_ratio}
onChange={(e) =>
setFormData({
...formData,
power_ratio: e.target.value as string,
})
}
displayEmpty
label="Соотношение мощности"
name="power_ratio"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="не применимо">Не применимо</MenuItem>
<MenuItem value="среднее">Среднее</MenuItem>
<MenuItem value="высокое">Высокое</MenuItem>
</Select>
</FormControl>
)}
</Grid>
<Button
variant="outlined"
component="label"
sx={{
borderRadius: "1vw",
p: "1vw",
borderColor: "#C27664",
fontFamily: "Unbounded",
color: "#C27664",
"&:hover": {
borderColor: "#945B4D",
bgcolor: "rgba(194, 118, 100, 0.1)",
},
}}
fullWidth
>
Загрузить изображение
<input
type="file"
hidden
accept="image/*"
onChange={handleImageChange}
/>
</Button>
<Grid item xs={12} md={6}>
<Paper
elevation={2}
sx={{
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "1vw",
overflow: "hidden",
bgcolor: "#2D2D2D",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.15)",
}}
>
{imagePreview ? (
<Box
component="img"
src={imagePreview}
alt="Предпросмотр"
sx={{
width: "100%",
height: "100%",
objectFit: "contain",
p: "1vw",
userSelect: "none",
pointerEvents: "none",
}}
/>
) : (
<Typography
color="text.secondary"
sx={{
p: "3vw",
textAlign: "center",
color: "white",
fontFamily: "Unbounded",
}}
>
Предпросмотр изображения
</Typography>
)}
</Paper>
</Grid>
</Grid>
</DialogContent>
<DialogActions sx={{ p: "1vw", bgcolor: "#f5f5f5" }}>
<Button
onClick={handleCloseDialogs}
sx={{
color: "black",
fontFamily: "Unbounded",
borderRadius: "1vw",
px: "1vw",
"&:hover": { bgcolor: "transparent", color: "#C27664" },
transition: "all 0.2s ease",
}}
>
Отмена
</Button>
<Button
onClick={handleCreateCar}
disabled={!isFormValid()}
variant="contained"
sx={{
bgcolor: "#C27664",
color: "white",
fontFamily: "Unbounded",
borderRadius: "1vw",
px: "2vw",
"&:hover": { bgcolor: "#945B4D" },
"&.Mui-disabled": {
bgcolor: "rgba(194, 118, 100, 0.5)",
},
}}
>
Создать
</Button>
</DialogActions>
</Dialog>
{/* Диалог редактирования автомобиля */}
<Dialog
open={openEditDialog}
onClose={handleCloseDialogs}
maxWidth="md"
fullWidth
PaperProps={{
sx: { borderRadius: "1vw" },
}}
>
<DialogTitle
sx={{
fontFamily: "Unbounded",
bgcolor: "#2D2D2D",
color: "white",
display: "flex",
alignItems: "center",
gap: "1vw",
}}
>
<EditIcon /> Редактировать автомобиль
</DialogTitle>
<DialogContent sx={{ mt: "1vw" }}>
<Grid container spacing={3}>
<Grid
item
xs={12}
md={6}
style={{
display: "grid",
gridTemplateColumns: "repeat(2, 1fr)",
gap: "1vw",
}}
>
<TextField
fullWidth
placeholder="Название автомобиля"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<DirectionsCarIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
<TextField
fullWidth
placeholder="Год выпуска"
value={formData.year}
onChange={(e) =>
setFormData({ ...formData, year: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<CalendarTodayIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
<TextField
fullWidth
name="base_price"
placeholder="Базовая цена в рублях"
value={formData.base_price}
onChange={handleInputChange}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
</Typography>
</InputAdornment>
),
}}
/>
<TextField
fullWidth
placeholder="Итоговая цена в рублях"
value={formData.price}
disabled
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "#f5f5f5",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
</Typography>
</InputAdornment>
),
}}
/>
<TextField
fullWidth
placeholder="Пробег (км)"
value={formData.mileage}
onChange={(e) =>
setFormData({ ...formData, mileage: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SpeedIcon sx={{ color: "#C27664" }} />
</InputAdornment>
),
}}
/>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Страна происхождения
</InputLabel>
<Select
value={formData.country_of_origin}
onChange={handleSelectChange}
displayEmpty
label="Страна происхождения"
name="country_of_origin"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="Россия">Россия</MenuItem>
<MenuItem value="Япония">Япония</MenuItem>
<MenuItem value="Китай">Китай</MenuItem>
<MenuItem value="США">США</MenuItem>
<MenuItem value="Германия">Германия</MenuItem>
<MenuItem value="Корея">Корея</MenuItem>
<MenuItem value="Италия">Италия</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип привода
</InputLabel>
<Select
value={formData.drive_type}
onChange={handleSelectChange}
displayEmpty
label="Тип привода"
name="drive_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="FWD">FWD</MenuItem>
<MenuItem value="RWD">RWD</MenuItem>
<MenuItem value="4WD">4WD</MenuItem>
<MenuItem value="AWD">AWD</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип двигателя
</InputLabel>
<Select
value={formData.engine_type}
onChange={(e) => {
const engineType = e.target.value as string;
const updatedFormData = {
...formData,
engine_type: engineType,
};
// Сбрасываем значения полей, которые не нужны для выбранного типа
if (
engineType === "бензиновый" ||
engineType === "дизельный"
) {
updatedFormData.electric_motor_power = "";
updatedFormData.hybrid_type = "не гибрид";
updatedFormData.power_ratio = "не применимо";
} else if (engineType === "электрический") {
updatedFormData.engine_capacity = "";
updatedFormData.engine_power = "";
updatedFormData.hybrid_type = "не гибрид";
}
setFormData(updatedFormData);
}}
displayEmpty
label="Тип двигателя"
name="engine_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
"& .hover": {
border: "0.1vw solid #C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="бензиновый">Бензиновый</MenuItem>
<MenuItem value="дизельный">Дизельный</MenuItem>
<MenuItem value="электрический">Электрический</MenuItem>
<MenuItem value="гибридный">Гибридный</MenuItem>
</Select>
</FormControl>
{/* Поле объёма двигателя - показываем для всех, кроме электрических */}
{formData.engine_type !== "электрический" && (
<TextField
fullWidth
placeholder="Объём двигателя"
value={formData.engine_capacity}
onChange={(e) =>
setFormData({
...formData,
engine_capacity: e.target.value,
})
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
л
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Поле мощности двигателя - показываем для всех, кроме электрических */}
{formData.engine_type !== "электрический" && (
<TextField
fullWidth
placeholder="Мощность двигателя (л.с.)"
value={formData.engine_power}
onChange={(e) =>
setFormData({ ...formData, engine_power: e.target.value })
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
л.с.
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Поле мощности электромотора - показываем только для электрических и гибридных */}
{(formData.engine_type === "электрический" ||
formData.engine_type === "гибридный") && (
<TextField
fullWidth
placeholder="Мощность электромотора (кВт)"
value={formData.electric_motor_power}
onChange={(e) =>
setFormData({
...formData,
electric_motor_power: e.target.value,
})
}
variant="outlined"
sx={{
"& .MuiOutlinedInput-root": {
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
border: "0.1vw solid #C27664",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& fieldset": {
border: "none",
},
},
}}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Typography
sx={{
fontFamily: "Unbounded",
fontSize: "1.5vw",
color: "#C27664",
}}
>
кВт
</Typography>
</InputAdornment>
),
}}
/>
)}
{/* Тип гибрида - показываем только для гибридов */}
{formData.engine_type === "гибридный" && (
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Тип гибрида
</InputLabel>
<Select
value={formData.hybrid_type}
onChange={(e) =>
setFormData({
...formData,
hybrid_type: e.target.value as string,
})
}
displayEmpty
label="Тип гибрида"
name="hybrid_type"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="мягкий">Мягкий гибрид (MHEV)</MenuItem>
<MenuItem value="полный">Полный гибрид (HEV)</MenuItem>
<MenuItem value="подключаемый">
Подключаемый гибрид (PHEV)
</MenuItem>
</Select>
</FormControl>
)}
{/* Соотношение мощности - показываем только для гибридов */}
{formData.engine_type === "гибридный" && (
<FormControl fullWidth>
<InputLabel
sx={{
fontFamily: "Unbounded",
color: "#C27664",
"&.Mui-focused": { color: "#C27664" },
}}
>
Соотношение мощности
</InputLabel>
<Select
value={formData.power_ratio}
onChange={(e) =>
setFormData({
...formData,
power_ratio: e.target.value as string,
})
}
displayEmpty
label="Соотношение мощности"
name="power_ratio"
sx={{
borderRadius: "1vw",
bgcolor: "white",
height: "4vw",
width: "100%",
fontFamily: "Unbounded",
fontSize: "1.2vw",
color: "#C27664",
"& .MuiOutlinedInput-notchedOutline": {
border: "0.1vw solid #C27664",
},
"& .MuiSvgIcon-root": {
fontSize: "2vw",
color: "#C27664",
},
transition: "all 0.2s ease",
}}
>
<MenuItem value="не применимо">Не применимо</MenuItem>
<MenuItem value="среднее">Среднее</MenuItem>
<MenuItem value="высокое">Высокое</MenuItem>
</Select>
</FormControl>
)}
<Button
variant="outlined"
component="label"
sx={{
fontFamily: "Unbounded",
borderRadius: "1vw",
p: "1vw",
borderColor: "#C27664",
color: "#C27664",
"&:hover": {
borderColor: "#945B4D",
bgcolor: "#C27664",
color: "white",
},
transition: "all 0.2s ease",
}}
fullWidth
>
Изменить изображение
<input
type="file"
hidden
accept="image/*"
onChange={handleImageChange}
/>
</Button>
</Grid>
<Grid item xs={12} md={6}>
<Paper
elevation={2}
sx={{
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "1vw",
overflow: "hidden",
bgcolor: "#2D2D2D",
boxShadow: "0 0.5vw 1vw rgba(0,0,0,0.15)",
}}
>
{imagePreview ? (
<Box
component="img"
src={imagePreview}
alt="Предпросмотр"
sx={{
width: "100%",
height: "100%",
objectFit: "contain",
p: "1vw",
userSelect: "none",
pointerEvents: "none",
}}
/>
) : (
<Typography
color="text.secondary"
sx={{
p: "3vw",
textAlign: "center",
color: "white",
fontFamily: "Unbounded",
}}
>
Предпросмотр изображения
</Typography>
)}
</Paper>
</Grid>
</Grid>
</DialogContent>
<DialogActions sx={{ p: "1vw", bgcolor: "#f5f5f5" }}>
<Button
onClick={handleCloseDialogs}
sx={{
color: "black",
fontFamily: "Unbounded",
borderRadius: "1vw",
px: "1vw",
"&:hover": { bgcolor: "transparent", color: "#C27664" },
transition: "all 0.2s ease",
}}
>
Отмена
</Button>
<Button
onClick={handleUpdateCar}
disabled={!isFormValid()}
variant="contained"
sx={{
bgcolor: "#C27664",
color: "white",
fontFamily: "Unbounded",
borderRadius: "1vw",
px: "2vw",
"&:hover": { bgcolor: "#945B4D" },
"&.Mui-disabled": {
bgcolor: "rgba(194, 118, 100, 0.5)",
},
}}
>
Сохранить
</Button>
</DialogActions>
</Dialog>
{/* Диалог удаления автомобиля */}
<Dialog
open={openDeleteDialog}
onClose={handleCloseDialogs}
PaperProps={{
sx: { borderRadius: "1vw", maxWidth: "40vw", overflow: "hidden" },
}}
>
<DialogTitle
sx={{
fontFamily: "Unbounded",
bgcolor: "#2D2D2D",
color: "white",
display: "flex",
alignItems: "center",
gap: "1vw",
}}
>
<DeleteIcon /> Удалить автомобиль
</DialogTitle>
<DialogContent sx={{ mt: "1vw", minWidth: "40vw" }}>
<Box sx={{ display: "flex", alignItems: "center", mb: "1vw" }}>
{selectedCar && (
<Box
component="img"
src={getImageUrl(selectedCar.image)}
alt={selectedCar.name}
sx={{
width: "10vw",
height: "5vw",
objectFit: "cover",
borderRadius: "1vw",
mr: "1vw",
pointerEvents: "none",
userSelect: "none",
}}
/>
)}
<Box>
<Typography
variant="h6"
sx={{ fontWeight: "bold", fontFamily: "Unbounded" }}
>
{selectedCar?.name}
</Typography>
{selectedCar && (
<Typography
variant="body2"
color="text.secondary"
sx={{ fontFamily: "Unbounded" }}
>
{selectedCar.year} г., {selectedCar.mileage} км,{" "}
{formatPrice(selectedCar.price)}
</Typography>
)}
</Box>
</Box>
<Alert severity="warning" sx={{ mt: "1vw", fontFamily: "Unbounded" }}>
Вы уверены, что хотите удалить этот автомобиль? Это действие нельзя
отменить.
</Alert>
</DialogContent>
<DialogActions sx={{ p: "1vw", bgcolor: "#f5f5f5" }}>
<Button
onClick={handleCloseDialogs}
sx={{
color: "black",
borderRadius: "1vw",
px: "1vw",
fontFamily: "Unbounded",
"&:hover": { bgcolor: "transparent", color: "#C27664" },
transition: "all 0.2s ease",
}}
>
Отмена
</Button>
<Button
onClick={handleDeleteCar}
variant="contained"
color="error"
sx={{
borderRadius: "1vw",
px: "2vw",
fontFamily: "Unbounded",
bgcolor: "#C27664",
color: "white",
"&:hover": { bgcolor: "#945B4D" },
transition: "all 0.2s ease",
}}
>
Удалить
</Button>
</DialogActions>
</Dialog>
</Box>
);
};
export default Vehicle;