From 7dddf2c9a7b8963a75bf000f03cae9d6e8c7ceda Mon Sep 17 00:00:00 2001
From: Chris Parsons
Date: Wed, 29 Oct 2025 00:04:27 -0700
Subject: [PATCH] feat: Add scoring rules editor to league settings and
creation pages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Created ScoringRulesEditor component with 8 placement point inputs
- Added scoring-types.ts for shared client/server types
- Integrated scoring rules into league settings page
- Integrated scoring rules into league creation form
- Added validation for point values (0-1000 range)
- Disabled editing in settings after draft starts
- Included helpful tips and preview display
Phase 1.3 complete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude
---
app/components/scoring/ScoringRulesEditor.tsx | 96 +++++++++++++++++++
app/lib/scoring-types.ts | 25 +++++
app/models/scoring-rules.ts | 31 +-----
app/routes/leagues/$leagueId.settings.tsx | 39 +++++++-
app/routes/leagues/new.tsx | 24 +++++
plans/scoring-system.md | 13 ++-
6 files changed, 194 insertions(+), 34 deletions(-)
create mode 100644 app/components/scoring/ScoringRulesEditor.tsx
create mode 100644 app/lib/scoring-types.ts
diff --git a/app/components/scoring/ScoringRulesEditor.tsx b/app/components/scoring/ScoringRulesEditor.tsx
new file mode 100644
index 0000000..6299288
--- /dev/null
+++ b/app/components/scoring/ScoringRulesEditor.tsx
@@ -0,0 +1,96 @@
+import { Label } from "~/components/ui/label";
+import { Input } from "~/components/ui/input";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "~/components/ui/card";
+import { DEFAULT_SCORING_RULES, type ScoringRules } from "~/lib/scoring-types";
+
+interface ScoringRulesEditorProps {
+ scoringRules?: Partial;
+ disabled?: boolean;
+}
+
+export function ScoringRulesEditor({ scoringRules, disabled = false }: ScoringRulesEditorProps) {
+ const rules = {
+ ...DEFAULT_SCORING_RULES,
+ ...scoringRules,
+ };
+
+ const placementLabels = [
+ { key: "pointsFor1st", label: "1st Place", emoji: "🥇" },
+ { key: "pointsFor2nd", label: "2nd Place", emoji: "🥈" },
+ { key: "pointsFor3rd", label: "3rd Place", emoji: "🥉" },
+ { key: "pointsFor4th", label: "4th Place", emoji: "4️⃣" },
+ { key: "pointsFor5th", label: "5th Place", emoji: "5️⃣" },
+ { key: "pointsFor6th", label: "6th Place", emoji: "6️⃣" },
+ { key: "pointsFor7th", label: "7th Place", emoji: "7️⃣" },
+ { key: "pointsFor8th", label: "8th Place", emoji: "8️⃣" },
+ ] as const;
+
+ return (
+
+
+ Scoring Rules
+
+ {disabled
+ ? "Scoring rules cannot be modified after the draft has started"
+ : "Set the fantasy points awarded for each final placement (1st through 8th)"}
+
+
+
+
+
+
+ How it works: At the end of each sport's season, participants will
+ be ranked 1st through 8th based on their performance. These point values will be
+ awarded to teams that drafted those participants.
+
+ 💡 Tip: The default scoring rewards winning heavily (100 pts for 1st)
+ but also values consistency (25 pts for 5th/6th). Customize these values to fit your
+ league's strategy preferences.
+