Skip to content

Commit

Permalink
Table Component/Rankings Page (#658)
Browse files Browse the repository at this point in the history
Co-authored-by: Serena Li <serena.li.usa@gmail.com>
  • Loading branch information
lowtorola and acrantel committed Feb 8, 2024
1 parent 73f986b commit 67cb3ed
Show file tree
Hide file tree
Showing 11 changed files with 589 additions and 3 deletions.
2 changes: 1 addition & 1 deletion frontend2/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = {
plugins: ["react"],
rules: {
indent: ["error", 2],
semi: "error", // require semicolons ending statements
semi: ["error", "always"], // require semicolons ending statements
},
settings: {
react: {
Expand Down
60 changes: 60 additions & 0 deletions frontend2/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions frontend2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
"@types/node": "^16.18.26",
"@types/react": "^18.2.6",
"@types/react-dom": "^18.2.4",
"jquery": "^3.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.1",
"react-router-dom": "^6.13.0",
"web-vitals": "^2.1.4"
},
Expand Down Expand Up @@ -46,6 +48,8 @@
]
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.4",
"@types/jquery": "^3.5.16",
"@types/js-cookie": "^3.0.3",
"@typescript-eslint/eslint-plugin": "^5.59.8",
"eslint": "^8.42.0",
Expand Down
4 changes: 3 additions & 1 deletion frontend2/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -38,10 +39,11 @@ const router = createBrowserRouter([
element: <EpisodeLayout />,
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: <Home /> },
{ path: "/:episodeId/quickstart", element: <QuickStart /> },
{ path: "/:episodeId/*", element: <NotFound /> },
{ path: "/:episodeId/rankings", element: <Rankings /> },
// Pages that should only be visible when logged in
// TODO: /:episodeId/team, /:episodeId/submissions, /:episodeId/scrimmaging
{ path: "/account", element: <Account /> },
Expand Down
86 changes: 86 additions & 0 deletions frontend2/src/components/BattlecodeTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from "react";
import Spinner from "./Spinner";

interface Column<T> {
header: React.ReactNode;
value: (data: T) => React.ReactNode;
}

interface TableProps<T> {
data: T[];
columns: Array<Column<T>>;
loading: boolean;
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<T>({
data,
columns,
loading,
onRowClick,
bottomElement,
}: TableProps<T>): React.ReactElement {
return (
<div className="w-5/6 pl-50">
<table className="w-full text-sm text-left text-gray-500">
<thead className="text-xs text-gray-700 uppercase bg-gray-50">
<tr>
{columns.map((col, idx) => (
<th key={idx} scope="col" className="px-8 py-3">
{col.header}
</th>
))}
</tr>
</thead>
<tbody>
{!loading &&
data.map((row, idx) => (
<tr
key={idx}
onClick={(ev) => {
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) => (
<th
key={idx}
scope="row"
className="px-8 py-3 font-medium text-gray-900 whitespace-nowrap"
>
{col.value(row)}
</th>
))}
</tr>
))}
</tbody>
</table>
{loading && (
<div className="w-full h-64 flex flex-row items-center justify-center">
<Spinner />
</div>
)}
<div className="mx-10 text-center">{bottomElement}</div>
</div>
);
}

export default BattlecodeTable;
Loading

0 comments on commit 67cb3ed

Please sign in to comment.