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([]); 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(null); // Состояния для формы const [formData, setFormData] = useState({ name: '', year: '', mileage: '', price: '', base_price: '', country_of_origin: '', drive_type: '', engine_type: 'бензиновый', engine_capacity: '', engine_power: '', electric_motor_power: '', hybrid_type: 'не гибрид', power_ratio: 'не применимо', }); const [imageFile, setImageFile] = useState(null); const [imagePreview, setImagePreview] = useState(''); // Загрузка списка автомобилей 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) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; const handleImageChange = (e: React.ChangeEvent) => { 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: '', 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 || '', 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 = () => ( ID Изображение Название Год Пробег Цена Действия {filteredCars.map((car) => ( {car.id} {car.name} } label={car.year} size="small" sx={{ bgcolor: '#e8f5e9', color: '#2e7d32' }} /> } label={`${car.mileage} км`} size="small" sx={{ bgcolor: '#e3f2fd', color: '#1565c0' }} /> } label={formatPrice(car.price)} size="small" sx={{ bgcolor: '#fce4ec', color: '#c2185b' }} /> handleOpenEditDialog(car)} color="primary" sx={{ color: "black", '&:hover': { color: '#C27664', bgcolor: "transparent" }, transition: "all 0.2s ease", }} > handleOpenDeleteDialog(car)} color="error" sx={{ '&:hover': { color: '#C27664', bgcolor: 'transparent', }, transition: "all 0.2s ease", }} > ))}
); // Рендер сетки карточек const renderGrid = () => ( {filteredCars.map((car) => ( {car.name} Год выпуска: {car.year} Пробег: {car.mileage} км Цена: {formatPrice(car.price)} ))} ); return ( {/* Заголовок и кнопки управления */} Управление автомобилями {/* Панель поиска и переключения вида */} setSearchQuery(e.target.value)} size="small" sx={{ minWidth: 300, '& .MuiOutlinedInput-root': { borderRadius: "1vw" } }} InputProps={{ startAdornment: ( ), }} /> Всего: {totalCars} автомобилей setViewMode(newValue)} sx={{ '& .MuiTab-root': { minWidth: 'auto' }, '& .Mui-selected': { color: '#C27664 !important' }, '& .MuiTabs-indicator': { backgroundColor: '#C27664' } }} > } value="list" sx={{ minWidth: 'auto' }} /> } value="grid" sx={{ minWidth: 'auto' }} /> {/* Сообщения об ошибках */} {error && ( {error} )} {/* Индикатор загрузки */} {loading ? ( ) : filteredCars.length === 0 ? ( Автомобили не найдены Попробуйте изменить параметры поиска или добавьте новый автомобиль ) : ( // Отображение списка автомобилей в зависимости от выбранного режима viewMode === 'list' ? renderTable() : renderGrid() )} {/* Диалог создания автомобиля */} Добавить автомобиль {/* ), }} /> */} 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", mb: "1vw", "& fieldset": { border: "none", }, }, }} InputProps={{ startAdornment: ( ), }} /> {/* ), }} /> */} 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", mb: "1vw", "& fieldset": { border: "none", }, }, }} InputProps={{ startAdornment: ( ), }} /> {/* ), }} /> */} 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", mb: "1vw", "& fieldset": { border: "none", }, }, }} InputProps={{ startAdornment: ( ), }} /> {/* ), }} /> */} setFormData({ ...formData, price: 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", mb: "1vw", "& fieldset": { border: "none", }, }, }} InputProps={{ startAdornment: ( ), }} /> Страна происхождения Тип привода Тип двигателя {/* */} 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: ( см³ ), }} /> {imagePreview ? ( ) : ( Предпросмотр изображения )} {/* Диалог редактирования автомобиля */} Редактировать автомобиль ), }} /> ), }} /> ), }} /> ), }} /> {imagePreview ? ( ) : ( Предпросмотр изображения )} {/* Диалог удаления автомобиля */} Удалить автомобиль {selectedCar && ( )} {selectedCar?.name} {selectedCar && ( {selectedCar.year} г., {selectedCar.mileage} км, {formatPrice(selectedCar.price)} )} Вы уверены, что хотите удалить этот автомобиль? Это действие нельзя отменить. ); }; export default Vehicle;