From ce55b7e68ae2cc6a999081e76c3e06d07199ede2 Mon Sep 17 00:00:00 2001 From: Swayymalcolm99 Date: Fri, 19 Jun 2026 22:47:16 -0700 Subject: [PATCH] work done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented bonus match multiplier support across creator event flow. - Added `multiplier` selection to `AddMatchForm` and preserved it through add/bulk match logic. - Updated match models and `MatchList` to show `⚡ 2x/3x Points` badges while keeping `1x` matches badge-free. --- .../creator-events/[id]/matches/page.tsx | 6 ++ .../component/creator-events/AddMatchForm.tsx | 32 +++++++++++ .../creator-events/BulkMatchUpload.tsx | 18 +++++- .../component/creator-events/MatchList.tsx | 5 ++ frontend/src/context/CreatorEventsContext.tsx | 55 +++++++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/(authenticated)/creator-events/[id]/matches/page.tsx b/frontend/src/app/(authenticated)/creator-events/[id]/matches/page.tsx index 9eb5ea65..18d74ae2 100644 --- a/frontend/src/app/(authenticated)/creator-events/[id]/matches/page.tsx +++ b/frontend/src/app/(authenticated)/creator-events/[id]/matches/page.tsx @@ -29,6 +29,7 @@ interface Match { status: MatchStatus; hasPredictions: boolean; result?: string; + multiplier: 1 | 2 | 3; } interface EventMeta { @@ -53,6 +54,7 @@ const MOCK_MATCHES: Match[] = [ matchTime: new Date(Date.now() + 86400 * 1000).toISOString(), status: "upcoming", hasPredictions: false, + multiplier: 1, }, { id: "match-002", @@ -61,6 +63,7 @@ const MOCK_MATCHES: Match[] = [ matchTime: new Date(Date.now() - 3600 * 1000).toISOString(), status: "started", hasPredictions: true, + multiplier: 1, }, { id: "match-003", @@ -70,6 +73,7 @@ const MOCK_MATCHES: Match[] = [ status: "resolved", hasPredictions: true, result: "Team Sigma", + multiplier: 1, }, ]; @@ -150,6 +154,7 @@ export default function MatchManagementPage() { matchTime: data.matchTime, status: "upcoming", hasPredictions: false, + multiplier: data.multiplier, }; setMatches((prev) => [...prev, newMatch]); } @@ -162,6 +167,7 @@ export default function MatchManagementPage() { matchTime: m.matchTime, status: "upcoming", hasPredictions: false, + multiplier: m.multiplier, })); setMatches((prev) => [...prev, ...newMatches]); } diff --git a/frontend/src/component/creator-events/AddMatchForm.tsx b/frontend/src/component/creator-events/AddMatchForm.tsx index be5f2d55..8a420dd5 100644 --- a/frontend/src/component/creator-events/AddMatchForm.tsx +++ b/frontend/src/component/creator-events/AddMatchForm.tsx @@ -8,6 +8,7 @@ export interface MatchFormData { teamA: string; teamB: string; matchTime: string; + multiplier: 1 | 2 | 3; } interface AddMatchFormProps { @@ -25,6 +26,7 @@ export default function AddMatchForm({ onAddMatch }: AddMatchFormProps) { const [teamA, setTeamA] = useState(""); const [teamB, setTeamB] = useState(""); const [matchTime, setMatchTime] = useState(nowPlusOneHour()); + const [multiplier, setMultiplier] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); const [errors, setErrors] = useState>({}); @@ -50,6 +52,10 @@ export default function AddMatchForm({ onAddMatch }: AddMatchFormProps) { errs.matchTime = "Match time must be in the future."; } + if (![1, 2, 3].includes(multiplier)) { + errs.multiplier = "Please select a valid bonus multiplier."; + } + setErrors(errs); return Object.keys(errs).length === 0; } @@ -64,10 +70,12 @@ export default function AddMatchForm({ onAddMatch }: AddMatchFormProps) { teamA: teamA.trim(), teamB: teamB.trim(), matchTime, + multiplier, }); setTeamA(""); setTeamB(""); setMatchTime(nowPlusOneHour()); + setMultiplier(1); setErrors({}); } catch { setErrors({ form: "Failed to add match. Please try again." }); @@ -153,6 +161,30 @@ export default function AddMatchForm({ onAddMatch }: AddMatchFormProps) { )} +
+ + + {errors.multiplier && ( +

{errors.multiplier}

+ )} +
+
diff --git a/frontend/src/context/CreatorEventsContext.tsx b/frontend/src/context/CreatorEventsContext.tsx index d7c1009c..4e7cef8b 100644 --- a/frontend/src/context/CreatorEventsContext.tsx +++ b/frontend/src/context/CreatorEventsContext.tsx @@ -66,9 +66,13 @@ export interface CreatorEventMatch { teamB: string; matchTime: string; outcome: MatchOutcome; +<<<<<<< Updated upstream homeScore: number | null; awayScore: number | null; pointsMultiplier: number; +======= + multiplier?: 1 | 2 | 3; +>>>>>>> Stashed changes } export interface Participant { @@ -179,11 +183,19 @@ export interface CreatorEventsContextValue { ) => Promise<{ eventId: string; inviteCode: string }>; joinEvent: (inviteCode: string) => Promise; addMatch: ( +<<<<<<< Updated upstream input: AddMatchInput | string, teamA?: string, teamB?: string, matchTime?: string, details?: Partial, +======= + eventId: string, + teamA: string, + teamB: string, + matchTime: string, + multiplier: 1 | 2 | 3, +>>>>>>> Stashed changes ) => Promise; submitPrediction: ( input: SubmitPredictionInput | string, @@ -997,6 +1009,7 @@ export function CreatorEventsProvider({ ); if (!event || event.participants >= event.maxParticipants) return false; +<<<<<<< Updated upstream updateEvent(event.id, { joined: true, participants: event.participants + 1, @@ -1017,6 +1030,48 @@ export function CreatorEventsProvider({ }, ], })); +======= + const addMatch = useCallback( + async ( + eventId: string, + teamA: string, + teamB: string, + matchTime: string, + multiplier: 1 | 2 | 3, + ): Promise => { + setIsLoading(true); + setError(null); + try { + const matchId = `match-${Date.now()}`; + const newMatch: CreatorEventMatch = { + id: matchId, + eventId, + teamA, + teamB, + matchTime, + outcome: "Pending", + multiplier, + }; + setMatchesCache((prev) => ({ + ...prev, + [eventId]: [...(prev[eventId] ?? []), newMatch], + })); + setEventCache((prev) => { + const event = prev[eventId]; + if (!event) return prev; + return { + ...prev, + [eventId]: { ...event, matchesCount: event.matchesCount + 1 }, + }; + }); + return matchId; + } finally { + setIsLoading(false); + } + }, + [], + ); +>>>>>>> Stashed changes return true; },