121
play-life-web/src/components/BoardSelector.jsx
Normal file
121
play-life-web/src/components/BoardSelector.jsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React, { useState, useEffect, useRef } from 'react'
|
||||
import './BoardSelector.css'
|
||||
|
||||
function BoardSelector({
|
||||
boards,
|
||||
selectedBoardId,
|
||||
onBoardChange,
|
||||
onBoardEdit,
|
||||
onAddBoard,
|
||||
loading
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const dropdownRef = useRef(null)
|
||||
|
||||
const selectedBoard = boards.find(b => b.id === selectedBoardId)
|
||||
|
||||
// Закрытие при клике снаружи
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
||||
setIsOpen(false)
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside)
|
||||
}, [])
|
||||
|
||||
const handleSelectBoard = (board) => {
|
||||
onBoardChange(board.id)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="board-selector" ref={dropdownRef}>
|
||||
<div className="board-header">
|
||||
<button
|
||||
className={`board-pill ${isOpen ? 'open' : ''}`}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
disabled={loading}
|
||||
>
|
||||
<span className="board-label">
|
||||
{loading ? 'Загрузка...' : (selectedBoard?.name || 'Выберите доску')}
|
||||
</span>
|
||||
<svg
|
||||
className={`chevron ${isOpen ? 'rotated' : ''}`}
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 12 12"
|
||||
>
|
||||
<path
|
||||
d="M2.5 4.5L6 8L9.5 4.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{selectedBoard && (
|
||||
<button
|
||||
className="board-action-btn"
|
||||
onClick={onBoardEdit}
|
||||
title={selectedBoard.is_owner ? 'Настройки доски' : 'Покинуть доску'}
|
||||
>
|
||||
{selectedBoard.is_owner ? (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="1.5"></circle>
|
||||
<circle cx="19" cy="12" r="1.5"></circle>
|
||||
<circle cx="5" cy="12" r="1.5"></circle>
|
||||
</svg>
|
||||
) : (
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={`board-dropdown ${isOpen ? 'visible' : ''}`}>
|
||||
<div className="dropdown-content">
|
||||
{boards.length === 0 ? (
|
||||
<div className="dropdown-empty">
|
||||
Нет досок
|
||||
</div>
|
||||
) : (
|
||||
<div className="dropdown-list">
|
||||
{boards.map(board => (
|
||||
<button
|
||||
key={board.id}
|
||||
className={`dropdown-item ${board.id === selectedBoardId ? 'selected' : ''}`}
|
||||
onClick={() => handleSelectBoard(board)}
|
||||
>
|
||||
<span className="item-name">{board.name}</span>
|
||||
<div className="item-meta">
|
||||
<span className={`item-members ${board.is_owner ? 'filled' : 'outline'}`}>{board.member_count + 1}</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button className="dropdown-item add-board" onClick={onAddBoard}>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="12" y1="8" x2="12" y2="16"></line>
|
||||
<line x1="8" y1="12" x2="16" y2="12"></line>
|
||||
</svg>
|
||||
<span>Создать доску</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BoardSelector
|
||||
Reference in New Issue
Block a user