mirror of
https://github.com/evroon/bracket.git
synced 2026-03-05 07:36:56 -05:00
Show modal when activating stages (#897)
This commit is contained in:
@@ -96,7 +96,7 @@ def determine_ranking_for_stage_item(
|
||||
return team_x_stats
|
||||
|
||||
|
||||
async def determine_team_ranking_for_stage_item(
|
||||
def determine_team_ranking_for_stage_item(
|
||||
stage_item: StageItemWithRounds,
|
||||
ranking: Ranking,
|
||||
) -> list[tuple[TeamId, TeamStatistics]]:
|
||||
|
||||
@@ -3,9 +3,9 @@ from bracket.logic.ranking.elo import (
|
||||
)
|
||||
from bracket.logic.ranking.statistics import TeamStatistics
|
||||
from bracket.models.db.match import MatchWithDetails
|
||||
from bracket.models.db.util import StageWithStageItems
|
||||
from bracket.sql.matches import sql_get_match, sql_update_team_ids_for_match
|
||||
from bracket.sql.rankings import get_ranking_for_stage_item
|
||||
from bracket.sql.stage_items import get_stage_item
|
||||
from bracket.sql.stages import get_full_tournament_details
|
||||
from bracket.utils.id_types import MatchId, StageId, StageItemId, TeamId, TournamentId
|
||||
from bracket.utils.types import assert_some
|
||||
@@ -65,16 +65,12 @@ async def set_team_ids_for_match(
|
||||
await sql_update_team_ids_for_match(assert_some(match.id), team1_id, team2_id)
|
||||
|
||||
|
||||
async def get_team_rankings_lookup(tournament_id: TournamentId) -> StageItemXTeamRanking:
|
||||
stages = await get_full_tournament_details(tournament_id)
|
||||
|
||||
stage_items = {
|
||||
stage_item.id: assert_some(await get_stage_item(tournament_id, stage_item.id))
|
||||
for stage in stages
|
||||
for stage_item in stage.stage_items
|
||||
}
|
||||
async def get_team_rankings_lookup_for_stage(
|
||||
tournament_id: TournamentId, stage: StageWithStageItems
|
||||
) -> StageItemXTeamRanking:
|
||||
stage_items = {stage_item.id: stage_item for stage_item in stage.stage_items}
|
||||
return {
|
||||
stage_item_id: await determine_team_ranking_for_stage_item(
|
||||
stage_item_id: determine_team_ranking_for_stage_item(
|
||||
stage_item,
|
||||
assert_some(await get_ranking_for_stage_item(tournament_id, stage_item.id)),
|
||||
)
|
||||
@@ -82,6 +78,16 @@ async def get_team_rankings_lookup(tournament_id: TournamentId) -> StageItemXTea
|
||||
}
|
||||
|
||||
|
||||
async def get_team_rankings_lookup(tournament_id: TournamentId) -> StageItemXTeamRanking:
|
||||
return {
|
||||
stage_item_id: team_ranking
|
||||
for stage in await get_full_tournament_details(tournament_id)
|
||||
for stage_item_id, team_ranking in (
|
||||
await get_team_rankings_lookup_for_stage(tournament_id, stage)
|
||||
).items()
|
||||
}
|
||||
|
||||
|
||||
async def update_matches_in_activated_stage(tournament_id: TournamentId, stage_id: StageId) -> None:
|
||||
[stage] = await get_full_tournament_details(tournament_id, stage_id=stage_id)
|
||||
stage_item_x_team_rankings = await get_team_rankings_lookup(tournament_id)
|
||||
|
||||
@@ -2,11 +2,11 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||
from starlette import status
|
||||
|
||||
from bracket.database import database
|
||||
from bracket.logic.ranking.elo import (
|
||||
determine_team_ranking_for_stage_item,
|
||||
)
|
||||
from bracket.logic.scheduling.builder import determine_available_inputs
|
||||
from bracket.logic.scheduling.handle_stage_activation import update_matches_in_activated_stage
|
||||
from bracket.logic.scheduling.handle_stage_activation import (
|
||||
get_team_rankings_lookup_for_stage,
|
||||
update_matches_in_activated_stage,
|
||||
)
|
||||
from bracket.logic.subscriptions import check_requirement
|
||||
from bracket.models.db.stage import Stage, StageActivateBody, StageUpdateBody
|
||||
from bracket.models.db.user import UserPublic
|
||||
@@ -22,8 +22,6 @@ from bracket.routes.models import (
|
||||
SuccessResponse,
|
||||
)
|
||||
from bracket.routes.util import stage_dependency
|
||||
from bracket.sql.rankings import get_ranking_for_stage_item
|
||||
from bracket.sql.stage_items import get_stage_item
|
||||
from bracket.sql.stages import (
|
||||
get_full_tournament_details,
|
||||
get_next_stage_in_tournament,
|
||||
@@ -33,7 +31,6 @@ from bracket.sql.stages import (
|
||||
)
|
||||
from bracket.sql.teams import get_teams_with_members
|
||||
from bracket.utils.id_types import StageId, TournamentId
|
||||
from bracket.utils.types import assert_some
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -158,17 +155,4 @@ async def get_rankings(
|
||||
Get the rankings for the stage items in this stage.
|
||||
"""
|
||||
[stage] = await get_full_tournament_details(tournament_id, stage_id=stage_id)
|
||||
|
||||
stage_items = {
|
||||
stage_item.id: assert_some(await get_stage_item(tournament_id, stage_item.id))
|
||||
for stage_item in stage.stage_items
|
||||
}
|
||||
stage_item_x_ranking = {
|
||||
stage_item_id: await determine_team_ranking_for_stage_item(
|
||||
stage_item,
|
||||
assert_some(await get_ranking_for_stage_item(tournament_id, stage_item.id)),
|
||||
)
|
||||
for stage_item_id, stage_item in stage_items.items()
|
||||
}
|
||||
|
||||
return StageRankingResponse(data=stage_item_x_ranking)
|
||||
return StageRankingResponse(data=await get_team_rankings_lookup_for_stage(tournament_id, stage))
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
"active_next_round_modal_choose_option_checked": "Adjust the start times of the next matches to start immediately(now). This will be done by modifying the margin times of the matches in the previous round.",
|
||||
"active_next_round_modal_choose_option_unchecked": "Use default timing (the next matches will be planned tightly after the matches of the active round end, taking margin into account)",
|
||||
"active_next_round_modal_description": "This will assign times and courts to matches of next round, which is the round after the current activated (green) round.",
|
||||
"active_next_stage_modal_description": "This will start the next stage. Teams will be automatically assigned to the matches.",
|
||||
"plan_next_stage_button": "Start the next stage",
|
||||
"active_next_stage_modal_title": "Start the next stage",
|
||||
"active_previous_stage_modal_description": "Are you sure you want to go back to the previous stage? Match results will be discarded.",
|
||||
"plan_previous_stage_button": "Go back to the previous stage",
|
||||
"active_previous_stage_modal_title": "Go back to the previous stage",
|
||||
"active_next_round_modal_title": "Assign times and courts to matches of next round",
|
||||
"active_player_checkbox_label": "This player is active",
|
||||
"active_players_checkbox_label": "These players are active",
|
||||
|
||||
@@ -255,7 +255,7 @@ export default function Builder({
|
||||
|
||||
const button = (
|
||||
<Stack miw="24rem" align="top" key={-1}>
|
||||
<h4>
|
||||
<h4 style={{ marginTop: '0rem' }}>
|
||||
<CreateStageButton tournament={tournament} swrStagesResponse={swrStagesResponse} />
|
||||
</h4>
|
||||
</Stack>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Button } from '@mantine/core';
|
||||
import { IconSquareArrowLeft, IconSquareArrowRight } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import React from 'react';
|
||||
|
||||
import { activateNextStage } from '../../services/stage';
|
||||
|
||||
export function NextStageButton({ tournamentData, swrStagesResponse }: any) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Button
|
||||
size="md"
|
||||
mb="10"
|
||||
color="indigo"
|
||||
leftSection={<IconSquareArrowRight size={24} />}
|
||||
onClick={async () => {
|
||||
await activateNextStage(tournamentData.id, 'next');
|
||||
swrStagesResponse.mutate();
|
||||
}}
|
||||
>
|
||||
{t('next_stage_button')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export function PreviousStageButton({ tournamentData, swrStagesResponse }: any) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="md"
|
||||
mb="10"
|
||||
color="indigo"
|
||||
leftSection={<IconSquareArrowLeft size={24} />}
|
||||
onClick={async () => {
|
||||
await activateNextStage(tournamentData.id, 'previous');
|
||||
swrStagesResponse.mutate();
|
||||
}}
|
||||
>
|
||||
{t('previous_stage_button')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
69
frontend/src/components/modals/activate_next_stage_modal.tsx
Normal file
69
frontend/src/components/modals/activate_next_stage_modal.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Alert, Button, Modal } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { IconAlertCircle, IconSquareArrowRight } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import React, { useState } from 'react';
|
||||
import { SWRResponse } from 'swr';
|
||||
|
||||
import { activateNextStage } from '../../services/stage';
|
||||
|
||||
export default function ActivateNextStageModal({
|
||||
tournamentId,
|
||||
swrStagesResponse,
|
||||
}: {
|
||||
tournamentId: number;
|
||||
swrStagesResponse: SWRResponse;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
opened={opened}
|
||||
onClose={() => setOpened(false)}
|
||||
title={t('active_next_stage_modal_title')}
|
||||
size="40rem"
|
||||
>
|
||||
<form
|
||||
onSubmit={form.onSubmit(async () => {
|
||||
await activateNextStage(tournamentId, 'next');
|
||||
swrStagesResponse.mutate();
|
||||
setOpened(false);
|
||||
})}
|
||||
>
|
||||
<Alert icon={<IconAlertCircle size={16} />} color="gray" radius="lg">
|
||||
{t('active_next_stage_modal_description')}
|
||||
</Alert>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
color="indigo"
|
||||
size="md"
|
||||
mt="lg"
|
||||
type="submit"
|
||||
leftSection={<IconSquareArrowRight size={24} />}
|
||||
>
|
||||
{t('plan_next_stage_button')}
|
||||
</Button>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<Button
|
||||
size="md"
|
||||
mb="10"
|
||||
color="indigo"
|
||||
leftSection={<IconSquareArrowRight size={24} />}
|
||||
onClick={async () => {
|
||||
setOpened(true);
|
||||
}}
|
||||
>
|
||||
{t('next_stage_button')}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { Alert, Button, Modal } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { IconAlertCircle, IconSquareArrowLeft } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import React, { useState } from 'react';
|
||||
import { SWRResponse } from 'swr';
|
||||
|
||||
import { activateNextStage } from '../../services/stage';
|
||||
|
||||
export default function ActivatePreviousStageModal({
|
||||
tournamentId,
|
||||
swrStagesResponse,
|
||||
}: {
|
||||
tournamentId: number;
|
||||
swrStagesResponse: SWRResponse;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
const form = useForm({
|
||||
initialValues: {},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
opened={opened}
|
||||
onClose={() => setOpened(false)}
|
||||
title={t('active_previous_stage_modal_title')}
|
||||
size="40rem"
|
||||
>
|
||||
<form
|
||||
onSubmit={form.onSubmit(async () => {
|
||||
await activateNextStage(tournamentId, 'previous');
|
||||
swrStagesResponse.mutate();
|
||||
setOpened(false);
|
||||
})}
|
||||
>
|
||||
<Alert icon={<IconAlertCircle size={16} />} color="orange" radius="lg">
|
||||
{t('active_previous_stage_modal_description')}
|
||||
</Alert>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
color="indigo"
|
||||
size="md"
|
||||
mt="lg"
|
||||
type="submit"
|
||||
leftSection={<IconSquareArrowLeft size={24} />}
|
||||
>
|
||||
{t('plan_previous_stage_button')}
|
||||
</Button>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
<Button
|
||||
size="md"
|
||||
mb="10"
|
||||
color="indigo"
|
||||
leftSection={<IconSquareArrowLeft size={24} />}
|
||||
onClick={async () => {
|
||||
setOpened(true);
|
||||
}}
|
||||
>
|
||||
{t('previous_stage_button')}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -5,10 +5,8 @@ import React from 'react';
|
||||
|
||||
import Builder from '../../../components/builder/builder';
|
||||
import { CreateStageButtonLarge } from '../../../components/buttons/create_stage';
|
||||
import {
|
||||
NextStageButton,
|
||||
PreviousStageButton,
|
||||
} from '../../../components/buttons/next_stage_button';
|
||||
import ActivateNextStageModal from '../../../components/modals/activate_next_stage_modal';
|
||||
import ActivatePreviousStageModal from '../../../components/modals/activate_previous_stage_modal';
|
||||
import { NoContent } from '../../../components/no_content/empty_table_info';
|
||||
import { TableSkeletonTwoColumnsSmall } from '../../../components/utils/skeletons';
|
||||
import { getTournamentIdFromRouter } from '../../../components/utils/util';
|
||||
@@ -47,11 +45,14 @@ export default function StagesPage() {
|
||||
content = (
|
||||
<>
|
||||
<Group grow mt="1rem" maw="30rem">
|
||||
<PreviousStageButton
|
||||
tournamentData={tournamentData}
|
||||
<ActivatePreviousStageModal
|
||||
tournamentId={tournamentData.id}
|
||||
swrStagesResponse={swrStagesResponse}
|
||||
/>
|
||||
<ActivateNextStageModal
|
||||
tournamentId={tournamentData.id}
|
||||
swrStagesResponse={swrStagesResponse}
|
||||
/>
|
||||
<NextStageButton tournamentData={tournamentData} swrStagesResponse={swrStagesResponse} />
|
||||
</Group>
|
||||
<Group mt="1rem" align="top">
|
||||
<Builder
|
||||
|
||||
Reference in New Issue
Block a user