feat: seprate listIds and inboxIds with feedIds in subscription store
This commit is contained in:
parent
b7fce0e640
commit
5f2cf8f20e
|
|
@ -11,18 +11,10 @@ export const TimelineTabs = () => {
|
|||
const { view, listId, inboxId, folderName } = routerParams
|
||||
|
||||
const listsData = useSubscriptionStore(
|
||||
useCallback(
|
||||
(state) =>
|
||||
state.feedIdByView[view].map((id) => state.data[id]).filter((s) => s && "listId" in s),
|
||||
[view],
|
||||
),
|
||||
useCallback((state) => Array.from(state.listIds).map((id) => state.data[id]), []),
|
||||
)
|
||||
const inboxData = useSubscriptionStore(
|
||||
useCallback(
|
||||
(state) =>
|
||||
state.feedIdByView[view].map((id) => state.data[id]).filter((s) => s && "inboxId" in s),
|
||||
[view],
|
||||
),
|
||||
useCallback((state) => Array.from(state.inboxIds).map((id) => state.data[id]), []),
|
||||
)
|
||||
const categoriesData = useSubscriptionStore(
|
||||
useCallback(
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
useInboxesGroupedData,
|
||||
useListsGroupedData,
|
||||
} from "./list.shared"
|
||||
import { SortableFeedList, SortByAlphabeticalInbox, SortByAlphabeticalList } from "./sort-by"
|
||||
import { SortableFeedList } from "./sort-by"
|
||||
|
||||
const FeedListImpl = forwardRef<HTMLDivElement, { className?: string; view: number }>(
|
||||
({ className, view }, ref) => {
|
||||
|
|
@ -214,23 +214,6 @@ const FeedListImpl = forwardRef<HTMLDivElement, { className?: string; view: numb
|
|||
rootClassName={cn("h-full", shouldFreeUpSpace && "overflow-visible")}
|
||||
>
|
||||
<StarredItem view={view} />
|
||||
{hasListData && (
|
||||
<>
|
||||
<div className="mt-1 flex h-6 w-full shrink-0 items-center rounded-md px-2.5 text-xs font-semibold text-theme-vibrancyFg transition-colors">
|
||||
{t("words.lists")}
|
||||
</div>
|
||||
<SortByAlphabeticalList view={view} data={listsData} />
|
||||
</>
|
||||
)}
|
||||
{hasInboxData && (
|
||||
<>
|
||||
<div className="mt-1 flex h-6 w-full shrink-0 items-center rounded-md px-2.5 text-xs font-semibold text-theme-vibrancyFg transition-colors">
|
||||
{t("words.inbox")}
|
||||
</div>
|
||||
<SortByAlphabeticalInbox view={view} data={inboxesData} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<DraggableContext.Provider value={draggableContextValue}>
|
||||
<div className="space-y-px" id="feeds-area" ref={setNodeRef}>
|
||||
{(hasListData || hasInboxData) && (
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import {
|
|||
subscriptionCategoryExistSelector,
|
||||
subscriptionsByFeedIsdSelector,
|
||||
} from "./selector"
|
||||
import type { SubscriptionFlatModel } from "./store"
|
||||
import { useSubscriptionStore } from "./store"
|
||||
|
||||
type FeedId = string
|
||||
|
|
@ -88,13 +87,14 @@ export const useAllFeeds = () => {
|
|||
(store) => {
|
||||
const feedInfo = [] as { title: string; id: string }[]
|
||||
|
||||
const allSubscriptions = Object.values(store.feedIdByView).flat()
|
||||
const allSubscriptions = Object.values(store.data).filter(
|
||||
(subscription) => !subscription.listId && !subscription.inboxId,
|
||||
)
|
||||
|
||||
for (const feedId of allSubscriptions) {
|
||||
const subscription = store.data[feedId]!
|
||||
const feed = feedTitleMap[feedId]
|
||||
for (const subscription of allSubscriptions) {
|
||||
const feed = feedTitleMap[subscription.feedId]
|
||||
if (feed) {
|
||||
feedInfo.push({ title: subscription.title || feed || "", id: feedId })
|
||||
feedInfo.push({ title: subscription.title || feed || "", id: subscription.feedId })
|
||||
}
|
||||
}
|
||||
return feedInfo
|
||||
|
|
@ -106,36 +106,18 @@ export const useAllFeeds = () => {
|
|||
|
||||
export const useAllLists = () => {
|
||||
return useSubscriptionStore(
|
||||
useCallback((store) => {
|
||||
const lists = [] as SubscriptionFlatModel[]
|
||||
|
||||
const allSubscriptions = Object.values(store.feedIdByView).flat()
|
||||
|
||||
for (const feedId of allSubscriptions) {
|
||||
const subscription = store.data[feedId]!
|
||||
if (subscription.listId) {
|
||||
lists.push(subscription)
|
||||
}
|
||||
}
|
||||
return lists
|
||||
}, []),
|
||||
useCallback(
|
||||
(store) => Object.values(store.data).filter((subscription) => subscription.listId),
|
||||
[],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
export const useAllInboxes = () => {
|
||||
return useSubscriptionStore(
|
||||
useCallback((store) => {
|
||||
const inboxes = [] as SubscriptionFlatModel[]
|
||||
|
||||
const allSubscriptions = Object.values(store.feedIdByView).flat()
|
||||
|
||||
for (const feedId of allSubscriptions) {
|
||||
const subscription = store.data[feedId]!
|
||||
if (subscription.inboxId) {
|
||||
inboxes.push(subscription)
|
||||
}
|
||||
}
|
||||
return inboxes
|
||||
}, []),
|
||||
useCallback(
|
||||
(store) => Object.values(store.data).filter((subscription) => subscription.inboxId),
|
||||
[],
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { FeedViewType } from "@follow/constants"
|
||||
import type { FeedViewType } from "@follow/constants"
|
||||
|
||||
import { FEED_COLLECTION_LIST, ROUTE_FEED_IN_FOLDER } from "~/constants"
|
||||
|
||||
|
|
@ -10,10 +10,7 @@ export const subscriptionCategoryExistSelector = (name: string) => (state: State
|
|||
state.categories.has(name)
|
||||
|
||||
export const feedSubscriptionCountSelector = (state: State) =>
|
||||
Object.values(state.data).filter(
|
||||
// FIXME: Backend data compatibility
|
||||
(s) => !!s.feedId && !s.listId && !s.inboxId && state.subscriptionIdSet.has(s.feedId),
|
||||
).length
|
||||
state.listIds.size + state.inboxIds.size + Object.values(state.feedIdByView).flat().length
|
||||
|
||||
export const feedIdByViewSelector = (view: FeedViewType) => (state: State) =>
|
||||
state.feedIdByView[view]
|
||||
|
|
@ -54,11 +51,6 @@ export const folderFeedsByFeedIdSelector =
|
|||
return feedIds
|
||||
}
|
||||
|
||||
export const listSubscriptionCountSelector = (state: State) =>
|
||||
Object.values(state.data).filter((s) => !!s.listId && state.subscriptionIdSet.has(s.listId))
|
||||
.length
|
||||
export const listSubscriptionCountSelector = (state: State) => state.listIds.size
|
||||
|
||||
export const inboxSubscriptionCountSelector = (state: State) =>
|
||||
Object.values(state.data).filter(
|
||||
(s) => !!s.inboxId && state.feedIdByView[FeedViewType.Articles].includes(s.inboxId),
|
||||
).length
|
||||
export const inboxSubscriptionCountSelector = (state: State) => state.inboxIds.size
|
||||
|
|
|
|||
|
|
@ -52,9 +52,13 @@ interface SubscriptionState {
|
|||
*/
|
||||
categories: Set<string>
|
||||
/**
|
||||
* All subscription ids set
|
||||
* All list ids set
|
||||
*/
|
||||
subscriptionIdSet: Set<string>
|
||||
listIds: Set<string>
|
||||
/**
|
||||
* All inbox ids set
|
||||
*/
|
||||
inboxIds: Set<string>
|
||||
}
|
||||
|
||||
function morphResponseData(data: SubscriptionModel[]): SubscriptionFlatModel[] {
|
||||
|
|
@ -102,7 +106,8 @@ export const useSubscriptionStore = createZustandStore<SubscriptionState>("subsc
|
|||
feedIdByView: { ...emptyDataIdByView },
|
||||
categoryOpenStateByView: { ...emptyCategoryOpenStateByView },
|
||||
categories: new Set(),
|
||||
subscriptionIdSet: new Set(),
|
||||
listIds: new Set(),
|
||||
inboxIds: new Set(),
|
||||
}))
|
||||
|
||||
const set = useSubscriptionStore.setState
|
||||
|
|
@ -118,18 +123,6 @@ class SubscriptionActions {
|
|||
constructor() {
|
||||
if (subscribeOnce) return
|
||||
subscribeOnce = true
|
||||
// autorun
|
||||
useSubscriptionStore.subscribe((next, prev) => {
|
||||
if (next.feedIdByView !== prev.feedIdByView) {
|
||||
const allSubscriptionIds = Object.values(next.feedIdByView).flat()
|
||||
set((state) => {
|
||||
return {
|
||||
...state,
|
||||
subscriptionIdSet: new Set(allSubscriptionIds),
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
useSubscriptionStore.subscribe((state, prev) => {
|
||||
if (state.data === prev.data) return
|
||||
|
|
@ -199,12 +192,18 @@ class SubscriptionActions {
|
|||
})
|
||||
immerSet((state) => {
|
||||
subscriptions.forEach((subscription) => {
|
||||
if (subscription.listId) {
|
||||
state.listIds.add(subscription.listId)
|
||||
} else if (subscription.inboxId) {
|
||||
state.inboxIds.add(subscription.inboxId)
|
||||
} else {
|
||||
state.feedIdByView[subscription.view].push(subscription.feedId)
|
||||
}
|
||||
state.data[subscription.feedId] = omit(subscription, [
|
||||
"feeds",
|
||||
"lists",
|
||||
"inboxes",
|
||||
]) as SubscriptionFlatModel
|
||||
state.feedIdByView[subscription.view].push(subscription.feedId)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -398,6 +397,7 @@ class SubscriptionActions {
|
|||
await tx.run()
|
||||
}
|
||||
|
||||
// TODO
|
||||
async unfollow(feedIds: string[]) {
|
||||
// const feed = getFeedById(feedId)
|
||||
const feeds = feedIds.map((feedId) => getFeedById(feedId))
|
||||
|
|
@ -422,15 +422,21 @@ class SubscriptionActions {
|
|||
|
||||
delete draft.data[feedId]
|
||||
|
||||
for (const view in draft.feedIdByView) {
|
||||
const currentViewFeedIds = draft.feedIdByView[view] as string[]
|
||||
if (subscription.listId) {
|
||||
draft.listIds.delete(subscription.listId)
|
||||
} else if (subscription.inboxId) {
|
||||
draft.inboxIds.delete(subscription.inboxId)
|
||||
} else {
|
||||
for (const view in draft.feedIdByView) {
|
||||
const currentViewFeedIds = draft.feedIdByView[view] as string[]
|
||||
|
||||
const idx = currentViewFeedIds.indexOf(feedId)
|
||||
const idx = currentViewFeedIds.indexOf(feedId)
|
||||
|
||||
if (idx !== -1) {
|
||||
currentViewFeedIds.splice(idx, 1)
|
||||
ctx.viewDeleted[feedId] = ctx.viewDeleted[feedId] || []
|
||||
ctx.viewDeleted[feedId].push(Number.parseInt(view))
|
||||
if (idx !== -1) {
|
||||
currentViewFeedIds.splice(idx, 1)
|
||||
ctx.viewDeleted[feedId] = ctx.viewDeleted[feedId] || []
|
||||
ctx.viewDeleted[feedId].push(Number.parseInt(view))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue