import { Trans } from "@lingui/react/macro"; import { Box, Stack } from "@mantine/core"; import { Constants } from "app/constants"; import { redirectToCategory, redirectToCategoryDetails, redirectToFeed, redirectToFeedDetails, redirectToTag, redirectToTagDetails, } from "app/redirect/thunks"; import { useAppDispatch, useAppSelector } from "app/store"; import { collapseTreeCategory } from "app/tree/thunks"; import type { Category, Subscription, TreeSubscription } from "app/types"; import { categoryUnreadCount, flattenCategoryTree } from "app/utils"; import { Loader } from "components/Loader"; import { OnDesktop } from "components/responsive/OnDesktop"; import React, { useEffect, useState } from "react"; import { TbChevronDown, TbChevronRight, TbInbox, TbStar, TbTag, } from "react-icons/tb"; 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)); } }; console.log(root?.feeds.map(f => f.hasNewEntries)); const allCategoryNode = () => ( All} icon={allIcon} unread={categoryUnreadCount(root)} selected={ source.type === "category" && source.id === Constants.categories.all.id } expanded={false} level={0} hasError={false} onClick={categoryClicked} /> ); const starredCategoryNode = () => ( Starred} icon={starredIcon} unread={0} selected={ source.type === "category" && source.id === Constants.categories.starred.id } expanded={false} level={0} hasError={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) ); return ( categoryIconClicked(e, category)} key={category.id} /> ); }; const feedNode = (feed: TreeSubscription, level = 0) => { if (!isFeedDisplayed(feed)) return null; return ( errorThreshold} onClick={feedClicked} key={feed.id} newMessages={feed.hasNewEntries} /> ); }; 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))} ); }