diff --git a/commafeed-client/src/app/entries/thunks.ts b/commafeed-client/src/app/entries/thunks.ts index 88c5abd1..3a85f601 100644 --- a/commafeed-client/src/app/entries/thunks.ts +++ b/commafeed-client/src/app/entries/thunks.ts @@ -3,6 +3,7 @@ import { client } from "app/client" import { Constants } from "app/constants" import { type EntrySource, type EntrySourceType, entriesSlice, setMarkAllAsReadConfirmationDialogOpen, setSearch } from "app/entries/slice" import type { RootState } from "app/store" +import { setHasNewEntries } from "app/tree/slice" import { reloadTree } from "app/tree/thunks" import type { Entry, MarkRequest, TagRequest } from "app/types" import { reloadTags } from "app/user/thunks" @@ -26,6 +27,9 @@ export const loadEntries = createAppAsyncThunk( const state = thunkApi.getState() const endpoint = getEndpoint(arg.source.type) const result = await endpoint(buildGetEntriesPaginatedRequest(state, arg.source, 0)) + if (arg.source.type === "feed") { + thunkApi.dispatch(setHasNewEntries({ feedId: +arg.source.id, value: false })) + } return result.data } ) diff --git a/commafeed-client/src/app/tree/slice.ts b/commafeed-client/src/app/tree/slice.ts index fd863350..4cf942ef 100644 --- a/commafeed-client/src/app/tree/slice.ts +++ b/commafeed-client/src/app/tree/slice.ts @@ -40,6 +40,15 @@ export const treeSlice = createSlice({ } }) }, + setHasNewEntries: (state, action: PayloadAction<{ feedId: number; value: boolean }>) => { + if (!state.rootCategory) return + + visitCategoryTree(state.rootCategory, category => { + category.feeds = category.feeds.map(feed => + feed.id === action.payload.feedId ? { ...feed, hasNewEntries: action.payload.value } : feed + ) + }) + }, }, extraReducers: builder => { builder.addCase(reloadTree.fulfilled, (state, action) => { @@ -65,4 +74,4 @@ export const treeSlice = createSlice({ }, }) -export const { setMobileMenuOpen, toggleSidebar, incrementUnreadCount } = treeSlice.actions +export const { setMobileMenuOpen, toggleSidebar, incrementUnreadCount, setHasNewEntries } = treeSlice.actions diff --git a/commafeed-client/src/app/tree/thunks.ts b/commafeed-client/src/app/tree/thunks.ts index ac0d7a33..22ef4b8d 100644 --- a/commafeed-client/src/app/tree/thunks.ts +++ b/commafeed-client/src/app/tree/thunks.ts @@ -1,7 +1,7 @@ import { createAppAsyncThunk } from "app/async-thunk" import { client } from "app/client" import { redirectToCategory, redirectToFeed } from "app/redirect/thunks" -import { incrementUnreadCount } from "app/tree/slice" +import { incrementUnreadCount, setHasNewEntries } from "app/tree/slice" import type { CollapseRequest, Subscription } from "app/types" import { flattenCategoryTree, visitCategoryTree } from "app/utils" @@ -11,7 +11,6 @@ export const collapseTreeCategory = createAppAsyncThunk( "tree/category/collapse", async (req: CollapseRequest) => await client.category.collapse(req).then(r => r.data) ) - export const selectNextUnreadTreeItem = createAppAsyncThunk( "tree/selectNextUnreadItem", ( @@ -75,6 +74,7 @@ export const newFeedEntriesDiscovered = createAppAsyncThunk( amount, }) ) + thunkApi.dispatch(setHasNewEntries({ feedId, value: true })) } } ) diff --git a/commafeed-client/src/app/types.ts b/commafeed-client/src/app/types.ts index 68a2218d..db57202b 100644 --- a/commafeed-client/src/app/types.ts +++ b/commafeed-client/src/app/types.ts @@ -30,13 +30,17 @@ export interface Subscription { filter?: string } +export interface TreeSubscription extends Subscription { + hasNewEntries?: boolean +} + export interface Category { id: string parentId?: string parentName?: string name: string children: Category[] - feeds: Subscription[] + feeds: TreeSubscription[] expanded: boolean position: number } diff --git a/commafeed-client/src/components/sidebar/Tree.tsx b/commafeed-client/src/components/sidebar/Tree.tsx index ccfa8dca..0d805737 100644 --- a/commafeed-client/src/components/sidebar/Tree.tsx +++ b/commafeed-client/src/components/sidebar/Tree.tsx @@ -11,7 +11,7 @@ import { } from "app/redirect/thunks" import { useAppDispatch, useAppSelector } from "app/store" import { collapseTreeCategory } from "app/tree/thunks" -import type { Category, Subscription } from "app/types" +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" @@ -133,7 +133,7 @@ export function Tree() { ) } - const feedNode = (feed: Subscription, level = 0) => { + const feedNode = (feed: TreeSubscription, level = 0) => { if (!isFeedDisplayed(feed)) return null return ( @@ -148,6 +148,7 @@ export function Tree() { hasError={feed.errorCount > errorThreshold} onClick={feedClicked} key={feed.id} + newMessages={feed.hasNewEntries} /> ) } diff --git a/commafeed-client/src/components/sidebar/TreeNode.tsx b/commafeed-client/src/components/sidebar/TreeNode.tsx index 26d55777..f61b6eb1 100644 --- a/commafeed-client/src/components/sidebar/TreeNode.tsx +++ b/commafeed-client/src/components/sidebar/TreeNode.tsx @@ -15,6 +15,7 @@ interface TreeNodeProps { expanded?: boolean level: number hasError: boolean + newMessages?: boolean onClick: (e: React.MouseEvent, id: string) => void onIconClick?: (e: React.MouseEvent, id: string) => void } @@ -64,12 +65,12 @@ export function TreeNode(props: TreeNodeProps) { hasError: props.hasError, hasUnread: props.unread > 0, }) + return ( props.onClick(e, props.id)} data-id={props.id} data-type={props.type} data-unread-count={props.unread} @@ -80,7 +81,7 @@ export function TreeNode(props: TreeNodeProps) { {props.name} {!props.expanded && ( - + )} diff --git a/commafeed-client/src/components/sidebar/UnreadCount.tsx b/commafeed-client/src/components/sidebar/UnreadCount.tsx index 63e39235..a1e6e154 100644 --- a/commafeed-client/src/components/sidebar/UnreadCount.tsx +++ b/commafeed-client/src/components/sidebar/UnreadCount.tsx @@ -1,26 +1,28 @@ -import { Badge, Tooltip } from "@mantine/core" +import { Badge, Indicator, Tooltip } from "@mantine/core" import { Constants } from "app/constants" import { tss } from "tss" const useStyles = tss.create(() => ({ badge: { width: "3.2rem", - // for some reason, mantine Badge has "cursor: 'default'" cursor: "pointer", }, })) -export function UnreadCount(props: { unreadCount: number }) { +export function UnreadCount(props: { unreadCount: number; newMessages: boolean | undefined }) { const { classes } = useStyles() if (props.unreadCount <= 0) return null const count = props.unreadCount >= 10000 ? "10k+" : props.unreadCount + return ( - - {count} - + + + {count} + + ) }