import { Trans } from "@lingui/react/macro" import { Box, Stack } from "@mantine/core" import React from "react" import { TbChevronDown, TbChevronRight, TbInbox, TbStar, TbTag } from "react-icons/tb" import { Constants } from "@/app/constants" import { redirectToCategory, redirectToCategoryDetails, redirectToFeed, redirectToFeedDetails, redirectToTag, redirectToTagDetails, } from "@/app/redirect/thunks" import { useAppDispatch, useAppSelector } from "@/app/store" import type { TreeSubscription } from "@/app/tree/slice" import { collapseTreeCategory } from "@/app/tree/thunks" import type { Category, Subscription } from "@/app/types" import { categoryHasNewEntries, categoryUnreadCount, flattenCategoryTree } from "@/app/utils" import { Loader } from "@/components/Loader" import { OnDesktop } from "@/components/responsive/OnDesktop" import { TreeNode } from "./TreeNode" import { TreeSearch } from "./TreeSearch" const allIcon = const starredIcon = const tagIcon = const expandedIcon = const collapsedIcon = const errorThreshold = 9 export function Tree() { const root = useAppSelector(state => state.tree.rootCategory) const source = useAppSelector(state => state.entries.source) const tags = useAppSelector(state => state.user.tags) const showRead = useAppSelector(state => state.user.settings?.showRead) const dispatch = useAppDispatch() const isFeedDisplayed = (feed: Subscription) => { const isCurrentFeed = source.type === "feed" && source.id === String(feed.id) return isCurrentFeed || feed.unread > 0 || showRead } const isCategoryDisplayed = (category: Category): boolean => { const isCurrentCategory = source.type === "category" && source.id === category.id return ( isCurrentCategory || showRead || category.children.some(c => isCategoryDisplayed(c)) || category.feeds.some(f => isFeedDisplayed(f)) ) } const feedClicked = (e: React.MouseEvent, id: string) => { if (e.detail === 2) { dispatch(redirectToFeedDetails(id)) } else { dispatch(redirectToFeed(id)) } } const categoryClicked = (e: React.MouseEvent, id: string) => { if (e.detail === 2) { dispatch(redirectToCategoryDetails(id)) } else { dispatch(redirectToCategory(id)) } } const categoryIconClicked = (e: React.MouseEvent, category: Category) => { e.stopPropagation() dispatch( collapseTreeCategory({ id: +category.id, collapse: category.expanded, }) ) } const tagClicked = (e: React.MouseEvent, id: string) => { if (e.detail === 2) { dispatch(redirectToTagDetails(id)) } else { dispatch(redirectToTag(id)) } } const allCategoryNode = () => ( All} icon={allIcon} unread={categoryUnreadCount(root)} hasNewEntries={categoryHasNewEntries(root)} selected={source.type === "category" && source.id === Constants.categories.all.id} expanded={false} level={0} hasError={false} hasWarning={false} onClick={categoryClicked} /> ) const starredCategoryNode = () => ( Starred} icon={starredIcon} unread={0} hasNewEntries={false} selected={source.type === "category" && source.id === Constants.categories.starred.id} expanded={false} level={0} hasError={false} hasWarning={false} onClick={categoryClicked} /> ) const categoryNode = (category: Category, level = 0) => { if (!isCategoryDisplayed(category)) return null const hasError = !category.expanded && flattenCategoryTree(category).some(c => c.feeds.some(f => f.errorCount > errorThreshold)) const hasWarning = !category.expanded && flattenCategoryTree(category).some(c => c.feeds.some(f => !!f.filterLegacy)) return ( categoryIconClicked(e, category)} key={category.id} /> ) } const feedNode = (feed: TreeSubscription, level = 0) => { if (!isFeedDisplayed(feed)) return null return ( errorThreshold} hasWarning={!!feed.filterLegacy} onClick={feedClicked} key={feed.id} /> ) } const tagNode = (tag: string) => ( ) const recursiveCategoryNode = (category: Category, level = 0) => ( {categoryNode(category, level)} {category.expanded && category.children.map(c => recursiveCategoryNode(c, level + 1))} {category.expanded && category.feeds.map(f => feedNode(f, level + 1))} ) if (!root) return const feeds = flattenCategoryTree(root).flatMap(c => c.feeds) return ( {allCategoryNode()} {starredCategoryNode()} {root.children.map(c => recursiveCategoryNode(c))} {root.feeds.map(f => feedNode(f))} {tags?.map(tag => tagNode(tag))} ) }