Typscript final

This commit is contained in:
2026-03-11 16:44:09 +01:00 Verified
parent 42b28350de
commit edd9b064ec
24 changed files with 486 additions and 419 deletions
@@ -1,7 +1,7 @@
// frontend/src/components/Bracket/BracketView.tsx
import React, { useEffect, useRef, useState } from 'react';
import { MatchData } from '../../types';
import { type MatchData } from '../../types';
import Podium from "../Tournament/Podium";
import MatchCard from "./MatchCard";
@@ -80,7 +80,7 @@ export default function BracketView({ matches, onMatchClick }: BracketViewProps)
const roundKeys = Object.keys(rounds).map(Number).sort((a, b) => a - b);
return roundKeys.map((r) => {
let matchesInRound = rounds[r];
const matchesInRound = rounds[r];
matchesInRound.sort((a, b) => a.number - b.number);
return (
<div key={r} className="flex flex-col gap-10 z-10 w-64 shrink-0 justify-around">
@@ -95,8 +95,8 @@ export default function BracketView({ matches, onMatchClick }: BracketViewProps)
const lb = matches.filter(m => m.bracket === 'Loser');
const finals = matches.filter(m => m.bracket === 'Finals');
let displayWb = [...wb];
let displayFinals = [...finals];
const displayWb = [...wb];
const displayFinals = [...finals];
if (!isDoubleElim && displayWb.length > 0) {
const maxRound = Math.max(...displayWb.map(m => m.round));
@@ -146,7 +146,6 @@ export default function BracketView({ matches, onMatchClick }: BracketViewProps)
)}
</div>
<div className="flex flex-col justify-center gap-6 z-10">
{/* @ts-ignore - Assuming Podium was typed earlier or needs its own MatchData import */}
<Podium matches={matches} />
</div>
</div>
@@ -1,7 +1,7 @@
// frontend/src/components/Bracket/MatchCard.tsx
import { Check } from 'lucide-react';
import { MatchData } from '../../types';
import { type MatchData } from '../../types';
import { printName, stringToColor } from '../../utils/helpers';
interface MatchCardProps {
@@ -48,7 +48,7 @@ export default function MatchCard({ match, onClick }: MatchCardProps) {
{ n: match.p1, s: match.p1_sets, win: match.winner_team_id !== null && match.winner_team_id === match.p1_team_id, real: match.p1_is_real },
{ n: match.p2, s: match.p2_sets, win: match.winner_team_id !== null && match.winner_team_id === match.p2_team_id, real: match.p2_is_real }
].map((p, i) => (
<div key={i} className={`flex justify-between items-center ${p.win ? 'text-zinc-800 dark:text-zinc-50 print:text-black! font-black' : p.real ? 'text-zinc-500 dark:text-zinc-400 print:text-black!' : 'text-zinc-400 print:text-zinc-600! italic'}`}>
<div key={i} className={`flex justify-between items-center ${p.win ? 'text-zinc-800 dark:text-zinc-50 print:text-black! font-black' : p.real ? 'text-zinc-600 dark:text-zinc-400 print:text-black!' : 'text-zinc-400 dark:text-zinc-600 print:text-zinc-600! italic'}`}>
<span className={`truncate text-xs tracking-tight pr-2 print:hidden ${p.win ? ' font-black text-orange-500' : 'font-bold'}`}>{p.n}</span>
@@ -11,8 +11,8 @@ interface TournamentSettings {
type: string;
timestamp: string;
duration: number;
courts: any[];
teams: any[];
courts: { name?: string }[];
teams: { name?: string }[];
}
interface TournamentFormProps {
@@ -106,12 +106,13 @@ export default function TournamentForm({ tournamentId, onSuccess, onDelete }: To
await api.post('/tournaments', fullPayload);
}
onSuccess();
} catch (err: any) {
} catch (err: unknown) {
console.error(err);
if (Array.isArray(err.detail)) {
setError(err.detail.map((e: any) => `${e.loc.join('.')}: ${e.msg}`).join(', '));
const error = err as { detail?: string | Array<{ loc: string[]; msg: string }> };
if (Array.isArray(error.detail)) {
setError(error.detail.map((e) => `${e.loc.join('.')}: ${e.msg}`).join(', '));
} else {
setError(typeof err.detail === 'string' ? err.detail : "Error saving tournament");
setError(typeof error.detail === 'string' ? error.detail : "Error saving tournament");
}
} finally {
setIsSubmitting(false);
+1 -1
View File
@@ -20,7 +20,7 @@ export interface OutletContextType {
}
export default function Layout({ darkMode, setDarkMode }: LayoutProps) {
const [isAdmin, setIsAdmin] = useState<boolean>(!!getToken());
const [isAdmin] = useState<boolean>(!!getToken());
const [navTitle, setNavTitle] = useState<string>('');
const [navSubtitle, setNavSubtitle] = useState<string>('');
const [showSettings, setShowSettings] = useState<boolean>(false);
@@ -2,7 +2,7 @@
import { CheckCircle, Pencil, Plus, Trophy } from 'lucide-react';
import React from 'react';
import { MatchData } from '../../types';
import { type MatchData } from '../../types';
import { printName, stringToColor } from '../../utils/helpers';
interface ScheduleRowProps {
@@ -2,7 +2,7 @@
import { Search } from 'lucide-react';
import { useState } from 'react';
import { MatchData } from '../../types';
import { type MatchData } from '../../types';
import ScheduleRow from './ScheduleRow';
interface ScheduleViewProps {
@@ -1,13 +1,10 @@
// frontend/src/components/Tournament/ScoreModal.tsx
import { type SetData } from '../../types';
import { Clock, Eraser, MapPin, Trophy } from 'lucide-react';
import { useState } from 'react';
import Modal from '../UI/Modal';
interface SetData {
p1: number | string;
p2: number | string;
}
interface MatchData {
id: string | number;
@@ -37,8 +34,9 @@ const ScoreForm = ({ match, isAdmin, onSubmit, onClear }: ScoreFormProps) => {
const handleSubmit = async () => {
try {
await onSubmit(match.id, sets, code);
} catch (err: any) {
setError(typeof err?.detail === 'string' ? err.detail : "Check code or scores");
} catch (err: unknown) {
const error = err as { detail?: string };
setError(typeof error?.detail === 'string' ? error.detail : "Check code or scores");
}
};
+2 -2
View File
@@ -1,6 +1,6 @@
// frontend/src/components/UI/Modal.tsx
import { LucideIcon, X } from 'lucide-react';
import { type LucideIcon, X } from 'lucide-react';
import React from 'react';
interface ModalProps {
@@ -19,7 +19,7 @@ export default function Modal({ isOpen, onClose, title, icon: Icon, children }:
<div className="p-6">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-black text-zinc-900 dark:text-white flex items-start gap-2">
{/* @ts-ignore - 'weight' is a specific prop if using Phosphor icons, but Lucide doesn't natively use it. Kept for compatibility. */}
{/* @ts-expect-error - 'weight' is a specific prop if using Phosphor icons, but Lucide doesn't natively use it. */}
{Icon && <Icon weight="duotone" className="text-orange-500 mt-1 shrink-0" size={24} />}
<span>{title}</span>
</h2>