From 9044073afdbe47400ab73b3b86aa4e4cf79f4866 Mon Sep 17 00:00:00 2001 From: kyuuseiryuu Date: Wed, 11 Mar 2026 11:51:30 +0900 Subject: [PATCH] feat: sync favorite player state with server and improve clear confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `isFav` selector to `useFavPlayerStore` to determine initial button state immediately. - Initialize `FavButton` value based on the store's `isFav` result instead of a stale local state. - In `FavePlayersPage`, integrate Ant Design message hooks for user feedback during server sync. - Show "syncing" loading indicator when starting the sync process. - Show "synced" success notification upon completion. - Enhance the "Clear Local Favorites" confirmation dialog: - Update warning text to indicate the action is irreversible. - Add custom button labels ("清空", "取消"). - Make the confirm button dangerous and add a delete icon for better UX. --- src/components/FavButton.tsx | 4 ++-- src/page/FavPlayersPage.tsx | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/FavButton.tsx b/src/components/FavButton.tsx index ac5bb53..c796fa2 100644 --- a/src/components/FavButton.tsx +++ b/src/components/FavButton.tsx @@ -22,7 +22,7 @@ const StyledContainer = styled.div` export function FavButton(props: Props) { const { isAuthenticated, getIdTokenClaims } = useLogto(); - const { fav, unFav } = useFavPlayerStore(store => store); + const { fav, unFav, isFav } = useFavPlayerStore(store => store); const favReq = useRequest(async () => { if (!isAuthenticated) return; const claims = await getIdTokenClaims(); @@ -33,7 +33,7 @@ export function FavButton(props: Props) { const claims = await getIdTokenClaims(); await fetch(`/api/fav/${claims?.aud}/${props.user?.uid}`, { method: 'DELETE' }); }, { manual: true, refreshDeps: [props, isAuthenticated] }); - const [value, setValue] = useState(0); + const [value, setValue] = useState(isFav(props.user?.uid) ? 1 : 0); useEffect(() => { if (!props.user) return; if (!isAuthenticated) return; diff --git a/src/page/FavPlayersPage.tsx b/src/page/FavPlayersPage.tsx index 9299b09..cfa6ade 100644 --- a/src/page/FavPlayersPage.tsx +++ b/src/page/FavPlayersPage.tsx @@ -1,5 +1,5 @@ -import { Avatar, Button, Card, Divider, Flex, Image, Popconfirm, Radio, Segmented, Spin, Typography } from "antd"; -import { useFavPlayerStore, type FavPlayer } from "../store/useFavPlayerStore"; +import { Avatar, Button, Card, Divider, Flex, Image, message as AntdMessage, Popconfirm, Radio, Segmented, Spin, Typography } from "antd"; +import { useFavPlayerStore } from "../store/useFavPlayerStore"; import { useNavigate } from "react-router"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useLogto, type IdTokenClaims } from "@logto/react"; @@ -19,6 +19,7 @@ enum ShowType { } export function FavePlayersPage() { + const [message, contextHolder] = AntdMessage.useMessage(); const { favMap, unFav } = useFavPlayerStore(state => state); const [sortType, setSortType] = useState(SortType.DEFAULT); const [showType, setShowType] = useState(ShowType.LOCAL); @@ -62,14 +63,17 @@ export function FavePlayersPage() { const jobs = list.map(async u => { await fetch(`/api/fav/${aud}/${u.uid}`, { method: 'PUT' }); }); + message.open({ key: 'sync', content: '同步中...', type: 'loading' }); await Promise.all(jobs); await favListRequest.runAsync(aud!); + message.open({ key: 'sync', content: '已同步', type: 'success' }); }, [isAuthenticated, list]); const handleClearLocal = useCallback(() => { list.forEach(e => unFav(e.uid)); }, []); return (
+ {contextHolder} 收藏的球员 @@ -142,7 +146,13 @@ export function FavePlayersPage() { >登陆后可同步收藏球员 ) } {(showType === ShowType.LOCAL && ( - + }} + > ))}