From ae7f7f7a708340c77db78983a74961e3e007bba0 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Wed, 5 Jul 2023 22:19:34 -0400 Subject: [PATCH 01/13] first stab at tabling the issue --- frontend2/src/components/BattlecodeTable.tsx | 69 +++++++++++ .../BattlecodeTableBottomElement.tsx | 110 ++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 frontend2/src/components/BattlecodeTable.tsx create mode 100644 frontend2/src/components/BattlecodeTableBottomElement.tsx diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx new file mode 100644 index 000000000..9a77699bd --- /dev/null +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -0,0 +1,69 @@ +import React from "react"; + +interface Column { + header: React.ReactNode; + value: (data: T) => React.ReactNode; +} + +interface TableProps { + data: T[]; + columns: Column[]; + onRowClick?: (data: T) => void; + bottomElement?: JSX.Element; +} + +/* + * Generic function prop types don't work with React.FC. + * For more, see https://stackoverflow.com/questions/68757395/how-to-make-a-functional-react-component-with-generic-type + */ +function BattlecodeTable({ + data, + columns, + onRowClick, + bottomElement, +}: TableProps) { + return ( +
+ + + + {columns.map((col, idx) => ( + + ))} + + + + {data.map((row, idx) => ( + { + ev.stopPropagation(); + onRowClick?.(row); + }} + className={ + idx % 2 === 0 + ? "bg-white border-b dark:bg-gray-900 dark:border-gray-700" + : "bg-gray-50 border-b dark:bg-gray-800 dark:border-gray-700" + } + > + {columns.map((col, idx) => ( + + ))} + + ))} + +
+ {col.header} +
+ {col.value(row)} +
+ {bottomElement} +
+ ); +} + +export default BattlecodeTable; diff --git a/frontend2/src/components/BattlecodeTableBottomElement.tsx b/frontend2/src/components/BattlecodeTableBottomElement.tsx new file mode 100644 index 000000000..b6558a55a --- /dev/null +++ b/frontend2/src/components/BattlecodeTableBottomElement.tsx @@ -0,0 +1,110 @@ +import React, { useMemo } from "react"; + +interface TableBottomProps { + totalCount: number; + pageSize: number; + currentPage: number; + onPage: (page: number) => void; +} + +const BattlecodeTableBottomElement: React.FC = ({ + totalCount, + pageSize, + currentPage, + onPage, +}) => { + const first = (currentPage - 1) * pageSize + 1; + const last = Math.min(currentPage * pageSize, totalCount); + const pageCount = Math.ceil(totalCount / pageSize); + + const backDisabled = currentPage <= 1; + const forwardDisabled = currentPage >= pageCount; + + return ( + + ); +}; + +export default BattlecodeTableBottomElement; From 1a848ad4ba5a53787b8c84e5cc74f2ba9f76ea89 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Wed, 5 Jul 2023 22:54:32 -0400 Subject: [PATCH 02/13] added rankings page --- frontend2/src/App.tsx | 4 +- frontend2/src/views/Rankings.tsx | 71 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 frontend2/src/views/Rankings.tsx diff --git a/frontend2/src/App.tsx b/frontend2/src/App.tsx index 3563aeec1..cbdbf57f5 100644 --- a/frontend2/src/App.tsx +++ b/frontend2/src/App.tsx @@ -16,6 +16,7 @@ import { } from "react-router-dom"; import { DEFAULT_EPISODE } from "./utils/constants"; import NotFound from "./views/NotFound"; +import Rankings from "./views/Rankings"; const App: React.FC = () => { const [episodeId, setEpisodeId] = useState(DEFAULT_EPISODE); @@ -38,10 +39,11 @@ const router = createBrowserRouter([ element: , children: [ // Pages that should always be visible - // TODO: /:episodeId/resources, /:episodeId/tournaments, /:episodeId/rankings, /:episodeId/queue + // TODO: /:episodeId/resources, /:episodeId/tournaments, /:episodeId/queue { path: "/:episodeId/home", element: }, { path: "/:episodeId/quickstart", element: }, { path: "/:episodeId/*", element: }, + { path: "/:episodeId/rankings", element: }, // Pages that should only be visible when logged in // TODO: /:episodeId/team, /:episodeId/submissions, /:episodeId/scrimmaging { path: "/account", element: }, diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx new file mode 100644 index 000000000..57d1b6dcb --- /dev/null +++ b/frontend2/src/views/Rankings.tsx @@ -0,0 +1,71 @@ +import { useContext, useEffect, useState } from "react"; +import { EpisodeContext } from "../contexts/EpisodeContext"; +import { Api } from "../utils/api"; +import BattlecodeTable from "../components/BattlecodeTable"; +import { PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList"; +import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement"; + +const Rankings: React.FC = () => { + const episodeId = useContext(EpisodeContext); + + const [page, setPage] = useState(1); + const [searchQuery, setSearchQuery] = useState(""); + const [requireActiveSubmission, setRequireActiveSubmission] = + useState(false); + + const [data, setData] = useState( + undefined + ); + + const queryVars = { + episodeId: episodeId.episodeId, + searchQuery: searchQuery, + requireActiveSubmission: false, + page: page, + }; + + useEffect(() => { + Api.searchTeams( + queryVars.episodeId, + queryVars.searchQuery, + queryVars.requireActiveSubmission, + queryVars.page + ).then((res) => setData(res)); + }, [queryVars]); + + if (!data) { + return <>Loading...; + } + + return ( + <> +

+ Rankings +

+
+ setPage(page)} + /> + } + columns={[ + { + header: "Rating", + value: (team) => team.profile?.rating ?? 0, + }, + { + header: "Team", + value: (team) => team.name, + }, + ]} + /> + + ); +}; + +export default Rankings; From 24d48b9c04f9a0b54be2c186e7a4859223589bc1 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Thu, 6 Jul 2023 20:28:07 -0400 Subject: [PATCH 03/13] better pagination --- frontend2/src/components/BattlecodeTable.tsx | 26 ++-- .../BattlecodeTableBottomElement.tsx | 89 +++++++------- frontend2/src/views/Rankings.tsx | 112 +++++++++++++----- 3 files changed, 143 insertions(+), 84 deletions(-) diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx index 9a77699bd..15e0e950a 100644 --- a/frontend2/src/components/BattlecodeTable.tsx +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React from "react" interface Column { header: React.ReactNode; @@ -7,7 +7,7 @@ interface Column { interface TableProps { data: T[]; - columns: Column[]; + columns: Array>; onRowClick?: (data: T) => void; bottomElement?: JSX.Element; } @@ -23,9 +23,9 @@ function BattlecodeTable({ bottomElement, }: TableProps) { return ( -
- - +
+
+ {columns.map((col, idx) => ( { - ev.stopPropagation(); - onRowClick?.(row); + ev.stopPropagation() + onRowClick?.(row) }} className={ - idx % 2 === 0 - ? "bg-white border-b dark:bg-gray-900 dark:border-gray-700" - : "bg-gray-50 border-b dark:bg-gray-800 dark:border-gray-700" + idx % 2 === 0 ? "bg-white border-b" : "bg-gray-50 border-b" } > {columns.map((col, idx) => ( @@ -61,9 +59,9 @@ function BattlecodeTable({ ))}
@@ -39,20 +39,18 @@ function BattlecodeTable({
{col.value(row)}
- {bottomElement} +
{bottomElement}
- ); + ) } -export default BattlecodeTable; +export default BattlecodeTable diff --git a/frontend2/src/components/BattlecodeTableBottomElement.tsx b/frontend2/src/components/BattlecodeTableBottomElement.tsx index b6558a55a..ad3caa380 100644 --- a/frontend2/src/components/BattlecodeTableBottomElement.tsx +++ b/frontend2/src/components/BattlecodeTableBottomElement.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React, { useMemo } from "react" interface TableBottomProps { totalCount: number; @@ -13,47 +13,52 @@ const BattlecodeTableBottomElement: React.FC = ({ currentPage, onPage, }) => { - const first = (currentPage - 1) * pageSize + 1; - const last = Math.min(currentPage * pageSize, totalCount); - const pageCount = Math.ceil(totalCount / pageSize); + const first = (currentPage - 1) * pageSize + 1 + const last = Math.min(currentPage * pageSize, totalCount) + const pageCount = Math.ceil(totalCount / pageSize) - const backDisabled = currentPage <= 1; - const forwardDisabled = currentPage >= pageCount; + const backDisabled = currentPage <= 1 + const forwardDisabled = currentPage >= pageCount return ( - ); -}; + ) +} -export default BattlecodeTableBottomElement; +export default BattlecodeTableBottomElement diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index 57d1b6dcb..20ad5786f 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -1,48 +1,74 @@ -import { useContext, useEffect, useState } from "react"; -import { EpisodeContext } from "../contexts/EpisodeContext"; -import { Api } from "../utils/api"; -import BattlecodeTable from "../components/BattlecodeTable"; -import { PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList"; -import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement"; +import { useContext, useEffect, useState } from "react" +import { EpisodeContext } from "../contexts/EpisodeContext" +import { Api } from "../utils/api" +import BattlecodeTable from "../components/BattlecodeTable" +import { type PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList" +import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement" +import { NavLink, useNavigate } from "react-router-dom" + +function trimString(str: string, maxLength: number) { + if (str.length > maxLength) { + return str.slice(0, maxLength - 1) + "..." + } + return str +} const Rankings: React.FC = () => { - const episodeId = useContext(EpisodeContext); + const episodeId = useContext(EpisodeContext).episodeId + + const navigate = useNavigate() - const [page, setPage] = useState(1); - const [searchQuery, setSearchQuery] = useState(""); + const [page, setPage] = useState(1) + const [searchQuery, setSearchQuery] = useState("") const [requireActiveSubmission, setRequireActiveSubmission] = - useState(false); + useState(false) + const [loading, setLoading] = useState(true) const [data, setData] = useState( undefined - ); + ) const queryVars = { - episodeId: episodeId.episodeId, - searchQuery: searchQuery, + episodeId, + searchQuery, requireActiveSubmission: false, - page: page, - }; + page, + } + + function handlePage(page: number) { + if (!loading) { + setPage(page) + } + } useEffect(() => { + setLoading(true) + Api.searchTeams( queryVars.episodeId, queryVars.searchQuery, queryVars.requireActiveSubmission, queryVars.page - ).then((res) => setData(res)); - }, [queryVars]); + ).then((res) => { + setData(res) + setLoading(false) + }) + + return () => { setLoading(false) } + }, [searchQuery, page]) - if (!data) { - return <>Loading...; + if (data == null) { + return <>Loading... } return ( - <> -

+
+

Rankings

-
+
+ +
{ totalCount={data.count ?? 0} pageSize={10} currentPage={page} - onPage={(page) => setPage(page)} + onPage={(page) => { handlePage(page) }} /> } + onRowClick={(r) => { navigate(`/team/${r.id}`) }} columns={[ { header: "Rating", - value: (team) => team.profile?.rating ?? 0, + value: (team) => team.profile?.rating.toFixed(0) ?? 0, }, { header: "Team", value: (team) => team.name, }, + { + header: "Members", + value: (team) => + team.members.map((member, idx) => ( + <> + + {trimString(member.username, 13)} + + {idx !== team.members.length - 1 ? ", " : ""} + + )), + }, + { + header: "Quote", + value: (team) => team.profile?.quote ?? "", + }, + { + header: "Eligibility", + value: (team) => + team.profile?.eligibleFor?.map((e) => e).join(", ") ?? "", + }, + { + header: "Auto-Accept Ranked", + value: (team) => (team.profile?.autoAcceptRanked ? "Yes" : "No"), + }, + { + header: "Auto-Accept Unranked", + value: (team) => (team.profile?.autoAcceptUnranked ? "Yes" : "No"), + }, ]} /> - - ); -}; +
+ ) +} -export default Rankings; +export default Rankings From 1b5a6197c5206c7ca1252820af0b1383054e6ab1 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Sat, 22 Jul 2023 13:24:34 -0400 Subject: [PATCH 04/13] working loading element --- frontend2/src/components/BattlecodeTable.tsx | 38 +++++++-- frontend2/src/views/Rankings.tsx | 88 +++++++++----------- 2 files changed, 74 insertions(+), 52 deletions(-) diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx index 15e0e950a..104cc72a6 100644 --- a/frontend2/src/components/BattlecodeTable.tsx +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; interface Column { header: React.ReactNode; @@ -8,6 +8,7 @@ interface Column { interface TableProps { data: T[]; columns: Array>; + loading: boolean; onRowClick?: (data: T) => void; bottomElement?: JSX.Element; } @@ -19,6 +20,7 @@ interface TableProps { function BattlecodeTable({ data, columns, + loading, onRowClick, bottomElement, }: TableProps) { @@ -39,8 +41,8 @@ function BattlecodeTable({ { - ev.stopPropagation() - onRowClick?.(row) + ev.stopPropagation(); + onRowClick?.(row); }} className={ idx % 2 === 0 ? "bg-white border-b" : "bg-gray-50 border-b" @@ -59,9 +61,35 @@ function BattlecodeTable({ ))} +
+ {loading && ( +
+ +
+ )} +
{bottomElement}
- ) + ); } -export default BattlecodeTable +const Spinner: React.FC = () => ( + +); + +export default BattlecodeTable; diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index 20ad5786f..6c79ea589 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -1,65 +1,54 @@ -import { useContext, useEffect, useState } from "react" -import { EpisodeContext } from "../contexts/EpisodeContext" -import { Api } from "../utils/api" -import BattlecodeTable from "../components/BattlecodeTable" -import { type PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList" -import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement" -import { NavLink, useNavigate } from "react-router-dom" +import { useContext, useEffect, useState } from "react"; +import { EpisodeContext } from "../contexts/EpisodeContext"; +import { Api } from "../utils/api"; +import BattlecodeTable from "../components/BattlecodeTable"; +import { type PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList"; +import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement"; +import { NavLink, useNavigate } from "react-router-dom"; function trimString(str: string, maxLength: number) { if (str.length > maxLength) { - return str.slice(0, maxLength - 1) + "..." + return str.slice(0, maxLength - 1) + "..."; } - return str + return str; } const Rankings: React.FC = () => { - const episodeId = useContext(EpisodeContext).episodeId + const episodeId = useContext(EpisodeContext).episodeId; - const navigate = useNavigate() + const navigate = useNavigate(); - const [page, setPage] = useState(1) - const [searchQuery, setSearchQuery] = useState("") + const [page, setPage] = useState(1); + const [searchQuery, setSearchQuery] = useState(""); const [requireActiveSubmission, setRequireActiveSubmission] = - useState(false) - const [loading, setLoading] = useState(true) + useState(false); + const [loading, setLoading] = useState(true); const [data, setData] = useState( undefined - ) - - const queryVars = { - episodeId, - searchQuery, - requireActiveSubmission: false, - page, - } + ); function handlePage(page: number) { if (!loading) { - setPage(page) + setPage(page); } } useEffect(() => { - setLoading(true) + setLoading(true); + setData({ ...data, results: [] }); - Api.searchTeams( - queryVars.episodeId, - queryVars.searchQuery, - queryVars.requireActiveSubmission, - queryVars.page - ).then((res) => { - setData(res) - setLoading(false) - }) + Api.searchTeams(episodeId, searchQuery, requireActiveSubmission, page).then( + (res) => { + setData(res); + setLoading(false); + } + ); - return () => { setLoading(false) } - }, [searchQuery, page]) - - if (data == null) { - return <>Loading... - } + return () => { + setLoading(false); + }; + }, [searchQuery, page]); return (
@@ -70,16 +59,21 @@ const Rankings: React.FC = () => {
{ handlePage(page) }} + onPage={(page) => { + handlePage(page); + }} /> } - onRowClick={(r) => { navigate(`/team/${r.id}`) }} + onRowClick={(r) => { + navigate(`/team/${r.id}`); + }} columns={[ { header: "Rating", @@ -121,7 +115,7 @@ const Rankings: React.FC = () => { ]} />
- ) -} + ); +}; -export default Rankings +export default Rankings; From 62dc4816856b47d18209dfbc73badcde765c1ad1 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Sat, 22 Jul 2023 14:04:37 -0400 Subject: [PATCH 05/13] neatening --- frontend2/src/views/Rankings.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index 6c79ea589..c514391ea 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -34,6 +34,8 @@ const Rankings: React.FC = () => { } } + console.log(data); + useEffect(() => { setLoading(true); setData({ ...data, results: [] }); @@ -55,9 +57,7 @@ const Rankings: React.FC = () => {

Rankings

-
- -
+
{ columns={[ { header: "Rating", - value: (team) => team.profile?.rating.toFixed(0) ?? 0, + value: (team) => Math.round(team.profile?.rating ?? 0), }, { header: "Team", @@ -102,7 +102,9 @@ const Rankings: React.FC = () => { { header: "Eligibility", value: (team) => - team.profile?.eligibleFor?.map((e) => e).join(", ") ?? "", + (team.profile?.eligibleFor ?? []) + .map((e) => e.toString()) + .join(", "), }, { header: "Auto-Accept Ranked", From d9bd683294d40797103694c410c902bec61dfe3a Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Wed, 26 Jul 2023 22:34:12 -0400 Subject: [PATCH 06/13] better spinner --- frontend2/src/components/BattlecodeTable.tsx | 26 +++++++++------ frontend2/src/views/Rankings.tsx | 33 +++++++++----------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx index 104cc72a6..2e074d38f 100644 --- a/frontend2/src/components/BattlecodeTable.tsx +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -45,7 +45,17 @@ function BattlecodeTable({ onRowClick?.(row); }} className={ - idx % 2 === 0 ? "bg-white border-b" : "bg-gray-50 border-b" + idx % 2 === 0 + ? `bg-white border-b ${ + onRowClick !== undefined + ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" + : "" + }}` + : `bg-gray-50 border-b ${ + onRowClick !== undefined + ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" + : "" + }` } > {columns.map((col, idx) => ( @@ -61,13 +71,11 @@ function BattlecodeTable({ ))} -
- {loading && ( -
- -
- )} -
+ {loading && ( +
+ +
+ )}
{bottomElement}
); @@ -76,7 +84,7 @@ function BattlecodeTable({ const Spinner: React.FC = () => (
+ +
+ ); +}); + +export default Input; diff --git a/frontend2/tailwind.config.js b/frontend2/tailwind.config.js index d3bde7873..ebaf88bbb 100644 --- a/frontend2/tailwind.config.js +++ b/frontend2/tailwind.config.js @@ -8,7 +8,10 @@ module.exports = { colors: { teal: "#00A28E", }, + container: { + center: true, + }, }, }, - plugins: [], + plugins: [require("@tailwindcss/forms")], }; From ae15570e270008f06266ef92093ce928e2853338 Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Wed, 26 Jul 2023 23:26:50 -0400 Subject: [PATCH 08/13] working search! --- frontend2/package-lock.json | 8 +++--- frontend2/package.json | 2 +- frontend2/src/components/BattlecodeTable.tsx | 2 +- frontend2/src/views/Rankings.tsx | 29 ++++++++++++++++++-- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/frontend2/package-lock.json b/frontend2/package-lock.json index 19243932d..2d3a9ae40 100644 --- a/frontend2/package-lock.json +++ b/frontend2/package-lock.json @@ -25,7 +25,7 @@ "web-vitals": "^2.1.4" }, "devDependencies": { - "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/forms": "^0.5.4", "@types/jquery": "^3.5.16", "@types/js-cookie": "^3.0.3", "@typescript-eslint/eslint-plugin": "^5.59.8", @@ -3899,9 +3899,9 @@ } }, "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.4.tgz", + "integrity": "sha512-YAm12D3R7/9Mh4jFbYSMnsd6jG++8KxogWgqs7hbdo/86aWjjlIEvL7+QYdVELmAI0InXTpZqFIg5e7aDVWI2Q==", "dev": true, "dependencies": { "mini-svg-data-uri": "^1.2.3" diff --git a/frontend2/package.json b/frontend2/package.json index 4fe2a7baf..885718636 100644 --- a/frontend2/package.json +++ b/frontend2/package.json @@ -48,7 +48,7 @@ ] }, "devDependencies": { - "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/forms": "^0.5.4", "@types/jquery": "^3.5.16", "@types/js-cookie": "^3.0.3", "@typescript-eslint/eslint-plugin": "^5.59.8", diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx index 2e074d38f..ec0283641 100644 --- a/frontend2/src/components/BattlecodeTable.tsx +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -25,7 +25,7 @@ function BattlecodeTable({ bottomElement, }: TableProps) { return ( -
+
diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index 4ff9370d6..b502859e6 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -5,6 +5,8 @@ import BattlecodeTable from "../components/BattlecodeTable"; import { type PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList"; import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement"; import { NavLink } from "react-router-dom"; +import Input from "../components/elements/Input"; +import Button from "../components/elements/Button"; function trimString(str: string, maxLength: number) { if (str.length > maxLength) { @@ -17,6 +19,7 @@ const Rankings: React.FC = () => { const episodeId = useContext(EpisodeContext).episodeId; const [page, setPage] = useState(1); + const [searchText, setSearchText] = useState(""); const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(true); @@ -45,11 +48,31 @@ const Rankings: React.FC = () => { }, [searchQuery, page]); return ( -
-

+
+

Rankings

-
+
+
+ { + setSearchText(ev.target.value); + }} + /> +
+
+
+
+
+ Date: Thu, 27 Jul 2023 00:14:06 -0400 Subject: [PATCH 09/13] working url params --- frontend2/src/components/BattlecodeTable.tsx | 65 ++++++++++---------- frontend2/src/views/Rankings.tsx | 31 +++++++--- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/frontend2/src/components/BattlecodeTable.tsx b/frontend2/src/components/BattlecodeTable.tsx index ec0283641..c7d07d42a 100644 --- a/frontend2/src/components/BattlecodeTable.tsx +++ b/frontend2/src/components/BattlecodeTable.tsx @@ -37,38 +37,39 @@ function BattlecodeTable({

- {data.map((row, idx) => ( - { - ev.stopPropagation(); - onRowClick?.(row); - }} - className={ - idx % 2 === 0 - ? `bg-white border-b ${ - onRowClick !== undefined - ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" - : "" - }}` - : `bg-gray-50 border-b ${ - onRowClick !== undefined - ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" - : "" - }` - } - > - {columns.map((col, idx) => ( - - ))} - - ))} + {!loading && + data.map((row, idx) => ( + { + ev.stopPropagation(); + onRowClick?.(row); + }} + className={ + idx % 2 === 0 + ? `bg-white border-b ${ + onRowClick !== undefined + ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" + : "" + }}` + : `bg-gray-50 border-b ${ + onRowClick !== undefined + ? "cursor-pointer hover:bg-gray-100 hover:text-gray-700" + : "" + }` + } + > + {columns.map((col, idx) => ( + + ))} + + ))}
- {col.value(row)} -
+ {col.value(row)} +
{loading && ( diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index b502859e6..a77d3188d 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -4,7 +4,7 @@ import { Api } from "../utils/api"; import BattlecodeTable from "../components/BattlecodeTable"; import { type PaginatedTeamPublicList } from "../utils/types/model/PaginatedTeamPublicList"; import BattlecodeTableBottomElement from "../components/BattlecodeTableBottomElement"; -import { NavLink } from "react-router-dom"; +import { NavLink, useSearchParams } from "react-router-dom"; import Input from "../components/elements/Input"; import Button from "../components/elements/Button"; @@ -18,24 +18,32 @@ function trimString(str: string, maxLength: number) { const Rankings: React.FC = () => { const episodeId = useContext(EpisodeContext).episodeId; - const [page, setPage] = useState(1); const [searchText, setSearchText] = useState(""); - const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(true); - const [data, setData] = useState( undefined ); + const [queryParams, setQueryParams] = useSearchParams({ + page: "1", + search: "", + }); + const page = parseInt(queryParams.get("page") ?? "1"); + const searchQuery = queryParams.get("search") ?? ""; + function handlePage(page: number) { if (!loading) { - setPage(page); + queryParams.set("page", page.toString()); + setQueryParams(queryParams); } } useEffect(() => { + if (searchQuery !== searchText) { + setSearchText(searchQuery); + } + setLoading(true); - setData({ ...data, results: [] }); Api.searchTeams(episodeId, searchQuery, false, page).then((res) => { setData(res); @@ -61,6 +69,12 @@ const Rankings: React.FC = () => { onChange={(ev) => { setSearchText(ev.target.value); }} + onKeyDown={(ev) => { + if (ev.key === "Enter") { + queryParams.set("search", searchText); + setQueryParams(queryParams); + } + }} />
@@ -68,7 +82,10 @@ const Rankings: React.FC = () => {
From d5ff0bb2b2d3ceb60bba21d317b8b451c540fd0e Mon Sep 17 00:00:00 2001 From: Lowell Torola Date: Wed, 2 Aug 2023 17:01:14 -0400 Subject: [PATCH 10/13] adding search --- frontend2/src/views/Rankings.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend2/src/views/Rankings.tsx b/frontend2/src/views/Rankings.tsx index a77d3188d..690e6c838 100644 --- a/frontend2/src/views/Rankings.tsx +++ b/frontend2/src/views/Rankings.tsx @@ -39,10 +39,6 @@ const Rankings: React.FC = () => { } useEffect(() => { - if (searchQuery !== searchText) { - setSearchText(searchQuery); - } - setLoading(true); Api.searchTeams(episodeId, searchQuery, false, page).then((res) => { @@ -64,6 +60,7 @@ const Rankings: React.FC = () => {
{ @@ -81,6 +78,7 @@ const Rankings: React.FC = () => {