6.25.0: Меню действий для досок вместо кнопок
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m11s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
poignatov
2026-03-19 20:10:34 +03:00
parent 6e7ebb9aa3
commit e8a766205f
6 changed files with 399 additions and 178 deletions

View File

@@ -11,6 +11,7 @@ import 'react-day-picker/style.css'
import './TaskList.css'
import './TaskDetail.css'
import './ShoppingList.css'
import './Wishlist.css'
const BOARDS_CACHE_KEY = 'shopping_boards_cache'
const ITEMS_CACHE_KEY = 'shopping_items_cache'
@@ -133,6 +134,7 @@ function ShoppingList({ onNavigate, refreshTrigger = 0, isActive = false, initia
const [postponeRemaining, setPostponeRemaining] = useState('')
const [isPostponing, setIsPostponing] = useState(false)
const [toast, setToast] = useState(null)
const [showBoardActionMenu, setShowBoardActionMenu] = useState(false)
const initialFetchDoneRef = useRef(false)
const prevIsActiveRef = useRef(isActive)
const itemsAbortRef = useRef(null)
@@ -388,15 +390,77 @@ function ShoppingList({ onNavigate, refreshTrigger = 0, isActive = false, initia
const handleBoardEdit = (boardId) => {
const id = boardId || selectedBoardId
if (id) {
onNavigate('shopping-board-form', { boardId: id })
if (!id) return
const board = boards.find(b => b.id === id)
if (board && !board.is_owner) {
openBoardActionMenu()
return
}
onNavigate('shopping-board-form', { boardId: id })
}
const handleAddBoard = () => {
onNavigate('shopping-board-form')
}
const openBoardActionMenu = () => {
setShowBoardActionMenu(true)
}
const closeBoardActionMenu = () => {
setShowBoardActionMenu(false)
}
const handleBoardArchive = async () => {
const board = boards.find(b => b.id === selectedBoardId)
if (!board) return
if (board.is_archived) {
setShowBoardActionMenu(false)
try {
const res = await authFetch(`/api/shopping/boards/${selectedBoardId}/unarchive`, {
method: 'POST'
})
if (res.ok) {
fetchBoards()
fetchItems(selectedBoardId)
}
} catch (err) {
console.error('Error unarchiving board:', err)
}
} else {
if (!window.confirm('Архивировать доску? Она переместится в архив.')) return
setShowBoardActionMenu(false)
try {
const res = await authFetch(`/api/shopping/boards/${selectedBoardId}/archive`, {
method: 'POST'
})
if (res.ok) {
fetchBoards()
}
} catch (err) {
console.error('Error archiving board:', err)
}
}
}
const handleBoardLeave = async () => {
if (!window.confirm('Покинуть доску? Вы больше не будете видеть её товары.')) return
setShowBoardActionMenu(false)
try {
const res = await authFetch(`/api/shopping/boards/${selectedBoardId}/leave`, {
method: 'POST'
})
if (res.ok) {
fetchBoards()
}
} catch (err) {
console.error('Error leaving board:', err)
}
}
const handleRefresh = () => {
if (selectedBoardId) fetchItems(selectedBoardId)
}
@@ -941,6 +1005,31 @@ function ShoppingList({ onNavigate, refreshTrigger = 0, isActive = false, initia
onClose={() => setToast(null)}
/>
)}
{showBoardActionMenu && createPortal(
<div className="wishlist-modal-overlay" style={{ zIndex: 2000 }} onClick={closeBoardActionMenu}>
<div className="wishlist-modal" onClick={(e) => e.stopPropagation()}>
<div className="wishlist-modal-header">
<h3>{boards.find(b => b.id === selectedBoardId)?.name}</h3>
</div>
<div className="wishlist-modal-actions">
{boards.find(b => b.id === selectedBoardId)?.is_archived ? (
<button className="wishlist-modal-copy" onClick={handleBoardArchive}>
Разархивировать
</button>
) : (
<button className="wishlist-modal-copy" onClick={handleBoardArchive}>
Архивировать
</button>
)}
<button className="wishlist-modal-delete" onClick={handleBoardLeave}>
Выйти
</button>
</div>
</div>
</div>,
document.body
)}
</div>
)
}