._.
This commit is contained in:
parent
35c7e12bdc
commit
fd0ece2957
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
59
src/api.jsx
59
src/api.jsx
@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -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
223
src/pages/Cities.jsx
Normal 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;
|
||||||
Loading…
x
Reference in New Issue
Block a user