Cài đặt tính năng người quản lí có thể khai báo số lượng người tham gia

This commit is contained in:
2026-06-15 20:52:43 +07:00
parent 75cf96898c
commit 8dac79fc4b
4 changed files with 86 additions and 8 deletions
+79 -7
View File
@@ -162,6 +162,13 @@ const MapContextMenu = ({ onAction }: { onAction: (action: string, latlng: L.Lat
};
export const TourDetailPage = ({ onBack }: { onBack: () => void }) => {
// Tách biệt các state và actions để tối ưu performance - Chuyển lên đầu để tránh lỗi initialization
const currentTour = useTourStore(state => state.currentTour);
const legs = useTourStore(state => state.legs);
const publicTours = useTourStore(state => state.publicTours);
const userRole = useTourStore(state => state.userRole);
const mapCenter = useTourStore(state => state.mapCenter);
const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings'>('plan');
const [viewMode, setViewMode] = useState<'map' | 'timeline'>('timeline');
const [isAddLocationOpen, setIsAddLocationOpen] = useState(false);
@@ -171,21 +178,19 @@ export const TourDetailPage = ({ onBack }: { onBack: () => void }) => {
const [selectedMember, setSelectedMember] = useState<any>(null);
const [isMemberDetailOpen, setIsMemberDetailOpen] = useState(false);
const [joinRequests, setJoinRequests] = useState<any[]>([]);
// State cho input số lượng người tham gia
const [adultCountInput, setAdultCountInput] = useState(currentTour?.adultCount ?? 0);
const [childCountInput, setChildCountInput] = useState(currentTour?.childCount ?? 0);
const [childDiscountInput, setChildDiscountInput] = useState(currentTour?.childDiscount ?? 0);
const [joinRequestActionId, setJoinRequestActionId] = useState<string | null>(null);
const [confirmState, setConfirmState] = useState<{ open: boolean; title?: string; message?: string; onConfirm?: () => void }>({ open: false });
// Tách biệt các state và actions để tối ưu performance
const currentTour = useTourStore(state => state.currentTour);
const legs = useTourStore(state => state.legs);
const publicTours = useTourStore(state => state.publicTours);
const userRole = useTourStore(state => state.userRole);
const mapCenter = useTourStore(state => state.mapCenter);
const fetchTour = useTourStore(state => state.fetchTour);
const fetchPublicTours = useTourStore(state => state.fetchPublicTours);
const setMapCenter = useTourStore(state => state.setMapCenter);
const updateTourStartPoint = useTourStore(state => state.updateTourStartPoint);
const updateTourEndPoint = useTourStore(state => state.updateTourEndPoint);
const updateTourDetails = useTourStore(state => state.updateTourDetails); // Thêm action này
const initializeLegs = useTourStore(state => state.initializeLegs);
const addLocation = useTourStore(state => state.addLocation);
const removeMember = useTourStore(state => state.removeMember);
@@ -334,6 +339,21 @@ export const TourDetailPage = ({ onBack }: { onBack: () => void }) => {
}
};
// Hàm xử lý cập nhật số lượng người tham gia
const handleUpdateParticipantCounts = async () => {
if (!currentTour) return;
try {
await updateTourDetails(currentTour.id, {
adultCount: adultCountInput,
childCount: childCountInput,
childDiscount: childDiscountInput,
});
notificationModal.openModal('Thành công', 'Đã cập nhật số lượng người tham gia.', 'success');
fetchTour(currentTour.id); // Re-fetch tour để cập nhật lại các tính toán liên quan
} catch (error: any) {
notificationModal.openModal('Lỗi', error.message || 'Không thể cập nhật số lượng người tham gia.', 'error');
}
};
// Xác định Điểm xuất phát và Điểm kết thúc hiển thị dưới widget tài chính
const startPoint = legs[0]?.locations[0];
const lastLeg = legs[legs.length - 1];
@@ -798,6 +818,58 @@ export const TourDetailPage = ({ onBack }: { onBack: () => void }) => {
)}
</div>
</div>
{canEdit && ( // Chỉ OWNER và MANAGER mới có thể chỉnh sửa phần này
<div className="p-6 bg-white rounded-3xl border border-gray-100 shadow-sm animate-in zoom-in-95">
<div className="flex items-center gap-3 mb-4">
<Users className="w-6 h-6 text-purple-500" />
<h3 className="text-lg font-bold text-gray-900">Quản số lượng người tham gia</h3>
</div>
<div className="space-y-4">
<div>
<label htmlFor="adultCount" className="block text-sm font-medium text-gray-700 mb-1">Số lượng người lớn</label>
<input
type="number"
id="adultCount"
value={adultCountInput}
onChange={(e) => setAdultCountInput(Number(e.target.value))}
min="0"
className="w-full px-4 py-2 border border-gray-200 rounded-xl focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label htmlFor="childCount" className="block text-sm font-medium text-gray-700 mb-1">Số lượng trẻ em</label>
<input
type="number"
id="childCount"
value={childCountInput}
onChange={(e) => setChildCountInput(Number(e.target.value))}
min="0"
className="w-full px-4 py-2 border border-gray-200 rounded-xl focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label htmlFor="childDiscount" className="block text-sm font-medium text-gray-700 mb-1">Giảm giá trẻ em (%)</label>
<input
type="number"
id="childDiscount"
value={childDiscountInput}
onChange={(e) => setChildDiscountInput(Number(e.target.value))}
min="0"
max="100"
className="w-full px-4 py-2 border border-gray-200 rounded-xl focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<button
onClick={handleUpdateParticipantCounts}
className="w-full px-4 py-3 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl transition-all shadow-md"
>
Lưu thay đi
</button>
</div>
</div>
)}
<div className="p-8 text-center bg-gray-50 rounded-3xl border border-dashed border-gray-200">
<Settings className="w-10 h-10 text-gray-300 mx-auto mb-3" />
<p className="text-gray-500 font-medium">Tính năng cài đt khác đang đưc cập nhật...</p>