diff --git a/dockerfile b/dockerfile index 2129945..d96a670 100644 --- a/dockerfile +++ b/dockerfile @@ -1,6 +1,6 @@ FROM oven/bun:latest COPY . /app WORKDIR /app -RUN bun install +RUN bun install && bunx --bun prisma generate ENTRYPOINT [ "bun", "start"] EXPOSE 3000 diff --git a/src/components/FavButton.tsx b/src/components/FavButton.tsx index 31c2372..ac5bb53 100644 --- a/src/components/FavButton.tsx +++ b/src/components/FavButton.tsx @@ -22,6 +22,7 @@ const StyledContainer = styled.div` export function FavButton(props: Props) { const { isAuthenticated, getIdTokenClaims } = useLogto(); + const { fav, unFav } = useFavPlayerStore(store => store); const favReq = useRequest(async () => { if (!isAuthenticated) return; const claims = await getIdTokenClaims(); @@ -48,10 +49,12 @@ export function FavButton(props: Props) { if (!props.user) return; setValue(value); if (value) { + fav(props.user); favReq.run(); setValue(1); } else { unFavReq.run(); + unFav(props.user.uid); setValue(0); } }, []); diff --git a/src/page/FavPlayersPage.tsx b/src/page/FavPlayersPage.tsx index ce489ea..7bafead 100644 --- a/src/page/FavPlayersPage.tsx +++ b/src/page/FavPlayersPage.tsx @@ -1,9 +1,9 @@ -import { Avatar, Button, Card, Divider, Flex, Image, Segmented, Spin, Typography } from "antd"; +import { Avatar, Button, Card, Divider, Flex, Image, 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 } from "@logto/react"; -import { LoginOutlined, SyncOutlined, UploadOutlined } from "@ant-design/icons"; +import { DeleteOutlined, LoginOutlined, UploadOutlined } from "@ant-design/icons"; import { useRequest } from "ahooks"; import type { XCXProfile } from "../types"; @@ -18,7 +18,7 @@ enum ShowType { } export function FavePlayersPage() { - const { favMap } = useFavPlayerStore(state => state); + const { favMap, unFav } = useFavPlayerStore(state => state); const [sortType, setSortType] = useState(SortType.DEFAULT); const list = useMemo(() => { const l = Object.values(favMap); @@ -30,7 +30,7 @@ export function FavePlayersPage() { } }, [favMap, sortType]); const navigate = useNavigate(); - const { isAuthenticated, getIdTokenClaims, signIn } = useLogto(); + const { isAuthenticated, getIdTokenClaims } = useLogto(); const favListRequest = useRequest(async (aud: string) => { const res = await fetch(`/api/fav/${aud}`); const data = await res.json(); @@ -55,6 +55,12 @@ export function FavePlayersPage() { await favListRequest.runAsync(aud!); }, [isAuthenticated, list]); const [showType, setShowType] = useState(ShowType.LOCAL); + const handleClearLocal = useCallback(() => { + list.forEach(e => unFav(e.uid)); + }, []); + useEffect(() => { + setShowType(isAuthenticated ? ShowType.ACCOUNT : ShowType.LOCAL); + }, [isAuthenticated]); const showList = useMemo(() => { if (showType === ShowType.LOCAL) { return list; @@ -71,13 +77,13 @@ export function FavePlayersPage() { 收藏的球员
- setShowType(e.target.value)} options={[ - ShowType.LOCAL, - ShowType.ACCOUNT, + { label: `${ShowType.LOCAL}(${list.length})`, value: ShowType.LOCAL}, + { label: `${ShowType.ACCOUNT}(${favListRequest.data?.length ?? 0})`, value: ShowType.ACCOUNT} ]} />
@@ -125,18 +131,25 @@ export function FavePlayersPage() { ))}
-
- { (showType === ShowType.LOCAL && isAuthenticated && list.length > 0) && } + + { (showType === ShowType.LOCAL && isAuthenticated && list.length > 0) && ( + + ) } { (showType === ShowType.LOCAL && !isAuthenticated && list.length > 0) && ( ) } -
+ {(showType === ShowType.LOCAL && ( + + + + ))} + )} diff --git a/src/page/UserCenter.tsx b/src/page/UserCenter.tsx index 75e8d8e..d15d8b6 100644 --- a/src/page/UserCenter.tsx +++ b/src/page/UserCenter.tsx @@ -2,7 +2,7 @@ import { EditOutlined, FileTextOutlined, HomeOutlined, KeyOutlined, LockOutlined import { useLogto, type IdTokenClaims } from "@logto/react"; import { Avatar, Button, Divider, Flex, Modal, Typography } from "antd"; import { useCallback, useEffect, useState } from "react"; -import { useNavigate } from "react-router"; +import { useLocation, useNavigate } from "react-router"; enum modifyRoutes { username = '/account/username', @@ -20,6 +20,18 @@ export const UserCenter = () => { const { signIn, isAuthenticated, signOut, getIdTokenClaims } = useLogto(); const [user, setUser] = useState(); const navigate = useNavigate(); + const location = useLocation(); + const handleSignIn = useCallback(() => { + const redirect = `${window.location.origin}/auth/callback`; + signIn(redirect); + }, []); + useEffect(() => { + if (isAuthenticated) return; + const autoSignIn = new URLSearchParams(location.search).get('autoSignIn'); + if (autoSignIn) { + handleSignIn(); + } + }, [isAuthenticated]); useEffect(() => { if (!isAuthenticated) return; getIdTokenClaims().then(claims => setUser(claims)); @@ -35,10 +47,7 @@ export const UserCenter = () => { type="primary" icon={} size="large" - onClick={() => { - const redirect = `${window.location.origin}/auth/callback`; - signIn(redirect); - }} + onClick={handleSignIn} > 登录