Cho phép xóa tour và xóa chặng trong Tour Dashboard

This commit is contained in:
2026-06-13 21:48:53 +07:00
parent 578b03d808
commit 5e3f10631f
18 changed files with 580 additions and 42 deletions
+24 -3
View File
@@ -4,7 +4,7 @@ import { MapContainer, TileLayer, Marker, Popup, useMap } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { useTourStore } from './useTourStore.js';
import { X, Navigation, Image as ImageIcon, LogOut, Settings } from 'lucide-react';
import { X, Navigation, Image as ImageIcon, LogOut, Settings, Edit2, Trash2 } from 'lucide-react';
import { UserManagementModal } from './UserManagementModal.js';
import { CreateTourModal } from './CreateTourModal.js';
const DefaultIcon = L.icon({
@@ -22,7 +22,7 @@ function RecenterMap({ position }) {
return null;
}
export const ExploreMap = ({ onBack, onLogout, user, onViewTour }) => {
const { publicTours, fetchPublicTours, fetchTour } = useTourStore();
const { publicTours, fetchPublicTours, fetchTour, updateTour, deleteTour } = useTourStore();
const [userPos, setUserPos] = useState([10.7769, 106.7009]);
const [isAdminModalOpen, setIsAdminModalOpen] = useState(false);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
@@ -30,6 +30,27 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour }) => {
fetchPublicTours();
navigator.geolocation.getCurrentPosition((pos) => setUserPos([pos.coords.latitude, pos.coords.longitude]), () => console.log("Không thể lấy vị trí người dùng"));
}, []);
const handleEditTour = async (tour) => {
const newTitle = window.prompt("Nhập tên mới cho Tour:", tour.title);
if (newTitle && newTitle !== tour.title) {
try {
await updateTour(tour.id, { title: newTitle });
}
catch (err) {
alert(err.message);
}
}
};
const handleDeleteTour = async (id) => {
if (window.confirm("Bạn có chắc chắn muốn xóa Tour này và toàn bộ dữ liệu liên quan?")) {
try {
await deleteTour(id);
}
catch (err) {
alert(err.message);
}
}
};
return (_jsxs("div", { className: "h-screen w-full relative", children: [_jsx("button", { onClick: onBack, className: "absolute top-6 left-6 z-[1000] bg-white p-3 rounded-full shadow-xl hover:bg-gray-50 transition-all", children: _jsx(X, { className: "w-6 h-6 text-gray-800" }) }), onLogout && (_jsxs("button", { onClick: onLogout, className: "absolute top-6 right-6 z-[1000] bg-white px-4 py-3 rounded-2xl shadow-xl hover:bg-red-50 hover:text-red-600 transition-all flex items-center gap-2 font-bold text-gray-700", children: [_jsx(LogOut, { className: "w-5 h-5" }), _jsx("span", { className: "hidden sm:inline", children: "\u0110\u0103ng xu\u1EA5t" })] })), user?.isAdmin && (_jsxs("button", { onClick: () => setIsAdminModalOpen(true), className: "absolute top-6 right-40 z-[1000] bg-blue-600 px-4 py-3 rounded-2xl shadow-xl hover:bg-blue-700 text-white transition-all flex items-center gap-2 font-bold", children: [_jsx(Settings, { className: "w-5 h-5" }), _jsx("span", { className: "hidden sm:inline", children: "Qu\u1EA3n l\u00FD h\u1EC7 th\u1ED1ng" })] })), user && (_jsxs("button", { onClick: () => setIsCreateModalOpen(true), className: "absolute top-6 right-80 z-[1000] bg-green-600 px-4 py-3 rounded-2xl shadow-xl hover:bg-green-700 text-white transition-all flex items-center gap-2 font-bold", children: [_jsx(Navigation, { className: "w-5 h-5" }), _jsx("span", { className: "hidden sm:inline", children: "T\u1EA1o Tour m\u1EDBi" })] })), _jsx("div", { className: "absolute top-6 left-20 z-[1000] bg-white/90 backdrop-blur-md px-6 py-3 rounded-2xl shadow-xl border border-white/20 hidden sm:block", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Navigation, { className: "w-4 h-4 text-blue-600" }), _jsx("span", { className: "font-bold text-gray-800", children: "\u0110ang kh\u00E1m ph\u00E1 khu v\u1EF1c c\u1EE7a b\u1EA1n" })] }) }), _jsxs(MapContainer, { center: userPos, zoom: 13, className: "h-full w-full", children: [_jsx(TileLayer, { url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution: '\u00A9 OpenStreetMap contributors' }), _jsx(RecenterMap, { position: userPos }), publicTours.map((tour) => {
const location = tour.legs?.[0]?.locations?.[0];
if (!location)
@@ -48,7 +69,7 @@ export const ExploreMap = ({ onBack, onLogout, user, onViewTour }) => {
</div>
`,
iconSize: [48, 48],
}), children: _jsx(Popup, { className: "custom-popup", children: _jsxs("div", { className: "p-1 max-w-[200px]", children: [_jsx("img", { src: tourImage, className: "w-full h-32 object-cover rounded-lg mb-2" }), _jsx("h4", { className: "font-bold text-gray-900 leading-tight mb-1", children: tour.title }), _jsxs("button", { onClick: () => onViewTour(tour.id), className: "text-xs font-bold text-blue-600 flex items-center gap-1", children: ["Xem chi ti\u1EBFt h\u00ECnh \u1EA3nh ", _jsx(ImageIcon, { className: "w-3 h-3" })] })] }) }) }, tour.id));
}), children: _jsx(Popup, { className: "custom-popup", children: _jsxs("div", { className: "p-1 max-w-[200px]", children: [_jsx("img", { src: tourImage, className: "w-full h-32 object-cover rounded-lg mb-2" }), _jsx("h4", { className: "font-bold text-gray-900 leading-tight mb-1", children: tour.title }), _jsxs("button", { onClick: () => onViewTour(tour.id), className: "text-xs font-bold text-blue-600 flex items-center gap-1", children: ["Xem chi ti\u1EBFt h\u00ECnh \u1EA3nh ", _jsx(ImageIcon, { className: "w-3 h-3" })] }), user && (_jsxs("div", { className: "flex gap-2 mt-3 pt-3 border-t border-gray-100", children: [_jsxs("button", { onClick: () => handleEditTour(tour), className: "flex-1 flex items-center justify-center gap-1 py-1.5 bg-blue-50 text-blue-600 rounded-lg text-[10px] font-bold hover:bg-blue-100 transition-colors", children: [_jsx(Edit2, { className: "w-3 h-3" }), " S\u1EEDa"] }), _jsxs("button", { onClick: () => handleDeleteTour(tour.id), className: "flex-1 flex items-center justify-center gap-1 py-1.5 bg-red-50 text-red-600 rounded-lg text-[10px] font-bold hover:bg-red-100 transition-colors", children: [_jsx(Trash2, { className: "w-3 h-3" }), " X\u00F3a"] })] }))] }) }) }, tour.id));
})] }), _jsx(UserManagementModal, { isOpen: isAdminModalOpen, onClose: () => setIsAdminModalOpen(false) }), _jsx(CreateTourModal, { isOpen: isCreateModalOpen, onClose: () => setIsCreateModalOpen(false), onSuccess: (tour) => {
fetchTour(tour.id);
onViewTour(tour.id);