From 364a4f5aa3e12ae5dd3720cb856c5d39d7db4b1c Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Mon, 6 Feb 2023 02:17:28 +0700 Subject: [PATCH] Highlight current user in leaderboard (#1194) * Highlight current user in leaderboard * use first of type for ssr safety --- website/src/components/DataTable.tsx | 26 +++++++++----- .../LeaderboardTable/LeaderboardTable.tsx | 35 +++++++++++++++++-- website/src/types/Leaderboard.ts | 1 + 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index d9161e19..c724ada5 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -15,6 +15,7 @@ import { Table, TableCaption, TableContainer, + TableRowProps, Tbody, Td, Th, @@ -22,9 +23,9 @@ import { Tr, useDisclosure, } from "@chakra-ui/react"; -import { useTranslation } from "next-i18next"; -import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"; +import { ColumnDef, flexRender, getCoreRowModel, Row, useReactTable } from "@tanstack/react-table"; import { Filter } from "lucide-react"; +import { useTranslation } from "next-i18next"; import { ChangeEvent, ReactNode } from "react"; import { useDebouncedCallback } from "use-debounce"; @@ -38,6 +39,8 @@ export type FilterItem = { value: string; }; +export type DataTableRowPropsCallback = (row: Row) => TableRowProps; + export type DataTableProps = { data: T[]; columns: DataTableColumnDef[]; @@ -49,6 +52,7 @@ export type DataTableProps = { disableNext?: boolean; disablePrevious?: boolean; disablePagination?: boolean; + rowProps?: TableRowProps | DataTableRowPropsCallback; }; export const DataTable = ({ @@ -62,6 +66,7 @@ export const DataTable = ({ disableNext, disablePrevious, disablePagination, + rowProps, }: DataTableProps) => { const { t } = useTranslation("leaderboard"); const { getHeaderGroups, getRowModel } = useReactTable({ @@ -117,13 +122,16 @@ export const DataTable = ({ ))} - {getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - {flexRender(cell.column.columnDef.cell, cell.getContext())} - ))} - - ))} + {getRowModel().rows.map((row) => { + const props = typeof rowProps === "function" ? rowProps(row) : rowProps; + return ( + + {row.getVisibleCells().map((cell) => ( + {flexRender(cell.column.columnDef.cell, cell.getContext())} + ))} + + ); + })} diff --git a/website/src/components/LeaderboardTable/LeaderboardTable.tsx b/website/src/components/LeaderboardTable/LeaderboardTable.tsx index 3b6aafcd..6314080c 100644 --- a/website/src/components/LeaderboardTable/LeaderboardTable.tsx +++ b/website/src/components/LeaderboardTable/LeaderboardTable.tsx @@ -1,12 +1,13 @@ -import { CircularProgress } from "@chakra-ui/react"; +import { CircularProgress, useColorModeValue, useToken } from "@chakra-ui/react"; import { createColumnHelper } from "@tanstack/react-table"; import { useTranslation } from "next-i18next"; -import React, { useMemo, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { get } from "src/lib/api"; +import { colors } from "src/styles/Theme/colors"; import { LeaderboardEntity, LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard"; import useSWRImmutable from "swr/immutable"; -import { DataTable } from "../DataTable"; +import { DataTable, DataTableRowPropsCallback } from "../DataTable"; const columnHelper = createColumnHelper(); @@ -23,6 +24,7 @@ export const LeaderboardTable = ({ rowPerPage: number; }) => { const { t } = useTranslation("leaderboard"); + const { data: reply, isLoading, @@ -66,6 +68,32 @@ export const LeaderboardTable = ({ return reply?.leaderboard.slice(start, start + rowPerPage) || []; }, [rowPerPage, page, reply?.leaderboard]); + const borderColor = useToken("colors", useColorModeValue(colors.light.active, colors.dark.active)); + const rowProps = useCallback>( + (row) => { + return row.original.highlighted + ? { + sx: { + // https://stackoverflow.com/questions/37963524/how-to-apply-border-radius-to-tr-in-bootstrap + position: "relative", + "td:first-of-type:before": { + borderLeft: `6px solid ${borderColor}`, + content: `""`, + display: "block", + width: "10px", + height: "100%", + left: 0, + top: 0, + borderRadius: "6px 0 0 6px", + position: "absolute", + }, + }, + } + : {}; + }, + [borderColor] + ); + if (isLoading) { return ; } @@ -86,6 +114,7 @@ export const LeaderboardTable = ({ disablePrevious={page === 1} onNextClick={() => setPage((p) => p + 1)} onPreviousClick={() => setPage((p) => p - 1)} + rowProps={rowProps} > ); }; diff --git a/website/src/types/Leaderboard.ts b/website/src/types/Leaderboard.ts index 5c0acfc3..b806ac95 100644 --- a/website/src/types/Leaderboard.ts +++ b/website/src/types/Leaderboard.ts @@ -40,4 +40,5 @@ export interface LeaderboardEntity { reply_ranked_3: number; streak_last_day_date: number | null; streak_days: number | null; + highlighted: boolean; }