Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

メインページに終了後・開催中・予定されたコンテストおよびユーザーのランキングの表示をした #261

Merged
merged 5 commits into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26,708 changes: 244 additions & 26,464 deletions frontend/package-lock.json

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions frontend/src/components/ContestTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { VFC } from 'react';
import Table from 'react-bootstrap/Table';
import { Link } from 'react-router-dom';
import { ContestInfo } from '../types';

type Props = { contests: ContestInfo[] | null };

export const ContestTable: VFC<Props> = ({ contests }) => {
return (
<>
<Table bordered hover size="sm" striped>
<thead>
<tr>
<th className="text-center">開始時刻</th>
<th className="text-center">コンテスト名</th>
<th className="text-center">種類</th>
<th className="text-center">時間</th>
<th className="text-center">Rated対象</th>
</tr>
</thead>
<tbody>
{contests?.map((contest) => (
<tr key={contest.id}>
<td className="text-center">{contest.startTimeAMPM}</td>
<td>
<Link to={`/contest/${contest.id}`}>{contest.name}</Link>
</td>
<td className="text-center">{contest.contestType}</td>
<td className="text-center">
{Math.floor(
(contest.unixEndTime - contest.unixStartTime) / (60 * 1000)
)}
</td>
<td className="text-center">
{contest.ratedBound > 0 ? `~ ${contest.ratedBound - 1}` : '-'}
</td>
</tr>
))}
</tbody>
</Table>
</>
);
};
20 changes: 17 additions & 3 deletions frontend/src/functions/HttpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
AccountInfo,
AccountRankingInfo,
ContestInfo,
LatestContestsInfo,
ContestsInfoList,
ProblemInfo,
ContestStandingsInfo,
SubmissionInfo,
Expand Down Expand Up @@ -126,8 +126,22 @@ export async function getAccountInformation(
/**
* @param page
*/
export function getLatestContests(page: number): Promise<LatestContestsInfo> {
return httpRequest<LatestContestsInfo>('/api/contests/latest', 'GET', {
export function getLatestContests(page: number): Promise<ContestsInfoList> {
return httpRequest<ContestsInfoList>('/api/contests/latest', 'GET', {
contest_page: page,
});
}

export function getUpcomingContests(): Promise<ContestsInfoList> {
return httpRequest<ContestsInfoList>('/api/contests/upcoming', 'GET');
}

export function getActiveContests(): Promise<ContestsInfoList> {
return httpRequest<ContestsInfoList>('/api/contests/active', 'GET');
}

export function getPastContests(page: number): Promise<ContestsInfoList> {
return httpRequest<ContestsInfoList>('/api/contests/past', 'GET', {
contest_page: page,
});
}
Expand Down
100 changes: 50 additions & 50 deletions frontend/src/pages/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,78 @@
import { VFC, useEffect, useState, useCallback } from 'react';
import Button from 'react-bootstrap/Button';
import Table from 'react-bootstrap/Table';
import { Link } from 'react-router-dom';
import { ContestTable } from '../components/ContestTable';
import { PagingElement } from '../components/PagingElement';
import { getLatestContests } from '../functions/HttpRequest';
import {
getUpcomingContests,
getActiveContests,
getPastContests,
} from '../functions/HttpRequest';
import { ContestInfo } from '../types';
import Ranking from './RankingPage';

// URL: /

const CONTEST_IN_ONE_PAGE = 10;

const ContestList: VFC = () => {
const [contests, setContests] = useState<ContestInfo[] | null>(null);
const [pageNum, setPageNum] = useState<number>(0);
const [currentPage, setCurrentPage] = useState(0);
const ContestList = () => {
const [upcomingContests, setUpcomingContests] = useState<
ContestInfo[] | null
>(null);
const [activeContests, setActiveContests] = useState<ContestInfo[] | null>(
null
);
const [pastContests, setPastContests] = useState<ContestInfo[] | null>(null);
const [contestPageNum, setContestPageNum] = useState<number>(0);
const [contestCurrentPage, setContestCurrentPage] = useState(0);

const updatePage = useCallback(
(newPage: number) => {
getLatestContests(newPage).then((latestContestsInfo) => {
setContests(latestContestsInfo.contests);
setCurrentPage(newPage);
const updateContestPage = useCallback(
(page) => {
getPastContests(page).then((pastContestsInfo) => {
setPastContests(pastContestsInfo.contests);
setContestCurrentPage(page);
});
},
[pageNum]
[contestPageNum]
);

useEffect(() => {
getLatestContests(0).then((latestContestsInfo) => {
setPageNum(
Math.ceil(latestContestsInfo.allContestNum / CONTEST_IN_ONE_PAGE)
getUpcomingContests().then((upcomingContestsInfo) => {
setUpcomingContests(upcomingContestsInfo.contests);
});

getActiveContests().then((activeContestsInfo) => {
setActiveContests(activeContestsInfo.contests);
});

getPastContests(0).then((pastContestsInfo) => {
setContestPageNum(
Math.ceil(pastContestsInfo.allContestNum / CONTEST_IN_ONE_PAGE)
);
setContests(latestContestsInfo.contests);
setPastContests(pastContestsInfo.contests);
});
}, []);

return (
<>
<Table bordered hover size="sm" striped>
<thead>
<tr>
<th className="text-center">開始時刻</th>
<th className="text-center">コンテスト名</th>
<th className="text-center">種類</th>
<th className="text-center">時間</th>
<th className="text-center">Rated対象</th>
</tr>
</thead>
<tbody>
{contests?.map((contest) => (
<tr key={contest.id}>
<td className="text-center">{contest.startTimeAMPM}</td>
<td>
<Link to={`/contest/${contest.id}`}>{contest.name}</Link>
</td>
<td className="text-center">{contest.contestType}</td>
<td className="text-center">
{Math.floor(
(contest.unixEndTime - contest.unixStartTime) / (60 * 1000)
)}
</td>
<td className="text-center">
{contest.ratedBound > 0 ? `~ ${contest.ratedBound - 1}` : '-'}
</td>
</tr>
))}
</tbody>
</Table>
<h2>開催中のコンテスト</h2>
{activeContests && activeContests.length > 0 ? (
<ContestTable contests={activeContests} />
) : (
<div>現在開催中のコンテストはありません</div>
)}
<h2>予定されたコンテスト</h2>
<ContestTable contests={upcomingContests} />
<h2>終了したコンテスト</h2>
<ContestTable contests={pastContests} />
<PagingElement
currentPage={currentPage}
onChange={updatePage}
currentPage={contestCurrentPage}
onChange={updateContestPage}
savePaging={true}
totalPages={pageNum}
totalPages={contestPageNum}
/>
<h2>ランキング</h2>
<Ranking />
<Link to={'/ranking'}>
<Button variant={'primary'}>順位表へ</Button>
</Link>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export interface ContestInfo {
contestCreators: ContestCreator[];
}

export interface LatestContestsInfo {
export interface ContestsInfoList {
contests: ContestInfo[];
allContestNum: number;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,25 @@ class ContestController(
}

@GetMapping("api/contests/latest")
fun getLatestContestsInfoResponse(@RequestParam("contest_page") contestPage: Int): LatestContestsInfo {
fun getLatestContestsInfoResponse(@RequestParam("contest_page") contestPage: Int): ContestInfoList {
return contestService.getLatestContestsInfo(contestPage)
}

@GetMapping("api/contests/upcoming")
fun getUpcomingContestsInfoResponse(): ContestInfoList {
return contestService.getUpcomingContestsInfo()
}

@GetMapping("api/contests/active")
fun getActiveContestsInfoResponse(): ContestInfoList {
return contestService.getActiveContestsInfo()
}

@GetMapping("api/contests/past")
fun getPastContestsInfoResponse(@RequestParam("contest_page") contestPage: Int): ContestInfoList {
return contestService.getPastContestsInfo(contestPage)
}

@PostMapping("api/contests", headers = ["Content-Type=application/json"])
fun addContestResponse(
@RequestBody requestContest: RequestContestInfoForUpdate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ class ContestRepository(val jdbcTemplate: JdbcTemplate) {
FROM contestInfo ORDER BY startTime desc LIMIT ? OFFSET ?""",
rowMapperForContestInfo, LATEST_CONTEST_PAGE_SIZE, page * LATEST_CONTEST_PAGE_SIZE)
}
fun findUpcomingContest(): List<ContestInfo> {
return jdbcTemplate.query("""
SELECT id, name, statement, startTime, endTime, contestType, ratedBound , penalty, ratingCalculated
FROM contestInfo where startTime > now() ORDER BY startTime desc""",
rowMapperForContestInfo)
}
fun findActiveContest(): List<ContestInfo> {
return jdbcTemplate.query("""
SELECT id, name, statement, startTime, endTime, contestType, ratedBound , penalty, ratingCalculated
FROM contestInfo where startTime < now() AND now() < endTime ORDER BY startTime desc""",
rowMapperForContestInfo)
}
fun findPastContest(page: Int): List<ContestInfo> {
return jdbcTemplate.query("""
SELECT id, name, statement, startTime, endTime, contestType, ratedBound , penalty, ratingCalculated
FROM contestInfo where now() > endTime ORDER BY startTime desc LIMIT ? OFFSET ?""",
rowMapperForContestInfo, LATEST_CONTEST_PAGE_SIZE, page * LATEST_CONTEST_PAGE_SIZE)
}
fun findContestCreators(contestId: String): List<ContestCreator> =
jdbcTemplate.query("""
SELECT accountName, contestId, position FROM contestCreator WHERE contestId = ?
Expand All @@ -66,6 +84,9 @@ class ContestRepository(val jdbcTemplate: JdbcTemplate) {
fun findAllContestNum(): Int =
jdbcTemplate.queryForObject("""SELECT count(*) from contestInfo""", Int::class.java)!!

fun findPastContestNum(): Int =
jdbcTemplate.queryForObject("""SELECT count(*) from contestInfo where now() > endTime""", Int::class.java)!!

fun addContest(contest: ContestInfo) {
jdbcTemplate.update("""
INSERT INTO contestInfo(id, name, statement, startTime, endTime, contestType, ratedBound, penalty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,30 @@ class ContestService(
fun getContestInfoByContestId(id: String): ContestInfo? =
contestRepository.findByContestId(id)

fun getLatestContestsInfo(page: Int): LatestContestsInfo {
fun getLatestContestsInfo(page: Int): ContestInfoList {
val contests = contestRepository.findLatestContest(page)
.map { ResponseContestInfoInterface.build(it) }
val allContestNum = contestRepository.findAllContestNum()
return LatestContestsInfo(contests, allContestNum)
return ContestInfoList(contests, allContestNum)
}

fun getUpcomingContestsInfo(): ContestInfoList {
val contests = contestRepository.findUpcomingContest()
.map { ResponseContestInfoInterface.build(it) }
return ContestInfoList(contests, contests.size)
}

fun getActiveContestsInfo(): ContestInfoList {
val contests = contestRepository.findActiveContest()
.map { ResponseContestInfoInterface.build(it) }
return ContestInfoList(contests, contests.size)
}

fun getPastContestsInfo(contestPage: Int): ContestInfoList {
val contests = contestRepository.findPastContest(contestPage)
.map { ResponseContestInfoInterface.build(it) }
val allContestNum = contestRepository.findPastContestNum()
return ContestInfoList(contests, allContestNum)
}

fun addContest(requestContest: RequestContestInfoForUpdate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ data class ResponseContestInfo(
override val endTimeAMPM: String
) : ResponseContestInfoInterface

data class LatestContestsInfo(
data class ContestInfoList(
val contests: List<ResponseContestInfo>,
val allContestNum: Int
)