diff --git a/backend/siarnaq/api/compete/serializers.py b/backend/siarnaq/api/compete/serializers.py index 355b4339f..a56d807f0 100644 --- a/backend/siarnaq/api/compete/serializers.py +++ b/backend/siarnaq/api/compete/serializers.py @@ -482,10 +482,15 @@ class HistoricalRatingSerializer(serializers.Serializer): class ScrimmageRecordSerializer(serializers.Serializer): + class ScrimmageRecordVariantSerializer(serializers.Serializer): + wins = serializers.IntegerField() + losses = serializers.IntegerField() + ties = serializers.IntegerField() + team_id = serializers.IntegerField() - wins = serializers.IntegerField() - losses = serializers.IntegerField() - ties = serializers.IntegerField() + Ranked = ScrimmageRecordVariantSerializer() + Unranked = ScrimmageRecordVariantSerializer() + All = ScrimmageRecordVariantSerializer() class EmptySerializer(serializers.Serializer): diff --git a/backend/siarnaq/api/compete/views.py b/backend/siarnaq/api/compete/views.py index daead198d..0d719380b 100644 --- a/backend/siarnaq/api/compete/views.py +++ b/backend/siarnaq/api/compete/views.py @@ -1,11 +1,22 @@ -from functools import reduce from typing import Optional import google.cloud.storage as storage import structlog from django.conf import settings from django.db import NotSupportedError, transaction -from django.db.models import Exists, OuterRef, Q, Subquery +from django.db.models import ( + Case, + Exists, + F, + IntegerField, + OuterRef, + Q, + Subquery, + Sum, + Value, + When, +) +from django.db.models.functions import Coalesce from django.utils import timezone from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema from rest_framework import mixins, status, viewsets @@ -615,12 +626,6 @@ def historical_rating_topN(self, request, pk=None, *, episode_id): type=int, description="A team to filter for. Defaults to your own team.", ), - OpenApiParameter( - name="scrimmage_type", - enum=["ranked", "unranked", "all"], - default="all", - description="Which type of scrimmages to filter for. Defaults to all.", - ), ], responses={ status.HTTP_200_OK: ScrimmageRecordSerializer(), @@ -635,64 +640,164 @@ def historical_rating_topN(self, request, pk=None, *, episode_id): permission_classes=(IsEpisodeMutable,), ) def scrimmaging_record(self, request, pk=None, *, episode_id): - """List the scrimmaging win-loss-tie record of a team.""" - queryset = self.get_queryset().filter(tournament_round__isnull=True) + """ + Retrieve the scrimmaging win-loss-tie record for a team. - scrimmage_type = self.request.query_params.get("scrimmage_type") - if scrimmage_type is not None: - if scrimmage_type == "ranked": - queryset = queryset.filter(is_ranked=True) - elif scrimmage_type == "unranked": - queryset = queryset.filter(is_ranked=False) + Returns a JSON object containing the team's record in ranked, + unranked, and overall matches. + The record is broken down into wins, losses, and ties for each category. - team_id = parse_int(self.request.query_params.get("team_id")) + Query Parameters: + - team_id (optional): ID of the team to retrieve the record for. + If not provided, uses the authenticated user's team. + + Returns: + - 200 OK: Successfully retrieved the team's scrimmaging record. + - 400 Bad Request: If no team_id is provided and the user is not associated + with a team, or if the provided team_id is invalid. + """ + team_id = parse_int(request.query_params.get("team_id")) if team_id is None and request.user.pk is not None: user_team = Team.objects.filter( members__pk=request.user.pk, episode_id=episode_id - ) + ).first() - if not user_team.exists(): + if not user_team: return Response(status=status.HTTP_400_BAD_REQUEST) - else: - team_id = user_team.get().id - - if team_id is not None: - queryset = queryset.filter(participants__team=team_id) - else: + team_id = user_team.id + elif team_id is None: return Response(status=status.HTTP_400_BAD_REQUEST) - has_invisible = self.get_queryset().filter( - participants__team__status=TeamStatus.INVISIBLE + + queryset = ( + self.get_queryset() + .filter(tournament_round__isnull=True, participants__team_id=team_id) + .exclude(participants__team__status=TeamStatus.INVISIBLE) ) - queryset = queryset.exclude(pk__in=Subquery(has_invisible.values("pk"))) - - def match_handler(record, match): - """Mutate the win-loss-tie record based on the match outcome.""" - this_team = match.participants.filter(team=team_id).first() - other_team = match.participants.exclude(team=team_id).first() - if this_team is None or other_team is None: - return record - if this_team.score is None or other_team.score is None: - return record - if this_team.score > other_team.score: - record["wins"] += 1 - elif this_team.score < other_team.score: - record["losses"] += 1 - else: - record["ties"] += 1 - return record - win_loss_tie = reduce( - match_handler, - queryset.all(), - { - "team_id": team_id, - "wins": 0, - "losses": 0, - "ties": 0, - }, + # Annotate the queryset to perform logic on the database side + results = queryset.annotate( + this_team_score=Sum( + Case( + When(participants__team_id=team_id, then="participants__score"), + default=Value(0), + output_field=IntegerField(), + ) + ), + other_team_score=Sum( + Case( + When(~Q(participants__team_id=team_id), then="participants__score"), + default=Value(0), + output_field=IntegerField(), + ) + ), + ).aggregate( + ranked_wins=Coalesce( + Sum( + Case( + When( + Q(this_team_score__gt=F("other_team_score")) + & Q(is_ranked=True), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), + ranked_losses=Coalesce( + Sum( + Case( + When( + Q(this_team_score__lt=F("other_team_score")) + & Q(is_ranked=True), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), + ranked_ties=Coalesce( + Sum( + Case( + When( + Q(this_team_score=F("other_team_score")) + & Q(is_ranked=True), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), + unranked_wins=Coalesce( + Sum( + Case( + When( + Q(this_team_score__gt=F("other_team_score")) + & Q(is_ranked=False), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), + unranked_losses=Coalesce( + Sum( + Case( + When( + Q(this_team_score__lt=F("other_team_score")) + & Q(is_ranked=False), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), + unranked_ties=Coalesce( + Sum( + Case( + When( + Q(this_team_score=F("other_team_score")) + & Q(is_ranked=False), + then=1, + ), + default=0, + output_field=IntegerField(), + ) + ), + 0, + ), ) - results = ScrimmageRecordSerializer(win_loss_tie).data - return Response(results, status=status.HTTP_200_OK) + + win_loss_tie = { + "team_id": team_id, + "Ranked": { + "wins": results["ranked_wins"], + "losses": results["ranked_losses"], + "ties": results["ranked_ties"], + }, + "Unranked": { + "wins": results["unranked_wins"], + "losses": results["unranked_losses"], + "ties": results["unranked_ties"], + }, + "All": { + "wins": results["ranked_wins"] + results["unranked_wins"], + "losses": results["ranked_losses"] + results["unranked_losses"], + "ties": results["ranked_ties"] + results["unranked_ties"], + }, + } + + serialized_results = ScrimmageRecordSerializer(win_loss_tie).data + return Response(serialized_results, status=status.HTTP_200_OK) @extend_schema( responses={ diff --git a/frontend/schema.yml b/frontend/schema.yml index be219e591..5bc3ae33e 100644 --- a/frontend/schema.yml +++ b/frontend/schema.yml @@ -275,7 +275,21 @@ paths: /api/compete/{episode_id}/match/scrimmaging_record/: get: operationId: compete_match_scrimmaging_record_retrieve - description: List the scrimmaging win-loss-tie record of a team. + description: |- + Retrieve the scrimmaging win-loss-tie record for a team. + + Returns a JSON object containing the team's record in ranked, + unranked, and overall matches. + The record is broken down into wins, losses, and ties for each category. + + Query Parameters: + - team_id (optional): ID of the team to retrieve the record for. + If not provided, uses the authenticated user's team. + + Returns: + - 200 OK: Successfully retrieved the team's scrimmaging record. + - 400 Bad Request: If no team_id is provided and the user is not associated + with a team, or if the provided team_id is invalid. parameters: - in: path name: episode_id @@ -283,16 +297,6 @@ paths: type: string pattern: ^[^\/.]+$ required: true - - in: query - name: scrimmage_type - schema: - type: string - enum: - - all - - ranked - - unranked - default: all - description: Which type of scrimmages to filter for. Defaults to all. - in: query name: team_id schema: @@ -2308,6 +2312,7 @@ components: LanguageEnum: enum: - java8 + - java21 - py3 type: string Match: @@ -2674,6 +2679,20 @@ components: properties: team_id: type: integer + Ranked: + $ref: "#/components/schemas/ScrimmageRecordVariant" + Unranked: + $ref: "#/components/schemas/ScrimmageRecordVariant" + All: + $ref: "#/components/schemas/ScrimmageRecordVariant" + required: + - All + - Ranked + - Unranked + - team_id + ScrimmageRecordVariant: + type: object + properties: wins: type: integer losses: @@ -2682,7 +2701,6 @@ components: type: integer required: - losses - - team_id - ties - wins ScrimmageRequest: diff --git a/frontend/src/api/_autogen/.openapi-generator/FILES b/frontend/src/api/_autogen/.openapi-generator/FILES index 6d90c6e7f..6cff9ae81 100644 --- a/frontend/src/api/_autogen/.openapi-generator/FILES +++ b/frontend/src/api/_autogen/.openapi-generator/FILES @@ -40,6 +40,7 @@ models/ResetToken.ts models/ResetTokenRequest.ts models/SaturnInvocationRequest.ts models/ScrimmageRecord.ts +models/ScrimmageRecordVariant.ts models/ScrimmageRequest.ts models/ScrimmageRequestRequest.ts models/ScrimmageStatusEnum.ts diff --git a/frontend/src/api/_autogen/apis/CompeteApi.ts b/frontend/src/api/_autogen/apis/CompeteApi.ts index 89520455e..bded95392 100644 --- a/frontend/src/api/_autogen/apis/CompeteApi.ts +++ b/frontend/src/api/_autogen/apis/CompeteApi.ts @@ -102,7 +102,6 @@ export interface CompeteMatchScrimmageListRequest { export interface CompeteMatchScrimmagingRecordRetrieveRequest { episodeId: string; - scrimmageType?: CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum; teamId?: number; } @@ -527,7 +526,7 @@ export class CompeteApi extends runtime.BaseAPI { } /** - * List the scrimmaging win-loss-tie record of a team. + * Retrieve the scrimmaging win-loss-tie record for a team. Returns a JSON object containing the team\'s record in ranked, unranked, and overall matches. The record is broken down into wins, losses, and ties for each category. Query Parameters: - team_id (optional): ID of the team to retrieve the record for. If not provided, uses the authenticated user\'s team. Returns: - 200 OK: Successfully retrieved the team\'s scrimmaging record. - 400 Bad Request: If no team_id is provided and the user is not associated with a team, or if the provided team_id is invalid. */ async competeMatchScrimmagingRecordRetrieveRaw(requestParameters: CompeteMatchScrimmagingRecordRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { if (requestParameters.episodeId === null || requestParameters.episodeId === undefined) { @@ -536,10 +535,6 @@ export class CompeteApi extends runtime.BaseAPI { const queryParameters: any = {}; - if (requestParameters.scrimmageType !== undefined) { - queryParameters['scrimmage_type'] = requestParameters.scrimmageType; - } - if (requestParameters.teamId !== undefined) { queryParameters['team_id'] = requestParameters.teamId; } @@ -565,7 +560,7 @@ export class CompeteApi extends runtime.BaseAPI { } /** - * List the scrimmaging win-loss-tie record of a team. + * Retrieve the scrimmaging win-loss-tie record for a team. Returns a JSON object containing the team\'s record in ranked, unranked, and overall matches. The record is broken down into wins, losses, and ties for each category. Query Parameters: - team_id (optional): ID of the team to retrieve the record for. If not provided, uses the authenticated user\'s team. Returns: - 200 OK: Successfully retrieved the team\'s scrimmaging record. - 400 Bad Request: If no team_id is provided and the user is not associated with a team, or if the provided team_id is invalid. */ async competeMatchScrimmagingRecordRetrieve(requestParameters: CompeteMatchScrimmagingRecordRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { const response = await this.competeMatchScrimmagingRecordRetrieveRaw(requestParameters, initOverrides); @@ -1162,13 +1157,3 @@ export class CompeteApi extends runtime.BaseAPI { } } - -/** - * @export - * @enum {string} - */ -export enum CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum { - All = 'all', - Ranked = 'ranked', - Unranked = 'unranked' -} diff --git a/frontend/src/api/_autogen/models/LanguageEnum.ts b/frontend/src/api/_autogen/models/LanguageEnum.ts index 352b481ee..812703495 100644 --- a/frontend/src/api/_autogen/models/LanguageEnum.ts +++ b/frontend/src/api/_autogen/models/LanguageEnum.ts @@ -19,6 +19,7 @@ */ export enum LanguageEnum { Java8 = 'java8', + Java21 = 'java21', Py3 = 'py3' } diff --git a/frontend/src/api/_autogen/models/ScrimmageRecord.ts b/frontend/src/api/_autogen/models/ScrimmageRecord.ts index 4f14a9526..c569be777 100644 --- a/frontend/src/api/_autogen/models/ScrimmageRecord.ts +++ b/frontend/src/api/_autogen/models/ScrimmageRecord.ts @@ -13,6 +13,13 @@ */ import { exists, mapValues } from '../runtime'; +import type { ScrimmageRecordVariant } from './ScrimmageRecordVariant'; +import { + ScrimmageRecordVariantFromJSON, + ScrimmageRecordVariantFromJSONTyped, + ScrimmageRecordVariantToJSON, +} from './ScrimmageRecordVariant'; + /** * * @export @@ -27,22 +34,22 @@ export interface ScrimmageRecord { team_id: number; /** * - * @type {number} + * @type {ScrimmageRecordVariant} * @memberof ScrimmageRecord */ - wins: number; + Ranked: ScrimmageRecordVariant; /** * - * @type {number} + * @type {ScrimmageRecordVariant} * @memberof ScrimmageRecord */ - losses: number; + Unranked: ScrimmageRecordVariant; /** * - * @type {number} + * @type {ScrimmageRecordVariant} * @memberof ScrimmageRecord */ - ties: number; + All: ScrimmageRecordVariant; } /** @@ -51,9 +58,9 @@ export interface ScrimmageRecord { export function instanceOfScrimmageRecord(value: object): boolean { let isInstance = true; isInstance = isInstance && "team_id" in value; - isInstance = isInstance && "wins" in value; - isInstance = isInstance && "losses" in value; - isInstance = isInstance && "ties" in value; + isInstance = isInstance && "Ranked" in value; + isInstance = isInstance && "Unranked" in value; + isInstance = isInstance && "All" in value; return isInstance; } @@ -69,9 +76,9 @@ export function ScrimmageRecordFromJSONTyped(json: any, ignoreDiscriminator: boo return { 'team_id': json['team_id'], - 'wins': json['wins'], - 'losses': json['losses'], - 'ties': json['ties'], + 'Ranked': ScrimmageRecordVariantFromJSON(json['Ranked']), + 'Unranked': ScrimmageRecordVariantFromJSON(json['Unranked']), + 'All': ScrimmageRecordVariantFromJSON(json['All']), }; } @@ -85,9 +92,9 @@ export function ScrimmageRecordToJSON(value?: ScrimmageRecord | null): any { return { 'team_id': value.team_id, - 'wins': value.wins, - 'losses': value.losses, - 'ties': value.ties, + 'Ranked': ScrimmageRecordVariantToJSON(value.Ranked), + 'Unranked': ScrimmageRecordVariantToJSON(value.Unranked), + 'All': ScrimmageRecordVariantToJSON(value.All), }; } diff --git a/frontend/src/api/_autogen/models/ScrimmageRecordVariant.ts b/frontend/src/api/_autogen/models/ScrimmageRecordVariant.ts new file mode 100644 index 000000000..8b19c96fb --- /dev/null +++ b/frontend/src/api/_autogen/models/ScrimmageRecordVariant.ts @@ -0,0 +1,84 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface ScrimmageRecordVariant + */ +export interface ScrimmageRecordVariant { + /** + * + * @type {number} + * @memberof ScrimmageRecordVariant + */ + wins: number; + /** + * + * @type {number} + * @memberof ScrimmageRecordVariant + */ + losses: number; + /** + * + * @type {number} + * @memberof ScrimmageRecordVariant + */ + ties: number; +} + +/** + * Check if a given object implements the ScrimmageRecordVariant interface. + */ +export function instanceOfScrimmageRecordVariant(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "wins" in value; + isInstance = isInstance && "losses" in value; + isInstance = isInstance && "ties" in value; + + return isInstance; +} + +export function ScrimmageRecordVariantFromJSON(json: any): ScrimmageRecordVariant { + return ScrimmageRecordVariantFromJSONTyped(json, false); +} + +export function ScrimmageRecordVariantFromJSONTyped(json: any, ignoreDiscriminator: boolean): ScrimmageRecordVariant { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'wins': json['wins'], + 'losses': json['losses'], + 'ties': json['ties'], + }; +} + +export function ScrimmageRecordVariantToJSON(value?: ScrimmageRecordVariant | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'wins': value.wins, + 'losses': value.losses, + 'ties': value.ties, + }; +} + diff --git a/frontend/src/api/_autogen/models/index.ts b/frontend/src/api/_autogen/models/index.ts index 804ff76c7..2e7d2a98d 100644 --- a/frontend/src/api/_autogen/models/index.ts +++ b/frontend/src/api/_autogen/models/index.ts @@ -33,6 +33,7 @@ export * from './ResetToken'; export * from './ResetTokenRequest'; export * from './SaturnInvocationRequest'; export * from './ScrimmageRecord'; +export * from './ScrimmageRecordVariant'; export * from './ScrimmageRequest'; export * from './ScrimmageRequestRequest'; export * from './ScrimmageStatusEnum'; diff --git a/frontend/src/api/apiTypes.ts b/frontend/src/api/apiTypes.ts index 53e74b189..9e538437c 100644 --- a/frontend/src/api/apiTypes.ts +++ b/frontend/src/api/apiTypes.ts @@ -66,6 +66,12 @@ export enum GenderEnum { export type Gender = `${GenderEnum}`; +export enum ScrimmageTypeEnum { + ALL = "All", + RANKED = "Ranked", + UNRANKED = "Unranked", +} + export const COUNTRIES: Record = { US: "United States of America", CA: "Canada", diff --git a/frontend/src/api/compete/competeApi.ts b/frontend/src/api/compete/competeApi.ts index c70ad4f2f..12e116f7c 100644 --- a/frontend/src/api/compete/competeApi.ts +++ b/frontend/src/api/compete/competeApi.ts @@ -244,15 +244,12 @@ export const getRatingHistory = async ({ * Defaults to all scrimmage types. * @param episodeId The episode ID to retrieve record data for. * @param teamId The team ID to retrieve record data for. - * @param scrimmageType The type of scrimmage to retrieve record data for. */ export const getScrimmagingRecord = async ({ episodeId, teamId, - scrimmageType, }: CompeteMatchScrimmagingRecordRetrieveRequest): Promise => await API.competeMatchScrimmagingRecordRetrieve({ episodeId, teamId, - scrimmageType, }); diff --git a/frontend/src/api/compete/competeFactories.ts b/frontend/src/api/compete/competeFactories.ts index 76ff2af74..d37a3420e 100644 --- a/frontend/src/api/compete/competeFactories.ts +++ b/frontend/src/api/compete/competeFactories.ts @@ -240,6 +240,6 @@ export const scrimmagingRecordFactory: QueryFactory< ScrimmageRecord > = { queryKey: competeQueryKeys.scrimmagingRecord, - queryFn: async ({ episodeId, teamId, scrimmageType }) => - await getScrimmagingRecord({ episodeId, teamId, scrimmageType }), + queryFn: async ({ episodeId, teamId }) => + await getScrimmagingRecord({ episodeId, teamId }), } as const; diff --git a/frontend/src/api/compete/useCompete.ts b/frontend/src/api/compete/useCompete.ts index d168872da..f784e0d82 100644 --- a/frontend/src/api/compete/useCompete.ts +++ b/frontend/src/api/compete/useCompete.ts @@ -256,19 +256,16 @@ export const useUserRatingHistory = ({ export const useScrimmagingRecord = ({ episodeId, teamId, - scrimmageType, }: CompeteMatchScrimmagingRecordRetrieveRequest): UseQueryResult => useQuery({ queryKey: buildKey(scrimmagingRecordFactory.queryKey, { episodeId, teamId, - scrimmageType, }), queryFn: async () => await scrimmagingRecordFactory.queryFn({ episodeId, teamId, - scrimmageType, }), staleTime: MILLIS_SECOND * SECONDS_MINUTE * STATISTICS_WAIT_MINUTES, }); diff --git a/frontend/src/api/loaders/accountLoader.ts b/frontend/src/api/loaders/accountLoader.ts index 2b976153b..5ab810502 100644 --- a/frontend/src/api/loaders/accountLoader.ts +++ b/frontend/src/api/loaders/accountLoader.ts @@ -1,5 +1,4 @@ import type { QueryClient } from "@tanstack/react-query"; -import { CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum } from "api/_autogen"; import { scrimmagingRecordFactory } from "api/compete/competeFactories"; import { safeEnsureQueryData } from "api/helpers"; import type { LoaderFunction } from "react-router-dom"; @@ -15,8 +14,6 @@ export const accountLoader = safeEnsureQueryData( { episodeId, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All, }, scrimmagingRecordFactory, queryClient, diff --git a/frontend/src/api/loaders/homeLoader.ts b/frontend/src/api/loaders/homeLoader.ts index 91dbb0435..453d29b91 100644 --- a/frontend/src/api/loaders/homeLoader.ts +++ b/frontend/src/api/loaders/homeLoader.ts @@ -9,7 +9,6 @@ import { userRatingHistoryFactory, scrimmagingRecordFactory, } from "api/compete/competeFactories"; -import { CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum } from "api/_autogen"; export const homeLoader = (queryClient: QueryClient): LoaderFunction => @@ -30,8 +29,6 @@ export const homeLoader = safeEnsureQueryData( { episodeId, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All, }, scrimmagingRecordFactory, queryClient, diff --git a/frontend/src/api/loaders/myTeamLoader.ts b/frontend/src/api/loaders/myTeamLoader.ts index c3dbcdb2e..a553a89c9 100644 --- a/frontend/src/api/loaders/myTeamLoader.ts +++ b/frontend/src/api/loaders/myTeamLoader.ts @@ -3,7 +3,6 @@ import type { LoaderFunction } from "react-router-dom"; import { myTeamFactory } from "../team/teamFactories"; import { safeEnsureQueryData } from "../helpers"; import { scrimmagingRecordFactory } from "api/compete/competeFactories"; -import { CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum } from "api/_autogen"; export const myTeamLoader = (queryClient: QueryClient): LoaderFunction => @@ -19,17 +18,6 @@ export const myTeamLoader = safeEnsureQueryData( { episodeId, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked, - }, - scrimmagingRecordFactory, - queryClient, - ); - safeEnsureQueryData( - { - episodeId, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked, }, scrimmagingRecordFactory, queryClient, diff --git a/frontend/src/api/loaders/scrimmagingLoader.ts b/frontend/src/api/loaders/scrimmagingLoader.ts index 0201410af..ba63f2e6b 100644 --- a/frontend/src/api/loaders/scrimmagingLoader.ts +++ b/frontend/src/api/loaders/scrimmagingLoader.ts @@ -9,12 +9,7 @@ import { } from "../compete/competeFactories"; import { buildKey, safeEnsureQueryData } from "../helpers"; import { myTeamFactory, searchTeamsFactory } from "../team/teamFactories"; -import { - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum, - Status526Enum, - type Episode, - type TeamPrivate, -} from "api/_autogen"; +import { Status526Enum, type Episode, type TeamPrivate } from "api/_autogen"; import { episodeInfoFactory } from "api/episode/episodeFactories"; import toast from "react-hot-toast"; @@ -77,28 +72,6 @@ export const scrimmagingLoader = { episodeId, teamId: myTeamInfo.id, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All, - }, - scrimmagingRecordFactory, - queryClient, - ); - safeEnsureQueryData( - { - episodeId, - teamId: myTeamInfo.id, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked, - }, - scrimmagingRecordFactory, - queryClient, - ); - safeEnsureQueryData( - { - episodeId, - teamId: myTeamInfo.id, - scrimmageType: - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked, }, scrimmagingRecordFactory, queryClient, diff --git a/frontend/src/components/CountdownDigital.tsx b/frontend/src/components/CountdownDigital.tsx deleted file mode 100644 index b3ecb27f9..000000000 --- a/frontend/src/components/CountdownDigital.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import type React from "react"; -import { useEffect, useMemo, useState } from "react"; - -const thousand = 1000; -const sixty = 60; -const hoursInDay = 24; -const fullPercentage = 100; -const countDownRefreshRate = 30; - -interface ProgressCircleProps { - sqSize: number; - percentage: number; -} - -const ProgressCircle: React.FC = ({ - sqSize, - percentage, -}) => { - const strokeWidth = 6; - const radius = (sqSize - strokeWidth) / 2; - const viewBox = `0 0 ${sqSize} ${sqSize}`; - const dashArray = radius * Math.PI * 2; - const dashOffset = dashArray - (dashArray * percentage) / fullPercentage; - - return ( - - - - - ); -}; - -interface DateParams { - days: number; - hours: number; - minutes: number; -} - -const computeTimeDiff = (fromDate: Date, toDate: Date): DateParams => { - const timeDiff = toDate.getTime() - fromDate.getTime(); - - const days = Math.floor(timeDiff / (thousand * sixty * sixty * hoursInDay)); - const hours = Math.floor( - (timeDiff % (thousand * sixty * sixty * hoursInDay)) / - (thousand * sixty * sixty), - ); - const minutes = Math.floor( - (timeDiff % (thousand * sixty * sixty)) / (thousand * sixty), - ); - - return { days, hours, minutes }; -}; - -interface CountdownDigitalProps { - date: Date; - title?: string; -} - -const CountdownDigital: React.FC = ({ date }) => { - const currentTime = new Date(); - const [count, setCount] = useState(0); - - useEffect(() => { - const intervalId = setInterval(() => { - setCount((prevCount) => prevCount + 1); - }, thousand * countDownRefreshRate); - return () => { - clearInterval(intervalId); - }; - }, []); - - const countdownInfo = useMemo( - () => computeTimeDiff(currentTime, date), - [count], - ); - const progressCircleSize = 140; - const percentageDays = - ((sixty - countdownInfo.days) / sixty) * fullPercentage; - const percentageHours = - ((hoursInDay - countdownInfo.hours) / hoursInDay) * fullPercentage; - const percentageMins = - ((sixty - countdownInfo.minutes) / sixty) * fullPercentage; - const countTxtSize = "3xl"; - const labelTxtSize = "l"; - - return ( -
-
- {ProgressCircle({ - sqSize: progressCircleSize, - percentage: percentageDays, - })} - -
- - {countdownInfo.days} - - Days -
-
-
- {ProgressCircle({ - sqSize: progressCircleSize, - percentage: percentageHours, - })} - -
- - {countdownInfo.hours} - - Hours -
-
-
- {ProgressCircle({ - sqSize: progressCircleSize, - percentage: percentageMins, - })} - -
- - {countdownInfo.minutes} - - Mins -
-
-
- ); -}; - -export default CountdownDigital; diff --git a/frontend/src/components/compete/ScrimmagingRecord.tsx b/frontend/src/components/compete/ScrimmagingRecord.tsx index 126c9cbbb..64ad6ce7f 100644 --- a/frontend/src/components/compete/ScrimmagingRecord.tsx +++ b/frontend/src/components/compete/ScrimmagingRecord.tsx @@ -1,10 +1,6 @@ import type React from "react"; -import { useMemo } from "react"; -import { - CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum, - type ScrimmageRecord, - type TeamPublic, -} from "api/_autogen"; +import type { ScrimmageRecord, TeamPublic } from "api/_autogen"; +import { ScrimmageTypeEnum } from "api/apiTypes"; import WinLossTie from "./WinLossTie"; import { useEpisodeId } from "contexts/EpisodeContext"; import { useQueryClient } from "@tanstack/react-query"; @@ -32,23 +28,10 @@ const ScrimmagingRecord: React.FC = ({ const { episodeId } = useEpisodeId(); const queryClient = useQueryClient(); - const scrimTypeToCheck = useMemo(() => { - if (!isNil(hideAllScrimmages) && !hideAllScrimmages) { - return CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All; - } else if (!isNil(hideRanked) && !hideRanked) { - return CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked; - } else if (!isNil(hideUnranked) && !hideUnranked) { - return CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked; - } else { - return CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All; - } - }, [hideAllScrimmages, hideRanked, hideUnranked]); - const recordWatcher = queryClient.getQueryState( buildKey(scrimmagingRecordFactory.queryKey, { episodeId, teamId: team.id, - scrimmageType: scrimTypeToCheck, }), ); @@ -73,25 +56,19 @@ const ScrimmagingRecord: React.FC = ({
{!hideAllScrimmages && ( )} {!hideUnranked && ( )} {!hideRanked && ( )} diff --git a/frontend/src/components/compete/WinLossTie.tsx b/frontend/src/components/compete/WinLossTie.tsx index c33a4e85a..82c522d8c 100644 --- a/frontend/src/components/compete/WinLossTie.tsx +++ b/frontend/src/components/compete/WinLossTie.tsx @@ -1,22 +1,21 @@ import type React from "react"; import { useMemo } from "react"; -import { CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum } from "api/_autogen"; +import type { ScrimmageTypeEnum } from "api/apiTypes"; import Spinner from "components/Spinner"; import { isNil } from "lodash"; import { useScrimmagingRecord } from "api/compete/useCompete"; import { useEpisodeId } from "contexts/EpisodeContext"; interface WinLossTieProps { - scrimmageType: CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum; + scrimmageType: ScrimmageTypeEnum; teamId: number; className?: string; } const scrimmageTypeToName = { - [CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.All]: - "All Scrimmages", - [CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Unranked]: "Unranked", - [CompeteMatchScrimmagingRecordRetrieveScrimmageTypeEnum.Ranked]: "Ranked", + All: "All Scrimmages", + Unranked: "Unranked", + Ranked: "Ranked", } as const; const WinLossTie: React.FC = ({ @@ -28,7 +27,6 @@ const WinLossTie: React.FC = ({ const scrimRecord = useScrimmagingRecord({ episodeId, teamId, - scrimmageType, }); const HEADER = @@ -70,13 +68,13 @@ const WinLossTie: React.FC = ({ Ties
- {dataOrLoading(scrimRecord.data?.wins)} + {dataOrLoading(scrimRecord.data?.[scrimmageType].wins)}
- {dataOrLoading(scrimRecord.data?.losses)} + {dataOrLoading(scrimRecord.data?.[scrimmageType].losses)}
- {dataOrLoading(scrimRecord.data?.ties)} + {dataOrLoading(scrimRecord.data?.[scrimmageType].ties)}
);