fix: gộp các nút của thành viên và guest vào một
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { io, Socket } from 'socket.io-client';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import {
|
||||
Compass,
|
||||
Users,
|
||||
@@ -528,18 +526,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
useEffect(() => {
|
||||
if (!user?.id) return;
|
||||
|
||||
// Connect to WebSocket using same origin/proxy
|
||||
const socket = Capacitor.isNativePlatform()
|
||||
? io(import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn')
|
||||
: io();
|
||||
socketRef.current = socket;
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[WS] MemberDashboard connected:', socket.id);
|
||||
socket.emit('joinUser', user.id);
|
||||
});
|
||||
|
||||
socket.on('messageReceived', (message: any) => {
|
||||
const handleMessageReceived = (e: Event) => {
|
||||
const message = (e as CustomEvent).detail;
|
||||
// If we are actively chatting with the sender of this message
|
||||
if (activeChatUser && (message.senderId === activeChatUser.id || message.receiverId === activeChatUser.id)) {
|
||||
setChatMessages(prev => [...prev, message]);
|
||||
@@ -888,8 +876,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
});
|
||||
}}
|
||||
className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-95 z-20 ${muteNotifications
|
||||
? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
|
||||
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
|
||||
? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
|
||||
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
|
||||
}`}
|
||||
title={muteNotifications ? "Bật thông báo đẩy" : "Tắt thông báo đẩy"}
|
||||
>
|
||||
@@ -940,7 +928,7 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Explore Map Quick Button */}
|
||||
<div className="p-4 border-b border-slate-900">
|
||||
<div className="p-4 border-b border-slate-900 flex flex-col gap-2">
|
||||
<button
|
||||
onClick={onExploreTours}
|
||||
className="w-full py-4 px-4 bg-indigo-600 hover:bg-indigo-700 text-white rounded-2xl font-bold flex items-center justify-center gap-2 shadow-lg active:scale-98 transition-all"
|
||||
@@ -948,6 +936,17 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<Compass className="w-5 h-5 animate-spin-slow" />
|
||||
{t('exploreTourMap')}
|
||||
</button>
|
||||
|
||||
<a
|
||||
href={`${import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn'}/downloads/yotrip-latest.apk`}
|
||||
download="yotrip.apk"
|
||||
className="w-full py-3 px-4 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-2xl font-bold flex items-center justify-center gap-2 shadow-md active:scale-95 transition-all text-xs text-center"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-green-400 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
<span>Tải ứng dụng Android (APK)</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Menu Items List */}
|
||||
@@ -955,8 +954,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('tours')}
|
||||
className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'tours'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-850/80 border-slate-700/80'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-850/80 border-slate-700/80'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -982,8 +981,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('photos')}
|
||||
className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'photos'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-850/80 border-slate-700/80'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-850/80 border-slate-700/80'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1007,8 +1006,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('connections')}
|
||||
className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'connections'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-900/60 border-slate-800/60'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-900/60 border-slate-800/60'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1034,8 +1033,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('chats')}
|
||||
className={`w-full p-4 hover:bg-slate-900 text-white rounded-2xl flex items-center justify-between font-bold active:scale-98 transition-all border ${activeTab === 'chats'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-900/60 border-slate-800/60'
|
||||
? 'bg-indigo-900/40 border-indigo-500/40'
|
||||
: 'bg-slate-900/60 border-slate-800/60'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1083,8 +1082,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<div className="hidden md:block absolute bottom-0 left-0 w-[500px] h-[500px] bg-purple-500/5 rounded-full blur-[120px] pointer-events-none z-0"></div>
|
||||
|
||||
<div className={`w-full relative z-10 flex overflow-hidden transition-all duration-350 ${isMobile
|
||||
? 'flex-col h-full bg-slate-950'
|
||||
: 'max-w-7xl h-[90vh] bg-slate-900/30 border border-slate-800/80 shadow-2xl rounded-3xl backdrop-blur-md'
|
||||
? 'flex-col h-full bg-slate-950'
|
||||
: 'max-w-7xl h-[90vh] bg-slate-900/30 border border-slate-800/80 shadow-2xl rounded-3xl backdrop-blur-md'
|
||||
}`}>
|
||||
|
||||
{/* Mobile Detail Header: Only on Mobile detail mode */}
|
||||
@@ -1139,8 +1138,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
});
|
||||
}}
|
||||
className={`absolute -bottom-1 -right-1 p-1.5 rounded-full border shadow-md transition-all active:scale-90 z-20 ${muteNotifications
|
||||
? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
|
||||
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
|
||||
? 'bg-slate-900 border-slate-800 text-slate-400 hover:text-slate-200'
|
||||
: 'bg-indigo-650 border-indigo-500 text-white hover:bg-indigo-600'
|
||||
}`}
|
||||
title={muteNotifications ? "Bật thông báo đẩy" : "Tắt thông báo đẩy"}
|
||||
>
|
||||
@@ -1197,6 +1196,17 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<Compass className="w-4 h-4 animate-spin-slow" />
|
||||
Khám phá Bản đồ Tour
|
||||
</button>
|
||||
|
||||
<a
|
||||
href={`${import.meta.env.VITE_BACKEND_URL || 'https://yotrip.labz.io.vn'}/downloads/yotrip-latest.apk`}
|
||||
download="yotrip.apk"
|
||||
className="w-full py-2.5 px-4 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-xl font-bold flex items-center justify-center gap-2 shadow-md active:scale-95 transition-all duration-150 text-xs"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-green-400 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
<span>Tải ứng dụng Android (APK)</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Vertical Tabs */}
|
||||
@@ -1204,8 +1214,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('tours')}
|
||||
className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'tours'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1223,8 +1233,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('photos')}
|
||||
className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'photos'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1242,8 +1252,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('chats')}
|
||||
className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'chats'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1260,8 +1270,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => handleSelectTab('connections')}
|
||||
className={`w-full py-3 px-4 rounded-xl flex items-center justify-between text-sm font-bold transition-all duration-150 ${activeTab === 'connections'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
? 'bg-slate-800/80 text-white border-l-4 border-indigo-500 shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800/30 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -1307,8 +1317,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
|
||||
{/* Tab content renders here */}
|
||||
<div className={`flex-1 relative z-10 flex flex-col ${activeTab === 'chats' || activeTab === 'photos'
|
||||
? 'overflow-hidden p-0'
|
||||
: 'p-4 md:p-8 overflow-y-auto'
|
||||
? 'overflow-hidden p-0'
|
||||
: 'p-4 md:p-8 overflow-y-auto'
|
||||
}`}>
|
||||
|
||||
{/* TAB 1: MY TOURS */}
|
||||
@@ -1502,8 +1512,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => setConnectionSubTab('list')}
|
||||
className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all ${connectionSubTab === 'list'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
Danh sách kết nối
|
||||
@@ -1511,8 +1521,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => setConnectionSubTab('search')}
|
||||
className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all flex items-center gap-1.5 ${connectionSubTab === 'search'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<Search className="w-3.5 h-3.5" /> Tìm thành viên mới
|
||||
@@ -1520,8 +1530,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<button
|
||||
onClick={() => setConnectionSubTab('pending')}
|
||||
className={`px-4 py-1.5 rounded-lg text-xs font-bold transition-all relative ${connectionSubTab === 'pending'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
? 'bg-indigo-600 text-white shadow-md'
|
||||
: 'text-slate-400 hover:bg-slate-800 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
Yêu cầu chờ duyệt
|
||||
@@ -1572,8 +1582,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<p className="text-[10px] text-slate-400 truncate">{connUser.email}</p>
|
||||
<div className="mt-1.5 flex items-center gap-1.5">
|
||||
<span className={`px-2 py-0.5 rounded text-[8px] font-black uppercase tracking-wider border ${conn.type === 'FAMILY'
|
||||
? 'bg-rose-950/40 text-rose-300 border-rose-900/50'
|
||||
: 'bg-indigo-950/40 text-indigo-300 border-indigo-900/50'
|
||||
? 'bg-rose-950/40 text-rose-300 border-rose-900/50'
|
||||
: 'bg-indigo-950/40 text-indigo-300 border-indigo-900/50'
|
||||
}`}>
|
||||
{conn.type === 'FAMILY' ? t('familyGroup') : t('friends')}
|
||||
</span>
|
||||
@@ -1679,8 +1689,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
<div>
|
||||
{statusText ? (
|
||||
<span className={`px-3 py-1 rounded-lg text-xs font-bold border ${statusText === t('friends') || statusText === t('familyGroup')
|
||||
? 'bg-emerald-950/30 border-emerald-900/50 text-emerald-300'
|
||||
: 'bg-slate-800/80 border-slate-700 text-slate-400'
|
||||
? 'bg-emerald-950/30 border-emerald-900/50 text-emerald-300'
|
||||
: 'bg-slate-800/80 border-slate-700 text-slate-400'
|
||||
}`}>
|
||||
{statusText}
|
||||
</span>
|
||||
@@ -1842,8 +1852,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
key={conn.id}
|
||||
onClick={() => handleSelectChatUser(connUser)}
|
||||
className={`w-full p-3 rounded-xl flex items-center gap-3 transition-all text-left ${isActive
|
||||
? 'bg-indigo-650 text-white shadow-md'
|
||||
: 'text-slate-350 hover:bg-slate-850/40 hover:text-slate-100'
|
||||
? 'bg-indigo-650 text-white shadow-md'
|
||||
: 'text-slate-350 hover:bg-slate-850/40 hover:text-slate-100'
|
||||
}`}
|
||||
>
|
||||
{connUser.avatar ? (
|
||||
@@ -1929,8 +1939,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
className={`flex flex-col max-w-[70%] ${isMe ? 'self-end items-end' : 'self-start items-start'}`}
|
||||
>
|
||||
<div className={`p-3.5 rounded-2xl text-xs font-medium leading-relaxed flex flex-col gap-1.5 relative group ${isMe
|
||||
? 'bg-indigo-650 text-white rounded-br-none shadow-md shadow-indigo-950/20'
|
||||
: 'bg-slate-800 text-slate-200 rounded-bl-none border border-slate-700/60'
|
||||
? 'bg-indigo-650 text-white rounded-br-none shadow-md shadow-indigo-950/20'
|
||||
: 'bg-slate-800 text-slate-200 rounded-bl-none border border-slate-700/60'
|
||||
}`}>
|
||||
{msg.attachmentUrl && (
|
||||
<div className="relative rounded-lg overflow-hidden border border-black/10 max-w-xs group/img">
|
||||
@@ -1956,8 +1966,8 @@ export const MemberDashboard: React.FC<MemberDashboardProps> = ({
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`flex items-center gap-1.5 px-3 py-2 rounded-xl text-[11px] font-bold transition-all border ${isMe
|
||||
? 'bg-indigo-750 border-indigo-750/30 text-indigo-100 hover:bg-indigo-800'
|
||||
: 'bg-slate-900/60 border-slate-800/80 text-slate-200 hover:bg-slate-900'
|
||||
? 'bg-indigo-750 border-indigo-750/30 text-indigo-100 hover:bg-indigo-800'
|
||||
: 'bg-slate-900/60 border-slate-800/80 text-slate-200 hover:bg-slate-900'
|
||||
}`}
|
||||
>
|
||||
<MapPin className="w-3.5 h-3.5 text-rose-500 shrink-0 animate-bounce" />
|
||||
|
||||
Reference in New Issue
Block a user