From 96aa416f53198426a89d6ca8c4802cb43ee7d2c3 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Thu, 22 Aug 2024 11:14:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=A2=98=E7=9B=AE=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=AD=98=E5=88=B0localstorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ChallengePanel.tsx | 29 +++++++++++-------- .../src/components/ScoreboardTable.tsx | 17 +++++------ .../src/pages/games/[id]/Scoreboard.tsx | 7 ++++- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/GZCTF/ClientApp/src/components/ChallengePanel.tsx b/src/GZCTF/ClientApp/src/components/ChallengePanel.tsx index f8cc08cdf..b1ddf584d 100644 --- a/src/GZCTF/ClientApp/src/components/ChallengePanel.tsx +++ b/src/GZCTF/ClientApp/src/components/ChallengePanel.tsx @@ -18,7 +18,7 @@ import { useLocalStorage } from '@mantine/hooks' import { mdiFileUploadOutline, mdiFlagOutline, mdiPuzzle } from '@mdi/js' import { Icon } from '@mdi/react' import dayjs from 'dayjs' -import React, { FC, useState } from 'react' +import React, { FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' import ChallengeCard from '@Components/ChallengeCard' @@ -50,7 +50,11 @@ const ChallengePanel: FC = () => { defaultValue: false, getInitialValueInEffect: false, }) - const [searchText, setSearchText] = useState('') + const [searchText, setSearchText] = useLocalStorage({ + key: 'challenge-search-pattern', + defaultValue: '', + getInitialValueInEffect: true, + }) const [searchPattern, setSearchPattern] = useState(null) const allChallenges = Object.values(challenges ?? {}).flat() @@ -64,8 +68,8 @@ const ChallengePanel: FC = () => { SubmissionType.Unaccepted) )) ?? [] const searchedChallenges = unsolvedTaggedChallenges.filter( - (chal) => !searchPattern || chal.title && searchPattern.test(chal.title) - ) + (chal) => !searchPattern || chal.title && searchPattern.test(chal.title) + ) const currentChallenges = searchedChallenges.length ? searchedChallenges : unsolvedTaggedChallenges const [challenge, setChallenge] = useState(null) @@ -75,6 +79,14 @@ const ChallengePanel: FC = () => { const challengeTagLabelMap = useChallengeTagLabelMap() const { t } = useTranslation() + useEffect(() => { + try { + setSearchPattern(searchText.trim() ? new RegExp(searchText.trim(), 'i') : null) + } catch { + setSearchPattern(null) + } + }, [searchText]) + // skeleton for loading if (!challenges) { return ( @@ -188,14 +200,7 @@ const ChallengePanel: FC = () => { placeholder={t('game.placeholder.challenge_search')} value={searchText ?? ''} error={searchText.trim() !== '' && (!searchPattern || searchedChallenges.length === 0)} - onChange={(e) => { - setSearchText(e.currentTarget.value) - try { - setSearchPattern(e.currentTarget.value.trim() ? new RegExp(e.currentTarget.value.trim(), 'i') : null) - } catch { - setSearchPattern(null) - } - }} + onChange={(e) => setSearchText(e.currentTarget.value)} w="10rem" styles={{ body: { diff --git a/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx b/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx index 3cc9fc32a..de1b68b22 100644 --- a/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx +++ b/src/GZCTF/ClientApp/src/components/ScoreboardTable.tsx @@ -261,7 +261,7 @@ export interface ScoreboardProps { organization: string | null setOrganization: (org: string | null) => void titlePattern: string | null - setTitlePattern: (pattern: string | null) => void + setTitlePattern: (pattern: string | ((prevState: string) => string)) => void category: ChallengeTag | null setCategory: (tag: ChallengeTag | null) => void } @@ -286,12 +286,6 @@ const ScoreboardTable: FC = ({ const [searchTextBuffer, setSearchTextBuffer] = useState('') const [searchCloseButtonVisible, setSearchCloseButtonVisible] = useState(false) const [filterTips, setFilterTips] = useState('') - const onSearch = (searchText: string) => { - setTitlePattern(searchText) - setSearchTextBuffer(searchText) - setSearchCloseButtonVisible(searchText.length > 0) - setPage(1) - } const [updatingBarrier, setUpdatingBarrier] = useState(true) @@ -313,6 +307,9 @@ const ScoreboardTable: FC = ({ } setUpdatingBarrier(false) + setSearchTextBuffer(titlePattern ?? '') + setSearchCloseButtonVisible((titlePattern?.length ?? 0) > 0) + setPage(1) try { const customScoreboard = generateCustomScoreboard( scoreboard, @@ -381,7 +378,7 @@ const ScoreboardTable: FC = ({ onSearch(searchTextBuffer?.trim() ?? '')} + onClick={() => setTitlePattern(searchTextBuffer?.trim() ?? '')} > @@ -391,11 +388,11 @@ const ScoreboardTable: FC = ({ onSearch('')} + onClick={() => setTitlePattern('')} /> } onKeyDown={(e) => - updatingBarrier && e.key === 'Enter' && onSearch(searchTextBuffer?.trim() ?? '') + e.key === 'Enter' && updatingBarrier && setTitlePattern(searchTextBuffer?.trim() ?? '') } value={searchTextBuffer ?? ''} onChange={(e) => { diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/Scoreboard.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/Scoreboard.tsx index a7dd162e4..9f213abea 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/Scoreboard.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/Scoreboard.tsx @@ -10,6 +10,7 @@ import WithNavBar from '@Components/WithNavbar' import { useIsMobile } from '@Utils/ThemeOverride' import { useGameTeamInfo } from '@Utils/useGame' import { ChallengeTag } from '@Api' +import { useLocalStorage } from '@mantine/hooks' const Scoreboard: FC = () => { const { id } = useParams() @@ -17,7 +18,11 @@ const Scoreboard: FC = () => { const { teamInfo, error } = useGameTeamInfo(numId) const [organization, setOrganization] = useState('all') - const [titlePattern, setTitlePattern] = useState(null) + const [titlePattern, setTitlePattern] = useLocalStorage({ + key: 'scoreboard-search-pattern', + defaultValue: '', + getInitialValueInEffect: false, + }) const [category, setCategory] = useState(null) const scoreboardProps: ScoreboardProps = {