import { useState, useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; import { FiSearch, FiPlus, FiSliders } from "react-icons/fi"; import { createRoom } from "../../store/slices/spaceSlice"; import { setActiveRoom } from "../../store/slices/appSlice"; import { getSpaceIconComponent } from "../../constants/spaceIcons"; function RoomItem({ room, isActive, onClick, lastMessage, lastMessageTime, unreadCount, }) { const [isHovered, setIsHovered] = useState(false); return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onClick={onClick} > {/* Room info */}
{room.name}
{room.is_private && ( Private )}
{/* Last message time */} {lastMessageTime && ( {lastMessageTime} )}
{/* Last message */}
0 ? "var(--text-primary)" : "var(--text-secondary)", fontWeight: unreadCount > 0 ? 500 : 400, }} > {lastMessage || "Bắt đầu trò chuyện"}
{/* Unread badge */} {unreadCount > 0 && ( {unreadCount > 99 ? "99+" : unreadCount} )}
); } function LoadingDots() { return (
); } function EmptyState({ isDark, onCreateRoomClick }) { return (
Chưa có room nào
Tạo room đầu tiên để bắt đầu thảo luận
); } function CreateRoomModal({ isOpen, onClose, onCreate, isDark }) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [isPrivate, setIsPrivate] = useState(false); if (!isOpen) return null; const handleSubmit = (e) => { e.preventDefault(); if (name.trim()) { onCreate({ name: name.trim(), description: description.trim(), isPrivate, }); setName(""); setDescription(""); setIsPrivate(false); onClose(); } }; return (

Tạo Room mới

setName(e.target.value)} placeholder="VD: Thảo luận, Tài liệu..." className="w-full px-3 py-2 rounded-md text-sm border outline-none" style={{ background: "var(--input-bg)", borderColor: "var(--input-border)", color: "var(--input-text)", }} autoFocus />
setDescription(e.target.value)} placeholder="Mô tả ngắn về room..." className="w-full px-3 py-2 rounded-md text-sm border outline-none" style={{ background: "var(--input-bg)", borderColor: "var(--input-border)", color: "var(--input-text)", }} />
setIsPrivate(e.target.checked)} className="w-4 h-4 cursor-pointer" style={{ accentColor: "var(--primary)" }} />
); } function SpaceRoomList({ activeSpace, activeRoom, setActiveRoom, searchQuery, setSearchQuery, onCreateRoomClick, }) { const { isDark } = useSelector((state) => state.theme); const dispatch = useDispatch(); const [isSearching, setIsSearching] = useState(false); const { spaces, roomsMap, roomsLoading, fetchedRooms, roomUnreadCounts, } = useSelector((state) => state.space); const currentUser = useSelector((state) => state.auth.user); const spaceRooms = roomsMap[activeSpace] || []; const isFetched = fetchedRooms[activeSpace]; // Helper to format last message from API const getRoomLastMessage = (room) => { const lastMsg = room.last_message; if (!lastMsg) return null; const isOwn = lastMsg.sender_id && currentUser?.id && String(lastMsg.sender_id) === String(currentUser.id); const senderName = isOwn ? "Bạn" : lastMsg.sender_display_name || lastMsg.username || "Unknown"; return { content: lastMsg.content, senderName, }; }; // Rooms are already fetched globally in App.jsx // This component only reads from Redux store, no need to fetch here const filteredRooms = spaceRooms.filter((room) => room.name.toLowerCase().includes(searchQuery.toLowerCase()), ); const handleSearchChange = (e) => { setSearchQuery(e.target.value); if (e.target.value.trim()) { setIsSearching(true); setTimeout(() => setIsSearching(false), 300); } else { setIsSearching(false); } }; const handleCreateRoom = (roomData) => { if (activeSpace) { dispatch(createRoom({ spaceId: activeSpace, data: roomData })); } }; const currentSpace = spaces.find((s) => s.id === activeSpace); return (
{/* Header */}
{currentSpace?.name || "Space"}
{/* Room list */}
{/* Header with create button — always visible */}
Rooms
{(roomsLoading || isSearching) && } {!roomsLoading && !isSearching && filteredRooms.length === 0 && ( )} {!isSearching && filteredRooms.length > 0 && (
{filteredRooms.map((room) => { const lastMsg = getRoomLastMessage(room); return ( setActiveRoom(room.id)} lastMessage={ lastMsg ? `${lastMsg.senderName}: ${lastMsg.content}` : null } unreadCount={roomUnreadCounts[room.id] || 0} /> ); })}
)}
); } export default SpaceRoomList;