- {submissionsLoading || problemLoading ? (
- <>
-
-
-
-
-
- {[...Array(8)].map((_, i) => (
-
- ))}
- >
- ) : (
-
-
-
-
- )}
+
+ }>
+
+
+ }>
+
+
diff --git a/apps/frontend/app/admin/contest/_components/DuplicateContest.tsx b/apps/frontend/app/admin/contest/_components/DuplicateContest.tsx
deleted file mode 100644
index 0702d654e8..0000000000
--- a/apps/frontend/app/admin/contest/_components/DuplicateContest.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-'use client'
-
-import {
- AlertDialog,
- AlertDialogTrigger,
- AlertDialogContent,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogCancel,
- AlertDialogAction
-} from '@/components/ui/alert-dialog'
-import { Button } from '@/components/ui/button'
-import { DUPLICATE_CONTEST } from '@/graphql/contest/mutations'
-import { useMutation } from '@apollo/client'
-import { CopyIcon } from 'lucide-react'
-import { useRouter } from 'next/navigation'
-import { toast } from 'sonner'
-
-export default function DuplicateContest({
- groupId,
- contestId,
- contestStatus
-}: {
- groupId: number
- contestId: number
- contestStatus: string
-}) {
- const router = useRouter()
- const [duplicateContest, { error }] = useMutation(DUPLICATE_CONTEST)
-
- const duplicateContestById = async () => {
- if (error) {
- console.error(error)
- return
- }
- const toastId = toast.loading('Duplicating contest...')
-
- const res = await duplicateContest({
- variables: {
- groupId,
- contestId
- }
- })
-
- if (res.data?.duplicateContest.contest) {
- toast.success(
- `Contest duplicated completed.\n Duplicated contest title: ${res.data.duplicateContest.contest.title}`,
- {
- id: toastId
- }
- )
- }
- router.refresh()
- }
-
- return (
-
-
-
-
-
- Duplicate
-
-
-
-
-
- Duplicate {contestStatus === 'ongoing' ? 'Ongoing ' : ''}Contest
-
-
- Contents That Will Be Copied:
-
- Title
- Start Time & End Time
- Description
-
- Contest Security Settings (invitation code, allow copy/paste)
-
- Contest Problems
-
- Participants of the selected contest
-
- (All participants of the selected contest will be
- automatically registered for the duplicated contest.)
-
-
-
- Contents That Will Not Be Copied:
-
- {contestStatus === 'ongoing' ? (
-
- Caution: The new contest will be set to visible.
-
- ) : (
-
- Caution: The new contest will be set to invisible
-
- )}
-
- Are you sure you want to proceed with duplicating the selected
- contest?
-
-
-
-
-
- Cancel
-
-
- Duplicate
-
-
-
-
-
- )
-}
diff --git a/apps/frontend/app/admin/contest/utils.ts b/apps/frontend/app/admin/contest/utils.ts
index 2a1cceff34..2af0e021c8 100644
--- a/apps/frontend/app/admin/contest/utils.ts
+++ b/apps/frontend/app/admin/contest/utils.ts
@@ -65,7 +65,8 @@ export interface OverallSubmission {
codeSize?: number | null
ip?: string | null
id: number
- order: number
+ order?: number | null
+ problemId: number
}
export interface UserSubmission {
@@ -76,5 +77,5 @@ export interface UserSubmission {
codeSize?: number | null
ip?: string | null
id: number
- order: number
+ order?: number | null
}
diff --git a/apps/frontend/components/DataTableAdmin.tsx b/apps/frontend/components/DataTableAdmin.tsx
deleted file mode 100644
index 7141b6c708..0000000000
--- a/apps/frontend/components/DataTableAdmin.tsx
+++ /dev/null
@@ -1,566 +0,0 @@
-'use client'
-
-import SubmissionDetailAdmin from '@/app/admin/contest/[id]/_components/SubmissionDetailAdmin'
-import DuplicateContest from '@/app/admin/contest/_components/DuplicateContest'
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle
-} from '@/components/ui/alert-dialog'
-import { Button } from '@/components/ui/button'
-import { Dialog, DialogContent } from '@/components/ui/dialog'
-import {
- Table,
- TableBody,
- TableCell,
- TableFooter,
- TableHead,
- TableHeader,
- TableRow
-} from '@/components/ui/table'
-import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
- TooltipProvider
-} from '@/components/ui/tooltip'
-import { DELETE_CONTEST } from '@/graphql/contest/mutations'
-import { GET_BELONGED_CONTESTS } from '@/graphql/contest/queries'
-import { DELETE_PROBLEM } from '@/graphql/problem/mutations'
-import { getStatusWithStartEnd } from '@/lib/utils'
-import { useLazyQuery, useMutation } from '@apollo/client'
-import type { ColumnDef, SortingState } from '@tanstack/react-table'
-import {
- flexRender,
- getCoreRowModel,
- getFacetedRowModel,
- getFacetedUniqueValues,
- getFilteredRowModel,
- getPaginationRowModel,
- getSortedRowModel,
- useReactTable
-} from '@tanstack/react-table'
-import { CopyIcon } from 'lucide-react'
-import type { Route } from 'next'
-import { usePathname, useRouter } from 'next/navigation'
-import { useEffect, useState, Suspense } from 'react'
-import { IoSearch } from 'react-icons/io5'
-import { PiTrashLight } from 'react-icons/pi'
-import { toast } from 'sonner'
-import DataTableLangFilter from './DataTableLangFilter'
-import DataTableLevelFilter from './DataTableLevelFilter'
-import { DataTablePagination } from './DataTablePagination'
-import DataTableProblemFilter from './DataTableProblemFilter'
-import { Input } from './ui/input'
-
-interface DataTableProps
{
- columns: ColumnDef[]
- data: TData[]
- enableSearch?: boolean // Enable search title
- searchColumn?: string
- enableFilter?: boolean // Enable filter for languages and tags
- enableProblemFilter?: boolean // Enable filter for problems
- enableDelete?: boolean // Enable delete selected rows
- enablePagination?: boolean // Enable pagination
- enableRowsPerpage?: boolean
- enableImport?: boolean // Enable import selected rows
- enableDuplicate?: boolean // Enable duplicate selected rows
- checkedRows?: ContestProblem[] // Check selected rows
- headerStyle?: {
- [key: string]: string
- }
- onSelectedExport?: (selectedRows: ContestProblem[]) => void
- defaultSortColumn?: { id: string; desc: boolean }
- enableFooter?: boolean
- defaultPageSize?: number
-}
-
-interface ContestProblem {
- id: number
- title: string
- difficulty: string
-}
-
-interface SelectedContest {
- original: {
- id: number
- startTime: string
- endTime: string
- }
-}
-
-const languageOptions = ['C', 'Cpp', 'Java', 'Python3']
-const levels = ['Level1', 'Level2', 'Level3', 'Level4', 'Level5']
-
-export function DataTableAdmin({
- columns,
- data,
- enableSearch = false,
- searchColumn = 'title',
- enableFilter = false,
- enableProblemFilter = false,
- enableDelete = false,
- enablePagination = false,
- enableRowsPerpage = true,
- enableImport = false,
- checkedRows = [],
- headerStyle = {},
- enableDuplicate = false,
- onSelectedExport = () => {},
- defaultSortColumn = { id: '', desc: false },
- enableFooter = false,
- defaultPageSize = 10
-}: DataTableProps) {
- const [rowSelection, setRowSelection] = useState({})
- const [sorting, setSorting] = useState([])
- const [defaultSortExists, setDefaultExists] = useState(defaultSortColumn.id)
- useEffect(() => {
- if (defaultSortExists)
- setSorting([{ id: defaultSortColumn.id, desc: defaultSortColumn.desc }])
- setDefaultExists('')
- }, [defaultSortExists, defaultSortColumn])
- const pathname = usePathname()
- const page = pathname.split('/').pop()
- const router = useRouter()
- const selectedRowCount = Object.values(rowSelection).filter(Boolean).length
- const table = useReactTable({
- data,
- columns,
- defaultColumn: {
- minSize: 0,
- size: Number.MAX_SAFE_INTEGER,
- maxSize: Number.MAX_SAFE_INTEGER
- },
- state: {
- sorting: enableImport
- ? [{ id: 'select', desc: true }, ...sorting]
- : sorting,
- rowSelection,
- columnVisibility: { languages: false }
- },
- autoResetPageIndex: false,
- enableRowSelection: true,
- onRowSelectionChange: setRowSelection,
- onSortingChange: setSorting,
- getCoreRowModel: getCoreRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- getPaginationRowModel: getPaginationRowModel(),
- getSortedRowModel: getSortedRowModel(),
- getFacetedRowModel: getFacetedRowModel(),
- getFacetedUniqueValues: getFacetedUniqueValues()
- })
-
- useEffect(() => {
- table.setPageSize(defaultPageSize)
- }, [defaultPageSize, table])
-
- let deletingObject
- if (pathname === '/admin/contest') {
- deletingObject = 'contest'
- } else {
- deletingObject = 'problem'
- }
-
- const [deleteProblem] = useMutation(DELETE_PROBLEM)
- const [deleteContest] = useMutation(DELETE_CONTEST)
- const [isDeleteAlertDialogOpen, setIsDeleteAlertDialogOpen] = useState(false)
- const [isSubmissionDialogOpen, setIsSubmissionDialogOpen] = useState(false)
- const [submissionId, setSubmissionId] = useState(0)
-
- useEffect(() => {
- if (checkedRows.length !== 0) {
- const problemIds = checkedRows.map((problem) => problem.id)
- const problemIndex = data.reduce((acc: number[], problem, index) => {
- if (problemIds.includes((problem as { id: number }).id)) {
- acc.push(index as number)
- }
- return acc
- }, [])
- setRowSelection(
- problemIndex.reduce(
- (acc: { [key: number]: boolean }, index: number) => ({
- ...acc,
- [index]: true
- }),
- {}
- )
- )
- }
- }, [checkedRows, data])
-
- const handleImportProblems = async () => {
- const selectedProblems = table.getSelectedRowModel().rows as {
- original: { id: number; title: string; difficulty: string; score: number }
- }[]
- const problems = selectedProblems.map((problem) => ({
- id: problem.original.id,
- title: problem.original.title,
- difficulty: problem.original.difficulty,
- score: problem.original.score ?? 0 // Score 기능 완료되면 수정해주세요!!
- }))
- onSelectedExport(problems)
- }
-
- // TODO: notice도 같은 방식으로 추가
- const handleDeleteRows = async () => {
- const selectedRows = table.getSelectedRowModel().rows as {
- original: { id: number }
- }[]
- const deletePromise = selectedRows.map((row) => {
- if (page === 'problem') {
- return deleteProblem({
- variables: {
- groupId: 1,
- id: row.original.id
- }
- })
- } else if (page === 'contest') {
- return deleteContest({
- variables: {
- groupId: 1,
- contestId: row.original.id
- }
- })
- } else {
- return Promise.resolve()
- }
- })
- await Promise.all(deletePromise)
- .then(() => {
- setRowSelection({})
- router.refresh()
- })
- .catch(() => {
- toast.error(`Failed to delete ${page}`)
- })
- }
-
- const [fetchContests] = useLazyQuery(GET_BELONGED_CONTESTS)
-
- const handleDeleteButtonClick = async () => {
- if (page === 'problem') {
- const selectedRows = table.getSelectedRowModel().rows as {
- original: { id: number }
- }[]
- const promises = selectedRows.map((row) =>
- fetchContests({
- variables: {
- problemId: Number(row.original.id)
- }
- }).then((result) => result.data)
- )
- const results = await Promise.all(promises)
- const isAllSafe = !results.some((data) => data !== undefined)
- if (isAllSafe) {
- setIsDeleteAlertDialogOpen(true)
- } else {
- setIsDeleteAlertDialogOpen(false)
- toast.error('Failed : Problem included in the contest')
- }
- } else {
- setIsDeleteAlertDialogOpen(true)
- }
- }
-
- return (
-
-
- {(enableSearch ||
- enableFilter ||
- enableImport ||
- enableDelete ||
- enableDuplicate) && (
-
-
- {enableSearch && (
-
-
- {
- table
- .getColumn(searchColumn)
- ?.setFilterValue(event.target.value)
- table.setPageIndex(0)
- }}
- className="h-10 w-[150px] bg-transparent pl-8 lg:w-[250px]"
- />
-
- )}
- {enableFilter && (
-
- {table.getColumn('languages') && (
-
- )}
- {table.getColumn('difficulty') && (
-
- )}
- {enableProblemFilter && (
-
- )}
-
- )}
-
-
- {enableImport ? (
-
handleImportProblems()}>
- Import / Edit
-
- ) : null}
- {enableDuplicate ? (
- selectedRowCount === 1 ? (
-
- ) : (
-
-
-
-
-
- Duplicate
-
-
-
- Select only one contest to duplicate
-
-
-
- )
- ) : null}
- {enableDelete ? (
- selectedRowCount !== 0 ? (
-
-
-
-
-
-
-
- Delete
-
- Are you sure you want to permanently delete{' '}
- {selectedRowCount} {deletingObject}(s)?
-
-
-
- Cancel
-
- handleDeleteRows()}
- className="bg-red-500 hover:bg-red-500/90"
- >
- Delete
-
-
-
-
-
-
- ) : (
-
-
-
- )
- ) : null}
-
-
- )}
-
-
-
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => {
- return (
-
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
-
- )
- })}
-
- ))}
-
-
-
- {table.getRowModel().rows?.length ? (
- table.getRowModel().rows.map((row) => {
- const participantRegex = /^\/admin\/contest\/\d+$/
- const href = (() => {
- if (participantRegex.test(pathname)) {
- return `${pathname}/participant/${(row.original as { userId: number }).userId}` as Route
- }
- if (page === 'contest') {
- return `/admin/contest/${(row.original as { id: number }).id}` as Route
- }
- if (page === 'problem') {
- return `/admin/problem/${(row.original as { id: number }).id}` as Route
- }
- if (page === 'submission') {
- const submission = row.original as {
- problemId: number
- id: number
- }
- return `/contest/${pathname.split('/')[3]}/problem/${submission.problemId}/submission/${submission.id}` as Route
- }
- if (pathname.includes('participant') && enableProblemFilter) {
- const submission = row.original as {
- contestId: number
- problemId: number
- id: number
- }
- return `/contest/${submission.contestId}/problem/${submission.problemId}/submission/${submission.id}` as Route
- }
- return ''
- })()
- return (
-
- {row.getVisibleCells().map((cell) => (
- {
- if (enableImport) {
- const selectedRowCount =
- table.getSelectedRowModel().rows.length
- if (selectedRowCount < 20 || row.getIsSelected()) {
- row.toggleSelected(!row.getIsSelected())
- } else {
- toast.error(
- 'You can only import up to 20 problems in a contest'
- )
- }
- } else {
- if (href) {
- if (href.includes('submission')) {
- const submissionId = Number(href.split('/')[6])
- setSubmissionId(submissionId)
- setIsSubmissionDialogOpen(true)
- } else {
- router.push(href)
- }
- }
- }
- }}
- >
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
-
- ))}
-
- )
- })
- ) : (
-
-
- No results.
-
-
- )}
-
- {enableFooter && (
-
- {table.getFooterGroups().map((footerGroup) => (
-
- {footerGroup.headers.map((footer) => {
- return (
-
- {footer.isPlaceholder
- ? null
- : flexRender(
- footer.column.columnDef.footer,
- footer.getContext()
- )}
-
- )
- })}
-
- ))}
-
- )}
-
-
- {enablePagination && (
-
- )}
-
{
- setIsSubmissionDialogOpen(false)
- }}
- >
-
-
-
-
-
- )
-}
diff --git a/apps/frontend/components/DataTableColumnHeader.tsx b/apps/frontend/components/DataTableColumnHeader.tsx
deleted file mode 100644
index bd40ec581c..0000000000
--- a/apps/frontend/components/DataTableColumnHeader.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { Button } from '@/components/ui/button'
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger
-} from '@/components/ui/dropdown-menu'
-import { cn } from '@/lib/utils'
-import { TriangleDownIcon, TriangleUpIcon } from '@radix-ui/react-icons'
-import type { Column } from '@tanstack/react-table'
-
-interface DataTableColumnHeaderProps
- extends React.HTMLAttributes {
- column: Column
- title: string
-}
-
-export function DataTableColumnHeader({
- column,
- title,
- className
-}: DataTableColumnHeaderProps) {
- // Title column
- if (!column.getCanSort()) {
- return (
-
- {title}
-
- )
- }
-
- return (
-
-
-
-
- {title}
- {column.getIsSorted() === 'desc' ? (
-
- ) : column.getIsSorted() === 'asc' ? (
-
- ) : (
-
-
-
-
- )}
-
-
-
- column.toggleSorting(false)}>
-
- {title === 'Visible' ? 'Hidden first' : 'Asc'}
-
- column.toggleSorting(true)}>
-
- {title === 'Visible' ? 'Visible first' : 'Desc'}
-
-
-
-
- )
-}
diff --git a/apps/frontend/components/DataTableLangFilter.tsx b/apps/frontend/components/DataTableLangFilter.tsx
deleted file mode 100644
index 50ae90a618..0000000000
--- a/apps/frontend/components/DataTableLangFilter.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import { Badge } from '@/components/ui/badge'
-import { Button } from '@/components/ui/button'
-import { Checkbox } from '@/components/ui/checkbox'
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandItem,
- CommandList
-} from '@/components/ui/command'
-import {
- Popover,
- PopoverContent,
- PopoverTrigger
-} from '@/components/ui/popover'
-import { Separator } from '@/components/ui/separator'
-import type { Column } from '@tanstack/react-table'
-import { IoFilter } from 'react-icons/io5'
-
-interface DataTableLangFilterProps {
- column?: Column
- title?: string
- options: string[]
-}
-
-export default function DataTableLangFilter({
- column,
- title,
- options
-}: DataTableLangFilterProps) {
- const selectedValues = new Set(column?.getFilterValue() as string[])
-
- return (
-
-
-
-
- {title}
- {selectedValues.size > 0 && (
- <>
-
-
- {selectedValues.size === options.length ? (
-
- All
-
- ) : (
-
- {options
- .filter((option) => selectedValues.has(option))
- .map((option) => (
-
- {option}
-
- ))}
-
- )}
-
- >
- )}
-
-
-
-
-
-
- No language found.
-
- {options.map((option) => (
-
- {
- if (selectedValues.has(option)) {
- selectedValues.delete(option)
- } else {
- selectedValues.add(option)
- }
- const filterValues = Array.from(selectedValues)
- column?.setFilterValue(
- filterValues.length ? filterValues : undefined
- )
- }}
- />
- {option}
-
- ))}
-
-
-
-
-
- )
-}
diff --git a/apps/frontend/components/DataTableLevelFilter.tsx b/apps/frontend/components/DataTableLevelFilter.tsx
deleted file mode 100644
index ed82730bc5..0000000000
--- a/apps/frontend/components/DataTableLevelFilter.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import { Badge } from '@/components/ui/badge'
-import { Button } from '@/components/ui/button'
-import { Checkbox } from '@/components/ui/checkbox'
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandItem,
- CommandList
-} from '@/components/ui/command'
-import {
- Popover,
- PopoverContent,
- PopoverTrigger
-} from '@/components/ui/popover'
-import { Separator } from '@/components/ui/separator'
-import type { Column } from '@tanstack/react-table'
-import { IoFilter } from 'react-icons/io5'
-
-interface DataTableLevelFilterProps {
- column?: Column
- title?: string
- options: string[]
-}
-
-export default function DataTableLevelFilter({
- column,
- title,
- options
-}: DataTableLevelFilterProps) {
- const selectedValues = new Set(column?.getFilterValue() as string)
-
- return (
-
-
-
-
- {title}
- {selectedValues.size > 0 && (
- <>
-
-
- {selectedValues.size === options.length ? (
-
- All
-
- ) : (
-
- {options
- .filter((option) => selectedValues.has(option))
- .map((option) => (
-
- Level {option.slice(-1)}
-
- ))}
-
- )}
-
- >
- )}
-
-
-
-
-
-
- No level found.
-
- {options.map((option) => (
-
- {
- if (selectedValues.has(option)) {
- selectedValues.delete(option)
- } else {
- selectedValues.add(option)
- }
- const filterValues = Array.from(selectedValues)
- column?.setFilterValue(
- filterValues.length ? filterValues : undefined
- )
- }}
- />
- Level {option.slice(-1)}
-
- ))}
-
-
-
-
-
- )
-}
diff --git a/apps/frontend/components/DataTablePagination.tsx b/apps/frontend/components/DataTablePagination.tsx
deleted file mode 100644
index 5322b5e74f..0000000000
--- a/apps/frontend/components/DataTablePagination.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue
-} from '@/components/ui/select'
-import { cn } from '@/lib/utils'
-import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons'
-import type { Table } from '@tanstack/react-table'
-
-interface DataTablePaginationProps {
- table: Table
- showRowsPerPage?: boolean
-}
-
-function pageArray(m: number, n: number): number[] {
- return Array(n - m + 1)
- .fill(0)
- .map((_, i) => m + i)
-}
-
-export function DataTablePagination({
- table,
- showRowsPerPage = true
-}: DataTablePaginationProps) {
- return (
-
-
- {table.getColumn('select') &&
- `${table.getFilteredSelectedRowModel().rows.length} of${' '}
- ${table.getFilteredRowModel().rows.length} row(s) selected`}
-
-
- {
- table.previousPage()
- }}
- disabled={!table.getCanPreviousPage()}
- >
-
-
- {pageArray(
- Math.floor(table.getState().pagination.pageIndex / 10) * 10 + 1,
- Math.min(
- Math.ceil(
- table.getFilteredRowModel().rows.length /
- table.getState().pagination.pageSize
- ),
- Math.floor(table.getState().pagination.pageIndex / 10) * 10 + 10
- )
- ).map((pageNumber) => (
- {
- table.setPageIndex(pageNumber - 1)
- }}
- >
- {pageNumber}
-
- ))}
- {
- table.nextPage()
- }}
- disabled={!table.getCanNextPage()}
- >
-
-
-
-
- {showRowsPerPage && (
-
-
Rows per page
-
{
- table.setPageSize(Number(value))
- }}
- >
-
-
-
-
- {[10, 20, 30, 40, 50].map((pageSize) => (
-
- {pageSize}
-
- ))}
-
-
-
- )}
-
-
- )
-}
diff --git a/apps/frontend/components/DataTableProblemFilter.tsx b/apps/frontend/components/DataTableProblemFilter.tsx
deleted file mode 100644
index b496a15818..0000000000
--- a/apps/frontend/components/DataTableProblemFilter.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { Button } from '@/components/ui/button'
-import {
- Command,
- CommandGroup,
- CommandItem,
- CommandList
-} from '@/components/ui/command'
-import {
- Popover,
- PopoverContent,
- PopoverTrigger
-} from '@/components/ui/popover'
-import { GET_CONTEST_PROBLEMS } from '@/graphql/problem/queries'
-import { cn } from '@/lib/utils'
-import { useQuery } from '@apollo/client'
-import type { Column } from '@tanstack/react-table'
-import { useParams } from 'next/navigation'
-import { useState } from 'react'
-import { FaCheck, FaChevronDown } from 'react-icons/fa'
-
-interface DataTableProblemFilterProps {
- column?: Column
-}
-
-export default function DataTableLevelFilter({
- column
-}: DataTableProblemFilterProps) {
- const { id } = useParams()
- const [selectedValue, setSelectedValue] = useState(
- undefined
- )
- const [problemFilterOpen, setProblemFilterOpen] = useState(false)
- const [problems, setProblems] = useState([])
-
- useQuery(GET_CONTEST_PROBLEMS, {
- variables: { groupId: 1, contestId: Number(id) },
- onCompleted: (problemData) => {
- const data = problemData.getContestProblems
- const sortedData = data.slice().sort((a, b) => a.order - b.order)
- setProblems([
- 'All Problems',
- ...sortedData.map(
- (problem) =>
- `${String.fromCharCode(65 + problem.order)}. ${problem.problem.title}`
- )
- ])
- }
- })
-
- return (
-
-
-
-
- {selectedValue ?? 'All Problems'}
-
-
-
-
-
-
-
-
-
- {problems.map((option) => (
- {
- option === 'All Problems'
- ? column?.setFilterValue(null)
- : column?.setFilterValue(option.slice(3))
- setProblemFilterOpen(false)
- setSelectedValue(option)
- }}
- >
-
- {option}
-
-
-
- ))}
-
-
-
-
-
- )
-}