This commit is contained in:
Андрей Дувакин 2024-10-05 12:10:59 +05:00
parent 35c7e12bdc
commit fd0ece2957
4 changed files with 289 additions and 0 deletions

View File

@ -3,6 +3,7 @@ import Login from "./pages/Login";
import Home from "./pages/Home.jsx"; import Home from "./pages/Home.jsx";
import Accessories from "./pages/Accessories.jsx"; import Accessories from "./pages/Accessories.jsx";
import PrivateRoute from "./components/PrivateRoute"; import PrivateRoute from "./components/PrivateRoute";
import Cities from "./pages/Cities.jsx";
const RoutesComponent = () => ( const RoutesComponent = () => (
<Routes> <Routes>
@ -10,6 +11,7 @@ const RoutesComponent = () => (
<Route element={<PrivateRoute />}> <Route element={<PrivateRoute />}>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/accessories" element={<Accessories />} /> <Route path="/accessories" element={<Accessories />} />
<Route path="/cities" element={<Cities />} />
</Route> </Route>
</Routes> </Routes>
); );

View File

@ -111,3 +111,62 @@ export const getCities = async () => {
throw error; throw error;
} }
}; };
export const createCity = async (cityData) => {
try {
const response = await axios.post(`${API_URL}/cities`, cityData, {
headers: {
Authorization: `Bearer ${getAuthToken()}`,
"Content-Type": "application/json",
},
});
return response.data;
} catch (error) {
console.log("Ошибка при создании города:", error);
throw error;
}
};
export const updateCity = async (id, cityData) => {
try {
const response = await axios.put(`${API_URL}/cities/${id}`, cityData, {
headers: {
Authorization: `Bearer ${getAuthToken()}`,
"Content-Type": "application/json",
},
});
return response.data;
} catch (error) {
console.log("Ошибка при обновлении города:", error);
throw error;
}
};
export const deleteCity = async (id) => {
try {
await axios.delete(`${API_URL}/cities/${id}`, {
headers: {
Authorization: `Bearer ${getAuthToken()}`,
Accept: "application/json",
},
});
} catch (error) {
console.log("Ошибка при удалении города:", error);
throw error;
}
};
export const getFederalDistricts = async () => {
try {
const response = await axios.get(`${API_URL}/federal-districts`, {
headers: {
Authorization: `Bearer ${getAuthToken()}`,
Accept: "application/json",
},
});
return response.data;
} catch (error) {
console.log("Ошибка при получении федеральных округов:", error);
throw error;
}
};

View File

@ -30,6 +30,11 @@ const Header = () => {
Компоненты Компоненты
</Link> </Link>
</li> </li>
<li className="nav-item">
<Link className="nav-link" to="/cities">
Города
</Link>
</li>
</ul> </ul>
<div className="d-flex align-items-center ml-auto"> <div className="d-flex align-items-center ml-auto">
{isAuthenticated ? ( {isAuthenticated ? (

223
src/pages/Cities.jsx Normal file
View File

@ -0,0 +1,223 @@
import React, { useState, useEffect } from "react";
import SelectionDialog from "../components/SelectionDialog.jsx";
import { useNavigate } from "react-router-dom";
import { getAuthToken } from "../api.jsx";
import {
getCities,
createCity,
updateCity,
deleteCity,
getFederalDistricts,
} from "../api.jsx";
const Cities = () => {
const [cities, setCities] = useState([]);
const [federalDistricts, setFederalDistricts] = useState([]);
const [newCity, setNewCity] = useState({
name: "",
federal_district_id: "",
});
const [editingCityId, setEditingCityId] = useState(null);
const [error, setError] = useState(null);
const [showDistrictDialog, setShowDistrictDialog] = useState(false);
const navigate = useNavigate();
useEffect(() => {
fetchCities();
fetchFederalDistricts();
}, []);
const fetchCities = async () => {
try {
const data = await getCities();
setCities(data);
} catch (error) {
console.error("Ошибка при загрузке городов:", error);
}
};
const fetchFederalDistricts = async () => {
try {
const data = await getFederalDistricts();
setFederalDistricts(data);
} catch (error) {
console.error("Ошибка при загрузке федеральных округов:", error);
}
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setNewCity({ ...newCity, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!newCity.name || !newCity.federal_district_id) {
setError("Пожалуйста, заполните все поля.");
return;
}
try {
if (editingCityId) {
await updateCity(editingCityId, newCity);
} else {
await createCity(newCity);
}
fetchCities();
resetForm();
} catch (error) {
console.error("Ошибка при добавлении или обновлении города:", error);
}
};
const handleEdit = (city) => {
setNewCity({
name: city.name,
federal_district_id: city.federal_district_id,
federal_district_name: city.federal_district_name,
});
setEditingCityId(city.id);
};
const handleDelete = async (cityId) => {
try {
await deleteCity(cityId);
fetchCities();
} catch (error) {
console.error("Ошибка при удалении города:", error);
}
};
const resetForm = () => {
setNewCity({
name: "",
federal_district_id: "",
});
setEditingCityId(null);
};
const handleDialogSelectDistrict = (selectedItem) => {
setNewCity({
...newCity,
federal_district_id: selectedItem.id,
federal_district_name: selectedItem.name,
});
setShowDistrictDialog(false);
};
if (getAuthToken() === null) {
navigate("/login");
}
return (
<div className="container mt-4">
<h3>Города</h3>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="cityName">Название города</label>
<input
type="text"
className="form-control"
id="cityName"
name="name"
placeholder="Введите название города"
value={newCity.name}
onChange={handleInputChange}
/>
</div>
<div className="input-group mb-3">
<input
type="text"
className="form-control"
id="federalDistrictId"
name="federalDistrictId"
placeholder="Выберите федеральный округ"
value={
newCity.federal_district_name ? newCity.federal_district_name : ""
}
readOnly
onClick={() => setShowDistrictDialog(true)}
/>
<div className="input-group-append">
<button
type="button"
className="btn btn-outline-secondary"
onClick={() => setShowDistrictDialog(true)}
>
Выбрать
</button>
</div>
</div>
<div className="btn-group">
<button type="submit" className="btn btn-primary">
{editingCityId ? "Обновить" : "Создать"}
</button>
<button
type="button"
className="btn btn-secondary"
onClick={resetForm}
>
Отменить
</button>
</div>
{error && (
<div className="alert alert-danger mt-3" role="alert">
{error}
</div>
)}
</form>
<h3 className="mt-5">Список городов</h3>
<table className="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Название</th>
<th>Федеральный округ</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
{cities.map((city) => (
<tr key={city.id}>
<td>{city.id}</td>
<td>{city.name}</td>
<td>{city.federal_district_name}</td>
<td>
<div className="btn-group">
<button
className="btn btn-warning"
onClick={() => handleEdit(city)}
>
Изменить
</button>
<button
className="btn btn-danger"
onClick={() => handleDelete(city.id)}
>
Удалить
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
<SelectionDialog
show={showDistrictDialog}
handleClose={() => setShowDistrictDialog(false)}
items={federalDistricts}
columns={[
{ key: "id", label: "ID" },
{ key: "name", label: "Название" },
]}
onSelect={handleDialogSelectDistrict}
/>
</div>
);
};
export default Cities;