From 68e0bd6f15f828a2e23ae637ea3a05b4b54efa6f Mon Sep 17 00:00:00 2001 From: jong-hui Date: Sun, 12 Mar 2023 04:06:29 +0900 Subject: [PATCH] =?UTF-8?q?:sparkles:=20feat:=20=EC=B1=94=ED=94=BC?= =?UTF-8?q?=EC=96=B8=20=EA=B2=80=EC=83=89=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + src/features/tier/TierTable/TierTable.tsx | 49 +++++++++++++++++++---- src/features/tier/TierTable/styled.ts | 13 ++++++ src/repositories/tier/types.ts | 23 +++++++++++ src/repositories/tier/useLaneTiers.ts | 14 +++++++ src/repositories/tier/useTiers.ts | 21 ++++++++++ src/types/lane.ts | 7 ++++ src/utils/champion.ts | 15 +++++++ yarn.lock | 10 +++++ 9 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/repositories/tier/types.ts create mode 100644 src/repositories/tier/useLaneTiers.ts create mode 100644 src/repositories/tier/useTiers.ts create mode 100644 src/types/lane.ts create mode 100644 src/utils/champion.ts diff --git a/package.json b/package.json index 5bfb3f1..0a737e9 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react-router-dom": "^6.6.2", "react-virtualized": "git+https://git@github.com/remorses/react-virtualized-fixed-import.git#9.22.3", "recoil": "^0.7.6", + "string-similarity": "^4.0.4", "styled-components": "^5.3.6", "swr": "^2.0.0", "vite-electron-plugin": "^0.8.2" @@ -50,6 +51,7 @@ "@types/node": "^18.11.18", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.10", + "@types/string-similarity": "^4.0.0", "@types/styled-components": "^5.1.26", "@vitejs/plugin-react": "^3.0.1", "cross-env": "^7.0.3", diff --git a/src/features/tier/TierTable/TierTable.tsx b/src/features/tier/TierTable/TierTable.tsx index a44a3f8..211f8e9 100644 --- a/src/features/tier/TierTable/TierTable.tsx +++ b/src/features/tier/TierTable/TierTable.tsx @@ -1,15 +1,20 @@ +import { useState } from 'react'; import { Controller } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { Table, Tooltip } from 'antd'; +import Search from 'antd/es/input/Search'; import clsx from 'clsx'; import dayjs from 'dayjs'; +import { uniqBy } from 'lodash'; import RankingVariation from '~/components/RankingVariation'; import ChampionProfileSmall from '~/features/asset/ChampionProfileSmall'; import LaneSelect from '~/features/lane/LaneSelect'; -import useAPI from '~/hooks/useAPI'; import { useCustomForm } from '~/hooks/useCustomForm'; +import { useLaneTiers } from '~/repositories/tier/useLaneTiers'; +import { useTiers } from '~/repositories/tier/useTiers'; +import { compareChampionName, isEqualChampionName } from '~/utils/champion'; import { TierTableStyled } from './styled'; @@ -29,12 +34,22 @@ const TierTable = ({ className }: TierTableProps) => { const lane = form.watch('lane'); - const { data = [], isLoading } = useAPI('ps', `/tiers/${lane}`, { - dedupingInterval: 1000 * 60 * 5, - }); + const { data, isLoading } = useLaneTiers(lane); + const { data: tiers } = useTiers(); + + const [inputtedChampionName, setInputtedChampionName] = useState(''); + + const searchedTiers = uniqBy( + tiers + .filter(tier => isEqualChampionName(tier.championInfo.nameKr, inputtedChampionName)) + .sort(tier => compareChampionName(tier.championInfo.nameKr, inputtedChampionName)), + tier => tier.championId, + ); const updatedAt = data[0]?.updatedAt; + const viewingData = inputtedChampionName === '' ? data : searchedTiers; + return (
@@ -55,7 +70,27 @@ const TierTable = ({ className }: TierTableProps) => { } + render={({ field }) => ( +
+ +
+ { + setInputtedChampionName(e.target.value); + }} + onSearch={_ => { + const highScoreTier = searchedTiers[0]; + + if (highScoreTier === undefined) { + return; + } + + navigate(`/champ/${highScoreTier.championId}`); + }} + /> +
+
+ )} />
@@ -160,8 +195,8 @@ const TierTable = ({ className }: TierTableProps) => { width: 100, }, ]} - dataSource={data} - rowKey={record => record.ranking} + dataSource={viewingData} + rowKey={record => String(record.championId + record.laneId + record.championInfo.nameKr)} loading={isLoading} pagination={false} scroll={{ y: 600 }} diff --git a/src/features/tier/TierTable/styled.ts b/src/features/tier/TierTable/styled.ts index 81630bd..02d24c2 100644 --- a/src/features/tier/TierTable/styled.ts +++ b/src/features/tier/TierTable/styled.ts @@ -74,4 +74,17 @@ export const TierTableStyled = styled.div` } } } + + .lane-selection { + display: flex; + justify-content: space-between; + align-items: center; + } + + .champion-search { + max-width: 400px; + } + .champion-search .ant-input { + padding: 4px 12px; + } `; diff --git a/src/repositories/tier/types.ts b/src/repositories/tier/types.ts new file mode 100644 index 0000000..694c59a --- /dev/null +++ b/src/repositories/tier/types.ts @@ -0,0 +1,23 @@ +export interface ChampionStats { + count: number; + pickRate: number; + banRate: number; + winRate: number; + opScore: number; + opTier: number; + isHoney: boolean; + isOp: boolean; + ranking: number; + rankingVariation: number; + updatedAt: string; + championId: number; + laneId: number; + honeyScore: number; + overallRanking: number; + overallRankingVariation: number; + championInfo: { + nameKr: string; + nameUs: string; + nameCn: string; + }; +} diff --git a/src/repositories/tier/useLaneTiers.ts b/src/repositories/tier/useLaneTiers.ts new file mode 100644 index 0000000..50d7910 --- /dev/null +++ b/src/repositories/tier/useLaneTiers.ts @@ -0,0 +1,14 @@ +import useAPI from '~/hooks/useAPI'; + +import { ChampionStats } from './types'; + +export const useLaneTiers = (lane: number) => { + const { data = [], isLoading } = useAPI('ps', `/tiers/${lane}`, { + dedupingInterval: 1000 * 60 * 5, + }); + + return { + data, + isLoading, + }; +}; diff --git a/src/repositories/tier/useTiers.ts b/src/repositories/tier/useTiers.ts new file mode 100644 index 0000000..af628cc --- /dev/null +++ b/src/repositories/tier/useTiers.ts @@ -0,0 +1,21 @@ +import { LANE } from '~/types/lane'; + +import { useLaneTiers } from './useLaneTiers'; + +export const useTiers = () => { + const { data: topLaneTiers } = useLaneTiers(LANE.TOP); + const { data: jungleLaneTiers } = useLaneTiers(LANE.JUNGLE); + const { data: midLaneTiers } = useLaneTiers(LANE.MID); + const { data: ADLaneTiers } = useLaneTiers(LANE.ADC); + const { data: supporterLaneTiers } = useLaneTiers(LANE.SUPPORT); + + const allLaneTiers = [ + ...topLaneTiers, + ...jungleLaneTiers, + ...midLaneTiers, + ...ADLaneTiers, + ...supporterLaneTiers, + ]; + + return { data: allLaneTiers }; +}; diff --git a/src/types/lane.ts b/src/types/lane.ts new file mode 100644 index 0000000..37b3a1e --- /dev/null +++ b/src/types/lane.ts @@ -0,0 +1,7 @@ +export enum LANE { + TOP = 0, + JUNGLE = 1, + MID = 2, + ADC = 3, + SUPPORT = 4, +} diff --git a/src/utils/champion.ts b/src/utils/champion.ts new file mode 100644 index 0000000..130902f --- /dev/null +++ b/src/utils/champion.ts @@ -0,0 +1,15 @@ +import { compareTwoStrings } from 'string-similarity'; + +// TODO: 초성검색 +export const isEqualChampionName = (target: string, reference: string) => { + return target.toLowerCase().includes(reference.toLowerCase()); +}; + +// TODO: 한글 +const THRESHOLD = 0.8; +export const compareChampionName = (a: string, b: string, threshold = THRESHOLD) => { + if (a === b) { + return 0; + } + return compareTwoStrings(a, b) > threshold ? 1 : -1; +}; diff --git a/yarn.lock b/yarn.lock index e77400f..8d8af86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -866,6 +866,11 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/string-similarity@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/string-similarity/-/string-similarity-4.0.0.tgz#8cc03d5d1baad2b74530fe6c7d849d5768d391ad" + integrity sha512-dMS4S07fbtY1AILG/RhuwmptmzK1Ql8scmAebOTJ/8iBtK/KI17NwGwKzu1uipjj8Kk+3mfPxum56kKZE93mzQ== + "@types/styled-components@^5.1.26": version "5.1.26" resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.26.tgz#5627e6812ee96d755028a98dae61d28e57c233af" @@ -4563,6 +4568,11 @@ string-convert@^0.2.0: resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== +string-similarity@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" + integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"