bugs: lỗi khi người dùng link để tham gia tour nhưng không xuất hiện trong danh sách thành viên
This commit is contained in:
@@ -844,6 +844,27 @@ export const TourDetailPage = ({
|
||||
const canUploadPhoto = isPublicView ? false : ['OWNER', 'MANAGER', 'MEMBER', 'MEMBER_NO_FINANCE'].includes(userRole || '');
|
||||
const isOwner = isPublicView ? false : userRole === 'OWNER';
|
||||
const canShare = isPublicView || ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '');
|
||||
const canManage = isOwner || (!isPublicView && userRole === 'MANAGER');
|
||||
|
||||
const duplicateMatches = useMemo(() => {
|
||||
if (!canManage || !currentTour?.participants) return [];
|
||||
|
||||
const manualMembers = currentTour.participants.filter((p: any) => !p.userId && p.displayName);
|
||||
const systemMembers = currentTour.participants.filter((p: any) => p.userId && p.user?.name);
|
||||
|
||||
const matches: Array<{ manual: any; system: any }> = [];
|
||||
|
||||
manualMembers.forEach((m: any) => {
|
||||
const match = systemMembers.find((s: any) => {
|
||||
return s.user.name.trim().toLowerCase() === m.displayName.trim().toLowerCase();
|
||||
});
|
||||
if (match) {
|
||||
matches.push({ manual: m, system: match });
|
||||
}
|
||||
});
|
||||
|
||||
return matches;
|
||||
}, [canManage, currentTour?.participants]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPublicView) {
|
||||
@@ -1609,6 +1630,45 @@ export const TourDetailPage = ({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{duplicateMatches.map((match) => (
|
||||
<div key={match.manual.id} className="mt-3 p-3 bg-amber-500/20 backdrop-blur-md border border-amber-500/30 rounded-2xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 text-xs text-amber-100 animate-in fade-in slide-in-from-top-1 shadow-lg">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-amber-400 animate-pulse shrink-0"></span>
|
||||
<span>
|
||||
Phát hiện thành viên ngoài hệ thống <strong>"{match.manual.displayName}"</strong> trùng tên với tài khoản <strong>"{match.system.user.name}"</strong> vừa tham gia.
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/v1/tours/${currentTour.id}/members/merge`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
manualParticipantId: match.manual.id,
|
||||
systemUserId: match.system.userId
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
throw new Error(data.message || 'Hợp nhất thất bại.');
|
||||
}
|
||||
notify({ title: 'Thành công', message: 'Đã gán thành viên ngoài hệ thống thành công!', type: 'success' });
|
||||
fetchTour(currentTour.id);
|
||||
} catch (e: any) {
|
||||
notify({ title: 'Lỗi', message: e.message || 'Không thể hợp nhất', type: 'error' });
|
||||
}
|
||||
}}
|
||||
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]"
|
||||
>
|
||||
Gán & Hợp nhất
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user