2025-10-31 22:13:12 -07:00
|
|
|
import type { Route } from "./+types/admin.sports-seasons.$id.events";
|
|
|
|
|
import { redirect } from "react-router";
|
|
|
|
|
import { findSportsSeasonById } from "~/models/sports-season";
|
|
|
|
|
import {
|
|
|
|
|
getScoringEventsForSportsSeason,
|
|
|
|
|
createScoringEvent,
|
|
|
|
|
deleteScoringEvent,
|
|
|
|
|
type CreateScoringEventData,
|
|
|
|
|
} from "~/models/scoring-event";
|
|
|
|
|
|
|
|
|
|
export async function loader({ params }: Route.LoaderArgs) {
|
|
|
|
|
const sportsSeason = await findSportsSeasonById(params.id);
|
|
|
|
|
|
|
|
|
|
if (!sportsSeason) {
|
|
|
|
|
throw new Response("Sports season not found", { status: 404 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const events = await getScoringEventsForSportsSeason(params.id);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
sportsSeason: sportsSeason as typeof sportsSeason & {
|
|
|
|
|
sport: { id: string; name: string; type: string; slug: string };
|
|
|
|
|
},
|
|
|
|
|
events,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function action({ request, params }: Route.ActionArgs) {
|
|
|
|
|
const formData = await request.formData();
|
|
|
|
|
const intent = formData.get("intent");
|
|
|
|
|
|
|
|
|
|
if (intent === "delete-event") {
|
|
|
|
|
const eventId = formData.get("eventId");
|
|
|
|
|
|
|
|
|
|
if (typeof eventId !== "string" || !eventId) {
|
|
|
|
|
return { error: "Event ID is required" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await deleteScoringEvent(eventId);
|
|
|
|
|
return { success: "Event deleted successfully" };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error deleting event:", error);
|
|
|
|
|
return { error: "Failed to delete event" };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const name = formData.get("name");
|
|
|
|
|
const eventType = formData.get("eventType");
|
|
|
|
|
const eventDate = formData.get("eventDate");
|
|
|
|
|
const playoffRound = formData.get("playoffRound");
|
|
|
|
|
|
|
|
|
|
// Validation
|
|
|
|
|
if (typeof name !== "string" || !name.trim()) {
|
|
|
|
|
return { error: "Event name is required" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
eventType !== "playoff_game" &&
|
|
|
|
|
eventType !== "major_tournament" &&
|
|
|
|
|
eventType !== "final_standings"
|
|
|
|
|
) {
|
|
|
|
|
return { error: "Invalid event type" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const eventData: CreateScoringEventData = {
|
|
|
|
|
sportsSeasonId: params.id,
|
|
|
|
|
name: name.trim(),
|
feat: Implement bracket expansion plan to support various tournament structures
- Added a comprehensive plan for bracket expansion, including support for 4, 8, 16, 32, and 68 team formats.
- Introduced a template-based bracket system with predefined templates for NCAA March Madness, NFL Playoffs, NBA Playoffs, and simple brackets.
- Updated UI flow for bracket creation, allowing admins to select templates and assign participants flexibly.
- Enhanced database schema to accommodate new scoring rules and bracket templates.
- Proposed updates to scoring logic to handle non-scoring rounds and participant placements correctly.
- Documented implementation phases for gradual rollout of new features.
- Addressed critical bugs in the playoff event processing and scoring logic, ensuring proper advancement and scoring rules across multiple leagues.
2025-11-03 09:36:16 -08:00
|
|
|
eventType: eventType as "playoff_game" | "major_tournament" | "final_standings",
|
2025-10-31 22:13:12 -07:00
|
|
|
eventDate: typeof eventDate === "string" && eventDate ? new Date(eventDate) : undefined,
|
|
|
|
|
playoffRound: typeof playoffRound === "string" && playoffRound ? playoffRound : undefined,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const event = await createScoringEvent(eventData);
|
|
|
|
|
return redirect(`/admin/sports-seasons/${params.id}/events/${event.id}`);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error creating scoring event:", error);
|
|
|
|
|
return { error: "Failed to create scoring event. Please try again." };
|
|
|
|
|
}
|
|
|
|
|
}
|