From 32a55ece6440f80f837adc6d558029ea5fbd6982 Mon Sep 17 00:00:00 2001 From: Innei Date: Fri, 20 Sep 2024 22:34:09 +0800 Subject: [PATCH] fix(discover): update follow status after add feed, closes #269, closes Signed-off-by: Innei --- apps/renderer/src/modules/discover/form.tsx | 245 ++++++++++++-------- 1 file changed, 154 insertions(+), 91 deletions(-) diff --git a/apps/renderer/src/modules/discover/form.tsx b/apps/renderer/src/modules/discover/form.tsx index 06a519bb74..cc2d17db55 100644 --- a/apps/renderer/src/modules/discover/form.tsx +++ b/apps/renderer/src/modules/discover/form.tsx @@ -1,6 +1,10 @@ import { zodResolver } from "@hookform/resolvers/zod" import { useMutation } from "@tanstack/react-query" -import { useEffect } from "react" +import { useSingleton } from "foxact/use-singleton" +import { produce } from "immer" +import { atom, useAtomValue, useStore } from "jotai" +import type { FC } from "react" +import { memo, useCallback, useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import { z } from "zod" @@ -55,6 +59,7 @@ const info: Record< }, } +type DiscoverSearchData = Awaited>["data"] export function DiscoverForm({ type }: { type: string }) { const { prefix, default: defaultValue } = info[type] const form = useForm>({ @@ -64,6 +69,8 @@ export function DiscoverForm({ type }: { type: string }) { }, }) const { t } = useTranslation() + + const jotaiStore = useStore() const mutation = useMutation({ mutationFn: async (keyword: string) => { const { data } = await apiClient.discover.$post({ @@ -72,9 +79,14 @@ export function DiscoverForm({ type }: { type: string }) { }, }) + jotaiStore.set(discoverSearchDataAtom, data) + return data }, }) + const discoverSearchDataAtom = useSingleton(() => atom()).current + + const discoverSearchData = useAtomValue(discoverSearchDataAtom) const { present, dismissAll } = useModalStack() @@ -120,6 +132,41 @@ export function DiscoverForm({ type }: { type: string }) { form.setValue("keyword", trimmedKeyword) }, [form, keyword, prefix]) + const handleSuccess = useCallback( + (item: DiscoverSearchData[number]) => { + const currentData = jotaiStore.get(discoverSearchDataAtom) + if (!currentData) return + jotaiStore.set( + discoverSearchDataAtom, + produce(currentData, (draft) => { + const sub = draft.find((i) => i.feed.id === item.feed.id) + if (!sub) return + sub.isSubscribed = true + sub.subscriptionCount = -~(sub.subscriptionCount as number) + }), + ) + }, + [discoverSearchDataAtom, jotaiStore], + ) + + const handleUnSubscribed = useCallback( + (item: DiscoverSearchData[number]) => { + const currentData = jotaiStore.get(discoverSearchDataAtom) + if (!currentData) return + jotaiStore.set( + discoverSearchDataAtom, + produce(currentData, (draft) => { + const sub = draft.find((i) => i.feed.id === item.feed.id) + if (!sub) return + sub.isSubscribed = false + sub.subscriptionCount = Number.isNaN(sub.subscriptionCount) + ? 0 + : (sub.subscriptionCount as number) - 1 + }), + ) + }, + [discoverSearchDataAtom, jotaiStore], + ) return ( <>
@@ -151,96 +198,13 @@ export function DiscoverForm({ type }: { type: string }) { {mutation.data?.length > 1 && "s"}
- {mutation.data.map((item) => ( - - - - - {item.docs ? ( - - - - - - ) : ( - <> - - {!!item.entries?.length && ( -
- {item.entries - .filter((e) => !!e) - .map((entry) => { - const assertEntry = entry - return ( - - {assertEntry.media?.[0] ? ( - - ) : ( -
- {assertEntry.title} -
- )} -
- {assertEntry.title} -
-
- ) - })} -
- )} -
- - {item.isSubscribed ? ( - - ) : ( - - )} -
- - {item.subscriptionCount} - {" "} - Followers -
-
- - )} -
+ {discoverSearchData?.map((item) => ( + ))}
@@ -248,3 +212,102 @@ export function DiscoverForm({ type }: { type: string }) { ) } + +const SearchCard: FC<{ + item: DiscoverSearchData[number] + onSuccess: (item: DiscoverSearchData[number]) => void + onUnSubscribed?: (item: DiscoverSearchData[number]) => void +}> = memo(({ item, onSuccess }) => { + const { present } = useModalStack() + + return ( + + + + + {item.docs ? ( + + + + + + ) : ( + <> + + {!!item.entries?.length && ( +
+ {item.entries + .filter((e) => !!e) + .map((entry) => { + const assertEntry = entry + return ( + + {assertEntry.media?.[0] ? ( + + ) : ( +
+ {assertEntry.title} +
+ )} +
+ {assertEntry.title} +
+
+ ) + })} +
+ )} +
+ + {item.isSubscribed ? ( + + ) : ( + + )} +
+ + {item.subscriptionCount} + {" "} + Followers +
+
+ + )} +
+ ) +})