Skip to content
Open
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
145 changes: 135 additions & 10 deletions next-frontend/public/wcaAPI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,32 @@ paths:
type: array
items:
$ref: '#/components/schemas/RegistrationData'
/competitions/{competitionId}/psych-sheet/{eventId}:
get:
summary: Get competition registrations
parameters:
- name: competitionId
in: path
required: true
schema:
type: string
- name: eventId
in: path
required: true
schema:
type: string
- name: sort_by
in: query
required: false
schema:
type: string
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/PsychSheet'
/competitions/{competitionId}/podiums:
get:
summary: Returns the podium results
Expand Down Expand Up @@ -1337,24 +1363,123 @@ components:
name:
type: string

RegistrationData:
PsychSheet:
type: object
required:
- sort_by
- sort_by_second
- sorted_rankings
properties:
id:
type: integer
competition_id:
sort_by:
type: string
user_id:
type: integer
event_ids:
sort_by_second:
type: string
sorted_rankings:
type: array
items:
type: string
type: object
required:
- name
- user_id
- wca_id
- country_iso2
- average_best
- average_rank
- single_best
- single_rank
- tied_previous
- pos
properties:
name:
type: string
user_id:
type: integer
wca_id:
type: string
country_iso2:
type: string
average_best:
type: integer
average_rank:
type: integer
single_best:
type: integer
single_rank:
type: integer
tied_previous:
type: boolean
pos:
type: integer

RegistrationData:
type: object
required:
- id
- competition_id
- registrant_id
- user_id
- event_ids
- user
- competing
properties:
id:
type: integer
registrant_id:
type: integer
user_id:
type: integer
guests:
type: integer
user:
type: object
required:
- id
- name
- gender
- country_iso2
properties:
id:
type: integer
name:
type: string
gender:
type: string
country_iso2:
type: string
wca_id:
type: string
competing:
type: object
required:
- event_ids
properties:
event_ids:
type: array
items:
type: string
# only when authenticated
registration_status:
type: string
registered_on:
type: string
format: datetime
comment:
type: string
admin_comment:
type: string
# only when authenticated
payment:
type: object
properties:
has_paid:
type: boolean
payment_status:
type: string
paid_amount_iso:
type: integer
currency_code:
type: string
updated_at:
type: string
format: datetime

WcifEvent:
type: object
Expand Down
84 changes: 84 additions & 0 deletions next-frontend/src/components/competitions/CompetitorTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { HStack, Icon, Link, Table, Text } from "@chakra-ui/react";
import EventIcon from "@/components/EventIcon";
import { route } from "nextjs-routes";
import Flag from "react-world-flags";
import CountryMap from "@/components/CountryMap";
import { components } from "@/types/openapi";
import { TFunction } from "i18next";

export default function CompetitorTable({
eventIds,
registrations,
t,
setPsychSheetEvent,
}: {
eventIds: string[];
registrations: components["schemas"]["RegistrationData"][];
setPsychSheetEvent: (eventId: string) => void;
t: TFunction;
}) {
return (
<Table.Root width="100%">
<Table.Header>
<Table.Row>
<Table.ColumnHeader>Name</Table.ColumnHeader>
<Table.ColumnHeader>Representing</Table.ColumnHeader>
{eventIds.map((eventId) => (
<Table.ColumnHeader
key={eventId}
onClick={() => setPsychSheetEvent(eventId)}
_hover={{ bg: "grey.solid", color: "wcawhite.contrast" }}
>
<EventIcon eventId={eventId} />
</Table.ColumnHeader>
))}
<Table.ColumnHeader>Total</Table.ColumnHeader>
</Table.Row>
</Table.Header>

<Table.Body>
{registrations
.toSorted((a, b) => a.user.name.localeCompare(b.user.name))
.map((registration) => (
<Table.Row key={registration.id}>
<Table.Cell>
{registration.user.wca_id ? (
<Link
href={route({
pathname: "/persons/[wcaId]",
query: { wcaId: registration.user.wca_id },
})}
>
<Text fontWeight="medium">{registration.user.name}</Text>
</Link>
) : (
<Text fontWeight="medium">{registration.user.name}</Text>
)}
</Table.Cell>
<Table.Cell>
<HStack>
<Icon asChild size="sm">
<Flag code={registration.user.country_iso2} />
</Icon>
<CountryMap
code={registration.user.country_iso2}
bold
t={t}
/>
</HStack>
</Table.Cell>

{eventIds.map((eventId) => (
<Table.Cell key={eventId}>
{registration.competing.event_ids.includes(eventId) ? (
<EventIcon eventId={eventId} />
) : null}
</Table.Cell>
))}
<Table.Cell>{registration.competing.event_ids.length}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
);
}
65 changes: 65 additions & 0 deletions next-frontend/src/components/competitions/PsychsheetTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { HStack, Icon, Link, Table, Text } from "@chakra-ui/react";
import { route } from "nextjs-routes";
import Flag from "react-world-flags";
import CountryMap from "@/components/CountryMap";
import { components } from "@/types/openapi";
import { TFunction } from "i18next";

export default function PsychsheetTable({
pychsheet,
t,
}: {
pychsheet: components["schemas"]["PsychSheet"];
t: TFunction;
}) {
return (
<Table.Root width="100%">
<Table.Header>
<Table.Row>
<Table.ColumnHeader>Pos</Table.ColumnHeader>
<Table.ColumnHeader>Name</Table.ColumnHeader>
<Table.ColumnHeader>Representing</Table.ColumnHeader>
<Table.ColumnHeader>WR</Table.ColumnHeader>
<Table.ColumnHeader>Single</Table.ColumnHeader>
<Table.ColumnHeader>Average</Table.ColumnHeader>
<Table.ColumnHeader>WR</Table.ColumnHeader>
</Table.Row>
</Table.Header>

<Table.Body>
{pychsheet.sorted_rankings
.toSorted((a, b) => a.pos - b.pos)
.map(
(registration) =>
registration.wca_id && (
<Table.Row key={registration.user_id}>
<Table.Cell>{registration.pos}</Table.Cell>
<Table.Cell>
<Link
href={route({
pathname: "/persons/[wcaId]",
query: { wcaId: registration.wca_id },
})}
>
<Text fontWeight="medium">{registration.name}</Text>
</Link>
</Table.Cell>
<Table.Cell>
<HStack>
<Icon asChild size="sm">
<Flag code={registration.country_iso2} />
</Icon>
<CountryMap code={registration.country_iso2} bold t={t} />
</HStack>
</Table.Cell>
<Table.Cell>{registration.single_rank}</Table.Cell>
<Table.Cell>{registration.single_best}</Table.Cell>
<Table.Cell>{registration.average_best}</Table.Cell>
<Table.Cell>{registration.average_rank}</Table.Cell>
</Table.Row>
),
)}
</Table.Body>
</Table.Root>
);
}
Loading