fix: tags không có trong csdl gây nên lỗi crash backend

This commit is contained in:
2026-06-16 11:15:39 +07:00
parent bc49e081c6
commit 8cca4a83ca
9 changed files with 189 additions and 10 deletions
+63 -1
View File
@@ -29,7 +29,8 @@ import {
Check,
X,
MessageSquare,
Share2
Share2,
Tag as TagIcon
} from 'lucide-react';
import L from 'leaflet';
@@ -188,6 +189,10 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
const [adultCountInput, setAdultCountInput] = useState(currentTour?.adultCount ?? 0);
const [childCountInput, setChildCountInput] = useState(currentTour?.childCount ?? 0);
const [childDiscountInput, setChildDiscountInput] = useState(currentTour?.childDiscount ?? 0);
const [tagsInput, setTagsInput] = useState<string[]>(currentTour?.tags ?? []);
const [customTag, setCustomTag] = useState('');
const availableTags = ['Văn hóa', 'Mạo hiểm', 'Nghỉ dưỡng', 'Thư giãn', 'Ẩm thực', 'Khám phá', 'Gia đình'];
const [isCommentModalOpen, setIsCommentModalOpen] = useState(false);
const [commentLocationId, setCommentLocationId] = useState('');
const [commentLocationName, setCommentLocationName] = useState('');
@@ -197,6 +202,12 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
const fetchTour = useTourStore(state => state.fetchTour);
const fetchPublicTourDetails = useTourStore(state => state.fetchPublicTourDetails); // New action
useEffect(() => {
if (currentTour) {
setTagsInput(currentTour.tags || []);
}
}, [currentTour]);
// Hàm tối ưu để cập nhật số lượng bình luận mà không cần fetch lại toàn bộ Tour
const handleCommentIncrement = (locationId: string) => {
const currentLegs = useTourStore.getState().legs;
@@ -424,6 +435,7 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
adultCount: adultCountInput,
childCount: childCountInput,
childDiscount: childDiscountInput,
tags: tagsInput
});
notificationModal.openModal('Thành công', 'Đã cập nhật thông tin chuyến đi.', 'success');
fetchTour(currentTour.id); // Re-fetch tour để cập nhật lại các tính toán liên quan
@@ -514,6 +526,16 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
<div className="max-w-2xl mx-auto space-y-4">
<h2 className="text-3xl font-black tracking-tight drop-shadow-md">{tourInfo.title}</h2>
{currentTour?.tags && currentTour.tags.length > 0 && (
<div className="flex flex-wrap gap-2">
{currentTour.tags.map((tag: string) => (
<span key={tag} className="px-2.5 py-1 bg-white/20 backdrop-blur-md border border-white/30 rounded-lg text-[10px] font-black uppercase tracking-wider">
{tag}
</span>
))}
</div>
)}
{currentTour?.description && (
<p className="text-sm md:text-base text-white/90 max-w-xl line-clamp-3 md:line-clamp-none bg-black/20 backdrop-blur-sm p-4 rounded-2xl border border-white/10 italic leading-relaxed">
<Quote className="w-4 h-4 inline-block mr-2 opacity-50" />
@@ -999,6 +1021,46 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
/>
</div>
</div>
<div>
<label className="block text-xs font-black text-gray-400 uppercase tracking-widest mb-2 ml-1 flex items-center gap-2">
<TagIcon className="w-3 h-3" /> Phân loại Tour
</label>
<div className="flex flex-wrap gap-2">
{availableTags.map(tag => (
<button
key={tag}
type="button"
onClick={() => setTagsInput(prev => prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag])}
className={`px-3 py-1.5 rounded-xl text-xs font-bold transition-all border ${
tagsInput.includes(tag)
? 'bg-blue-600 text-white border-blue-600'
: 'bg-white text-gray-500 border-gray-200 hover:border-blue-300'
}`}
>
{tag}
</button>
))}
</div>
<div className="flex gap-2 mt-3">
<input
type="text"
value={customTag}
onChange={(e) => setCustomTag(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), setTagsInput(prev => customTag.trim() && !prev.includes(customTag.trim()) ? [...prev, customTag.trim()] : prev), setCustomTag(''))}
placeholder="Thêm nhãn tùy chỉnh..."
className="flex-1 px-4 py-2.5 bg-gray-50 border border-gray-100 rounded-xl text-sm outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
type="button"
onClick={() => { if (customTag.trim() && !tagsInput.includes(customTag.trim())) { setTagsInput([...tagsInput, customTag.trim()]); setCustomTag(''); } }}
className="px-4 py-2 bg-blue-50 text-blue-600 rounded-xl text-xs font-bold hover:bg-blue-100 transition-all border border-blue-100"
>
Thêm
</button>
</div>
</div>
<button
onClick={handleUpdateTourInfo}
className="w-full mt-6 px-4 py-4 bg-blue-600 hover:bg-blue-700 text-white font-black uppercase tracking-widest rounded-2xl transition-all shadow-lg shadow-blue-100 active:scale-95"