mirror of
https://gitlab.com/MrFry/qmining-page
synced 2025-04-01 20:23:44 +02:00
267 lines
7 KiB
JavaScript
267 lines
7 KiB
JavaScript
import React, { useState, useEffect } from 'react'
|
|
|
|
import Header from '../components/header'
|
|
import LoadingIndicator from '../components/LoadingIndicator'
|
|
|
|
import styles from './ranklist.module.css'
|
|
import constants from '../constants'
|
|
|
|
const selectOptions = {
|
|
newQuestions: { name: 'Beküldött új kérdések' },
|
|
allQuestions: { name: 'Megoldott kérdések' },
|
|
count: { name: 'Megoldott tesztek' },
|
|
}
|
|
|
|
const sinceOptions = {
|
|
all: {
|
|
name: 'All time',
|
|
},
|
|
monthly: { name: 'Havi' },
|
|
weekly: { name: 'Heti' },
|
|
daily: { name: 'Napi' },
|
|
}
|
|
|
|
function getTimeString(date) {
|
|
return (
|
|
date.getFullYear() +
|
|
'-' +
|
|
('0' + (date.getMonth() + 1)).slice(-2) +
|
|
'-' +
|
|
('0' + date.getDate()).slice(-2)
|
|
)
|
|
}
|
|
|
|
function getSinceDate(keyword) {
|
|
if (keyword === 'all') {
|
|
return null
|
|
}
|
|
|
|
const date = new Date()
|
|
if (keyword === 'daily') {
|
|
date.setDate(date.getDate() - 1)
|
|
} else if (keyword === 'weekly') {
|
|
date.setDate(date.getDate() - 7)
|
|
} else if (keyword === 'monthly') {
|
|
date.setDate(date.getDate() - 30)
|
|
}
|
|
return date
|
|
}
|
|
|
|
async function getListFromServer(since) {
|
|
return new Promise((resolve, reject) => {
|
|
let query = ''
|
|
if (since && since !== 'all') {
|
|
query = `?since=${getTimeString(getSinceDate(since))}`
|
|
}
|
|
fetch(`${constants.apiUrl}ranklist${query}`, {
|
|
credentials: 'include',
|
|
Accept: 'application/json',
|
|
'Content-Type': 'application/json',
|
|
})
|
|
.then((resp) => {
|
|
return resp.json()
|
|
})
|
|
.then((data) => {
|
|
resolve(data)
|
|
})
|
|
.catch((error) => {
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
function sortDataBy(data, key) {
|
|
return data.sort((a, b) => {
|
|
if (a[key] < b[key]) {
|
|
return 1
|
|
} else if (a[key] > b[key]) {
|
|
return -1
|
|
} else {
|
|
return 0
|
|
}
|
|
})
|
|
}
|
|
|
|
export default function RankList({ globalData, globalState, setGlobalState }) {
|
|
const userId = globalData.userId
|
|
const [ranklist, setRanklist] = useState(null)
|
|
const [selfUserId, setSelfUserId] = useState('...')
|
|
const [key, setKey] = useState('newQuestions')
|
|
const [since, setSince] = useState('all')
|
|
const [sum, setSum] = useState()
|
|
const [ownEntryOnTop, setOwnEntryOnTop] = useState(false)
|
|
const [isEmpty, setIsEmpty] = useState(false)
|
|
|
|
const getList = () => {
|
|
setSum()
|
|
setRanklist(null)
|
|
if (globalState[`rankilst_${since}`]) {
|
|
const { list, sum, selfuserId } = globalState[`rankilst_${since}`]
|
|
setRanklist(list || [])
|
|
setSum(sum)
|
|
if (selfuserId) {
|
|
setSelfUserId(selfuserId)
|
|
}
|
|
} else {
|
|
getListFromServer(since)
|
|
.then((data) => {
|
|
const { list, sum, selfuserId } = data
|
|
if (!list && !sum && !selfuserId) {
|
|
setIsEmpty(true)
|
|
return
|
|
}
|
|
setRanklist(list || [])
|
|
setSum(sum)
|
|
if (selfuserId) {
|
|
setSelfUserId(selfuserId)
|
|
}
|
|
setGlobalState({
|
|
[`rankilst_${since}`]: data,
|
|
})
|
|
})
|
|
.catch(() => {
|
|
setRanklist(null)
|
|
})
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
getList()
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
getList()
|
|
}, [since])
|
|
|
|
const list =
|
|
ranklist &&
|
|
sortDataBy(ranklist, key).reduce((acc, entry, i) => {
|
|
if (entry.userId === userId && ownEntryOnTop) {
|
|
return [{ rank: i, ...entry }, ...acc]
|
|
} else {
|
|
return [...acc, { rank: i, ...entry }]
|
|
}
|
|
}, [])
|
|
|
|
const updateSince = (keyword) => {
|
|
setSince(keyword)
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<Header title={'Ranklista'} />
|
|
<div className={styles.container}>
|
|
<div>
|
|
<center>
|
|
<div className={'pageHeader'}>
|
|
<h1>Ranklista</h1>
|
|
</div>
|
|
</center>
|
|
<div
|
|
className={styles.infoText}
|
|
>{`A felhasználó ID-d: #${selfUserId}`}</div>
|
|
<div className={'selectContainer'}>
|
|
<div>Megjelenítés: </div>
|
|
<select
|
|
onChange={(e) => {
|
|
updateSince(e.target.value)
|
|
}}
|
|
>
|
|
{Object.keys(sinceOptions).map((key) => {
|
|
const val = sinceOptions[key]
|
|
return (
|
|
<option key={key} value={key}>
|
|
{val.name}
|
|
</option>
|
|
)
|
|
})}
|
|
</select>
|
|
</div>
|
|
<div className={'selectContainer'}>
|
|
<div>Rendezés: </div>
|
|
<select
|
|
value={key}
|
|
onChange={(e) => {
|
|
setKey(e.target.value)
|
|
}}
|
|
>
|
|
{Object.keys(selectOptions).map((key) => {
|
|
const val = selectOptions[key]
|
|
return (
|
|
<option key={key} value={key}>
|
|
{val.name}
|
|
</option>
|
|
)
|
|
})}
|
|
</select>
|
|
</div>
|
|
<div className={'checkbContainer'}>
|
|
<div>Saját hely mutatása felül:</div>
|
|
<input
|
|
type="checkbox"
|
|
checked={ownEntryOnTop}
|
|
onChange={(e) => {
|
|
setOwnEntryOnTop(e.target.checked)
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
{sum && list ? (
|
|
<>
|
|
<div className={`${styles.sumRow}`}>
|
|
<div />
|
|
<div>
|
|
<b>{'Összesen: '}</b>
|
|
</div>
|
|
<div>{sum.newQuestions.toLocaleString()}</div>
|
|
<div>{sum.allQuestions.toLocaleString()}</div>
|
|
<div>{sum.count.toLocaleString()}</div>
|
|
</div>
|
|
<div className={styles.headerRow}>
|
|
<div>
|
|
<b>{'Rank'}</b>
|
|
</div>
|
|
<div>{'Felhasználó ID'}</div>
|
|
{Object.keys(selectOptions).map((listKey) => {
|
|
const val = selectOptions[listKey]
|
|
return (
|
|
<div
|
|
className={`${listKey === key && styles.selected}`}
|
|
key={listKey}
|
|
>
|
|
{val.name}
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
<div className={styles.table}>
|
|
{list.map((listItem, i) => {
|
|
return (
|
|
<div
|
|
className={`${styles.row} ${
|
|
listItem.userId === selfUserId && styles.selfRow
|
|
}`}
|
|
key={i}
|
|
>
|
|
<div>{listItem.rank + 1}</div>
|
|
<div>{'#' + listItem.userId}</div>
|
|
{Object.keys(selectOptions).map((listKey) => {
|
|
const val = listItem[listKey]
|
|
return <div key={listKey}>{val}</div>
|
|
})}
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
</>
|
|
) : isEmpty ? (
|
|
<div style={{ textAlign: 'center', padding: 20 }}>
|
|
A ranklista üres
|
|
</div>
|
|
) : (
|
|
<LoadingIndicator />
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|