152 lines
4.8 KiB
TypeScript
152 lines
4.8 KiB
TypeScript
import { Form, Link, redirect } from "react-router";
|
|
import { getAuth } from "@clerk/react-router/server";
|
|
import { createLeague } from "~/models/league";
|
|
import { createSeason } from "~/models/season";
|
|
import { createManyTeams } from "~/models/team";
|
|
import type { Route } from "./+types/new";
|
|
import { Button } from "~/components/ui/button";
|
|
import { Input } from "~/components/ui/input";
|
|
import { Label } from "~/components/ui/label";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "~/components/ui/card";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "~/components/ui/select";
|
|
|
|
export async function action(args: Route.ActionArgs) {
|
|
const { userId } = await getAuth(args);
|
|
const { request } = args;
|
|
|
|
if (!userId) {
|
|
throw new Response("Unauthorized", { status: 401 });
|
|
}
|
|
|
|
const formData = await request.formData();
|
|
const name = formData.get("name");
|
|
const teamCount = formData.get("teamCount");
|
|
|
|
// Validation
|
|
if (typeof name !== "string" || !name.trim()) {
|
|
return { error: "League name is required" };
|
|
}
|
|
|
|
if (typeof teamCount !== "string") {
|
|
return { error: "Number of teams is required" };
|
|
}
|
|
|
|
const teamCountNum = parseInt(teamCount, 10);
|
|
if (isNaN(teamCountNum) || teamCountNum < 6 || teamCountNum > 16) {
|
|
return { error: "Number of teams must be between 6 and 16" };
|
|
}
|
|
|
|
try {
|
|
// Create league
|
|
const league = await createLeague({
|
|
name: name.trim(),
|
|
createdBy: userId,
|
|
});
|
|
|
|
// Create first season
|
|
const currentYear = new Date().getFullYear();
|
|
const season = await createSeason({
|
|
leagueId: league.id,
|
|
year: currentYear,
|
|
status: "pre_draft",
|
|
});
|
|
|
|
// Create teams with placeholder names
|
|
const teams = Array.from({ length: teamCountNum }, (_, i) => ({
|
|
seasonId: season.id,
|
|
name: `Team ${i + 1}`,
|
|
ownerId: i === 0 ? userId : null, // Assign first team to creator
|
|
}));
|
|
|
|
await createManyTeams(teams);
|
|
|
|
// Redirect to league homepage
|
|
return redirect(`/leagues/${league.id}`);
|
|
} catch (error) {
|
|
console.error("Error creating league:", error);
|
|
return { error: "Failed to create league. Please try again." };
|
|
}
|
|
}
|
|
|
|
export default function NewLeague({ actionData }: Route.ComponentProps) {
|
|
return (
|
|
<div className="container max-w-2xl mx-auto py-8 px-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-3xl">Start a New League</CardTitle>
|
|
<CardDescription>
|
|
Create your fantasy league and invite your friends to compete.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Form method="post" className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="name">League Name</Label>
|
|
<Input
|
|
id="name"
|
|
name="name"
|
|
type="text"
|
|
placeholder="Enter league name"
|
|
required
|
|
minLength={3}
|
|
maxLength={50}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="teamCount">Number of Teams</Label>
|
|
<Select name="teamCount" defaultValue="12" required>
|
|
<SelectTrigger id="teamCount">
|
|
<SelectValue placeholder="Select number of teams" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="6">6 Teams</SelectItem>
|
|
<SelectItem value="7">7 Teams</SelectItem>
|
|
<SelectItem value="8">8 Teams</SelectItem>
|
|
<SelectItem value="9">9 Teams</SelectItem>
|
|
<SelectItem value="10">10 Teams</SelectItem>
|
|
<SelectItem value="11">11 Teams</SelectItem>
|
|
<SelectItem value="12">12 Teams</SelectItem>
|
|
<SelectItem value="13">13 Teams</SelectItem>
|
|
<SelectItem value="14">14 Teams</SelectItem>
|
|
<SelectItem value="15">15 Teams</SelectItem>
|
|
<SelectItem value="16">16 Teams</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
<p className="text-sm text-muted-foreground">
|
|
Choose between 6 and 16 teams
|
|
</p>
|
|
</div>
|
|
|
|
{actionData?.error && (
|
|
<div className="bg-destructive/15 text-destructive px-4 py-3 rounded-md text-sm">
|
|
{actionData.error}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex gap-4">
|
|
<Button type="submit" className="flex-1">
|
|
Create League
|
|
</Button>
|
|
<Button type="button" variant="outline" asChild>
|
|
<Link to="/">Cancel</Link>
|
|
</Button>
|
|
</div>
|
|
</Form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|