Skip to content
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
20 changes: 14 additions & 6 deletions src/components/TournamentForm/TournamentForm.schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { zodResolver } from '@hookform/resolvers/zod';
import {
CurrencyCode,
GameSystem,
Expand All @@ -15,8 +14,12 @@ import {
validateGameSystemConfig,
} from '~/components/GameSystemConfigFields';

interface CreateSchemaConfig {
competitorCount: number;
}

// TODO: Convert gameSystemConfig to union of other game systems
export const tournamentFormSchema = z.object({
export const createSchema = (config: CreateSchemaConfig) => z.object({

// General
title: z.string().min(3, 'Title must be at least 3 characters.').max(40, 'Titles are limited to 40 characters.'),
Expand Down Expand Up @@ -97,15 +100,20 @@ export const tournamentFormSchema = z.object({
path: ['pairingConfig'],
});
}
if (data.maxCompetitors < config.competitorCount) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Can not set tournament size to ${data.maxCompetitors} when there are already ${config.competitorCount} ${data.competitorSize > 1 ? 'teams' : 'players'} registered.`,
path: ['maxCompetitors'],
Comment on lines +103 to +107
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validation message uses the wrong entity label in solo events.

Line 106 picks 'teams'/'players' from maxCompetitors, not from tournament mode. For non-team tournaments this can show the wrong noun.

Proposed fix
-      message: `Can not set tournament size to ${data.maxCompetitors} when there are already ${config.competitorCount} ${data.maxCompetitors > 1 ? 'teams' : 'players'} registered.`,
+      message: `Can not set tournament size to ${data.maxCompetitors} when there are already ${config.competitorCount} ${data.competitorSize > 1 ? 'teams' : 'players'} registered.`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/TournamentForm/TournamentForm.schema.ts` around lines 103 -
107, The validation message uses maxCompetitors to pick the noun but should use
the tournament mode; update the ctx.addIssue message construction so it selects
'teams' vs 'players' based on the tournament mode flag (e.g., a team boolean or
mode on the config) rather than data.maxCompetitors. Locate the block around
data.maxCompetitors, config.competitorCount and ctx.addIssue and compute a label
like const entityLabel = config.isTeamTournament ? 'teams' : 'players' (or use
the existing mode field on config), then interpolate entityLabel into the
message.

});
}
});

export const tournamentFormResolver = zodResolver(tournamentFormSchema);

export type TournamentSubmitData = TournamentEditableFields;

export type TournamentFormData = z.infer<typeof tournamentFormSchema>;
export type TournamentFormData = z.infer<ReturnType<typeof createSchema>>;

export const defaultValues: Omit<z.infer<typeof tournamentFormSchema>, 'location'> = {
export const defaultValues: Omit<z.infer<ReturnType<typeof createSchema>>, 'location'> = {
maxCompetitors: 20,
competitorSize: 1,
useNationalTeams: false,
Expand Down
14 changes: 11 additions & 3 deletions src/components/TournamentForm/TournamentForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { GameSystemConfigFields } from '~/components/GameSystemConfigFields';
import { Card } from '~/components/generic/Card';
import { Form, FormField } from '~/components/generic/Form';
import { InputSelect } from '~/components/generic/InputSelect';
import { useGetTournamentCompetitorsByTournament } from '~/services/tournamentCompetitors';
import { useGetTournament } from '~/services/tournaments';
import { validateForm } from '~/utils/validateForm';
import { CompetitorFields } from './components/CompetitorFields';
import { FormatFields } from './components/FormatFields';
import { GeneralFields } from './components/GeneralFields';
import { PairingFields } from './components/PairingFields';
import {
createSchema,
defaultValues,
TournamentFormData,
tournamentFormSchema,
TournamentSubmitData,
} from './TournamentForm.schema';
import { convertDateToEpoch, convertEpochToDate } from './TournamentForm.utils';
Expand All @@ -41,7 +42,12 @@ export const TournamentForm = ({
onSubmit: handleSubmit,
tournamentId,
}: TournamentFormProps): JSX.Element => {
const { data: tournament } = useGetTournament(tournamentId ? { id: tournamentId } : 'skip');
const { data: tournament } = useGetTournament(tournamentId ? {
id: tournamentId,
} : 'skip');
const { data: tournamentCompetitors } = useGetTournamentCompetitorsByTournament(tournamentId ? {
tournamentId: tournamentId,
} : 'skip');
const form = useForm<TournamentFormData>({
defaultValues: {
...defaultValues,
Expand All @@ -57,7 +63,9 @@ export const TournamentForm = ({
mode: 'onSubmit',
});
const onSubmit: SubmitHandler<TournamentFormData> = async (formData) => {
const data = validateForm(tournamentFormSchema, formData, form.setError as UseFormSetError<FieldValues>);
const data = validateForm(createSchema({
competitorCount: tournamentCompetitors?.length ?? 0,
}), formData, form.setError as UseFormSetError<FieldValues>);
if (data) {
handleSubmit({
...data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const CompetitorFields = ({
<Switch checked={useTeams} onCheckedChange={handleToggleIsTeam} />
</FormField>
<div className={styles.Stackable}>
<FormField name="maxCompetitors" label={`Total ${getCompetitorLabel()}`} disabled={disableFields}>
<FormField name="maxCompetitors" label={`Total ${getCompetitorLabel()}`} disabled={!['draft', 'published'].includes(status)}>
<InputText type="number" />
</FormField>
<Animate show={useTeams}>
Expand Down