You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
4.9 KiB
TypeScript

import { useContext, useState } from 'preact/hooks'
import { SolutionStat } from '../../shared/model'
import { sortByNumericKey, sortByStringKey } from '../../shared/utils'
import { prependBaseUrl } from '../api'
import { Header } from '../components/Header'
import { useResource, MetadataContext } from '../hooks'
export const ScoresPage = () => {
const metadata = useContext(MetadataContext)
metadata.title = `PHC Problemi`
metadata.description = 'Bacheca di problemi del PHC'
const [stats] = useResource<Record<string, SolutionStat>>(`/api/stats`, {})
type Column = 'student' | 'sent' | 'correct'
type Order = 'ascending' | 'descending'
type SortStateSpace = [Column, Order]
const [[sortStateColumn, sortStateOrder], setSortState] = useState<SortStateSpace>(['correct', 'descending'])
const transitionColumn: (k: Column) => Partial<Record<Column, Record<Order, (c: Column) => SortStateSpace>>> = k => ({
[k]: {
ascending: (c: Column) => (c === k ? [k, 'descending'] : [c, 'ascending']),
descending: (c: Column) => (c === k ? [k, 'ascending'] : [c, 'ascending']),
},
})
const transitionMap: Record<Column, Record<Order, (c: Column) => SortStateSpace>> = {
...(transitionColumn('student') as Record<'student', Record<Order, (c: Column) => SortStateSpace>>),
...(transitionColumn('sent') as Record<'sent', Record<Order, (c: Column) => SortStateSpace>>),
...(transitionColumn('correct') as Record<'correct', Record<Order, (c: Column) => SortStateSpace>>),
}
let orderedStats
if (sortStateColumn === 'student') {
orderedStats = sortByStringKey(Object.entries(stats), ([user, s]) => user.toLowerCase(), sortStateOrder === 'ascending')
} else {
orderedStats = sortByNumericKey(
Object.entries(stats),
// @ts-ignore
([user, s]) => s[sortStateColumn + 'SolutionsCount'],
sortStateOrder === 'ascending'
)
}
return (
<>
<Header />
<main class="page-scores">
<div class="subtitle">Classifica</div>
<div class="scrollable">
<div class="table">
<div class="cell header">
<span>Studente</span>
<span onClick={() => setSortState(transitionMap[sortStateColumn][sortStateOrder]('student'))}>
<span class="material-symbols-outlined icon">
{sortStateColumn === 'student'
? sortStateOrder === 'ascending'
? 'expand_more'
: 'expand_less'
: 'unfold_more'}
</span>
</span>
</div>
<div class="cell header">
<span>Soluzioni Inviate</span>
<span onClick={() => setSortState(transitionMap[sortStateColumn][sortStateOrder]('sent'))}>
<span class="material-symbols-outlined icon">
{sortStateColumn === 'sent'
? sortStateOrder === 'ascending'
? 'expand_more'
: 'expand_less'
: 'unfold_more'}
</span>
</span>
</div>
<div class="cell header">
<span>Soluzioni Corrette</span>
<span onClick={() => setSortState(transitionMap[sortStateColumn][sortStateOrder]('correct'))}>
<span class="material-symbols-outlined icon">
{sortStateColumn === 'correct'
? sortStateOrder === 'ascending'
? 'expand_more'
: 'expand_less'
: 'unfold_more'}
</span>
</span>
</div>
{orderedStats.map(([user, s]) => (
<>
<div class="cell">
<a href={prependBaseUrl(`/u/${user}`)}>@{user}</a>
</div>
<div class="cell">{s.sentSolutionsCount}</div>
<div class="cell last-col">{s.correctSolutionsCount}</div>
</>
))}
</div>
</div>
</main>
</>
)
}