fix: khách mời join vào tour gán với tên thêm thủ công

This commit is contained in:
2026-06-21 07:37:20 +07:00
parent 55fba75fda
commit 392a4d4766
6 changed files with 544 additions and 6 deletions
+29 -3
View File
@@ -5,6 +5,7 @@ import { ExpenseManager } from '../components/ExpenseManager';
import { useTourStore } from '@/store/useTourStore';
import { AddLocationModal } from '@/components/AddLocationModal';
import { AddMemberModal } from '../components/AddMemberModal';
import { MembersTab } from '../components/MembersTab';
import { useConfirm } from '@/hooks/useConfirm';
import { useNotification } from '@/hooks/useNotification';
import { CommentModal } from '@/components/CommentModal';
@@ -360,7 +361,8 @@ export const TourDetailPage = ({
const [userSpeed, setUserSpeed] = useState<number | null>(null); // Tốc độ di chuyển từ GPS
// Di chuyển khai báo state lên trên useEffect để tránh lỗi "before initialization"
const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings'>('plan');
const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings' | 'members'>('plan');
const [mergingId, setMergingId] = useState<string | null>(null);
const [viewMode, setViewMode] = useState<'map' | 'timeline'>('timeline');
const [isHeadingMode, setIsHeadingMode] = useState(false);
const [mapRotation, setMapRotation] = useState(0);
@@ -1398,6 +1400,7 @@ export const TourDetailPage = ({
{ id: 'plan', label: 'Lộ trình', icon: MapIcon, visible: true },
{ id: 'expense', label: 'Chi phí', icon: Wallet, visible: ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '') },
{ id: 'photo', label: 'Ảnh', icon: ImageIcon, visible: true },
{ id: 'members', label: 'Thành viên', icon: Users, visible: canManage },
{ id: 'settings', label: 'Cài đặt', icon: Settings, visible: userRole === 'OWNER' },
].filter(t => t.visible);
@@ -1640,7 +1643,15 @@ export const TourDetailPage = ({
</span>
</div>
<button
disabled={mergingId === match.manual.id}
onClick={async () => {
const isConfirmed = await confirm({
title: 'Hợp nhất thành viên',
message: `Gán tài khoản "${match.system.user.name}" thay thế cho thành viên thủ công "${match.manual.displayName}"? Thao tác này không thể hoàn tác.`
});
if (!isConfirmed) return;
setMergingId(match.manual.id);
try {
const res = await fetch(`/api/v1/tours/${currentTour.id}/members/merge`, {
method: 'POST',
@@ -1661,11 +1672,13 @@ export const TourDetailPage = ({
fetchTour(currentTour.id);
} catch (e: any) {
notify({ title: 'Lỗi', message: e.message || 'Không thể hợp nhất', type: 'error' });
} finally {
setMergingId(null);
}
}}
className="px-3.5 py-2 bg-amber-500 hover:bg-amber-600 active:scale-95 text-white font-black rounded-xl transition-all shrink-0 shadow-md text-[11px]"
className={`px-3.5 py-2 bg-amber-500 hover:bg-amber-600 active:scale-95 text-white font-black rounded-xl transition-all shrink-0 shadow-md text-[11px] ${mergingId === match.manual.id ? 'opacity-50 cursor-not-allowed' : ''}`}
>
Gán & Hợp nhất
{mergingId === match.manual.id ? 'Đang xử lý...' : 'Gán & Hợp nhất'}
</button>
</div>
))}
@@ -2641,6 +2654,19 @@ export const TourDetailPage = ({
</div>
</div>
)}
{activeTab === 'members' && canManage && currentTour && (
<MembersTab
tourId={currentTour.id}
participants={currentTour.participants || []}
joinRequests={joinRequests}
userRole={userRole}
canManage={canManage}
isOwner={isOwner}
onRemoveMember={(memberIdOrUserId: string) => removeMember(currentTour.id, memberIdOrUserId)}
onRefresh={() => fetchTour(currentTour.id)}
onOpenAddMember={() => setIsAddMemberOpen(true)}
/>
)}
</div>
</div>