diff --git a/app/components/draft/AvailableParticipantsSection.tsx b/app/components/draft/AvailableParticipantsSection.tsx
index 05addc2..53d5824 100644
--- a/app/components/draft/AvailableParticipantsSection.tsx
+++ b/app/components/draft/AvailableParticipantsSection.tsx
@@ -193,7 +193,7 @@ export function AvailableParticipantsSection({
{participant.sport.name}
- {participant.expectedValue}
+ {participant.expectedValue ? participant.expectedValue.toFixed(1) : "—"}
|
{hasTeam && (
diff --git a/app/models/draft-utils.ts b/app/models/draft-utils.ts
index 91c4e27..9a202f5 100644
--- a/app/models/draft-utils.ts
+++ b/app/models/draft-utils.ts
@@ -294,10 +294,12 @@ export async function getTopAvailableParticipant(
allParticipants.push(...seasonParticipants);
}
- // Sort by EV desc, then name
+ // Sort by EV desc, then name (expectedValue is a decimal string from DB)
allParticipants.sort((a, b) => {
- if (b.expectedValue !== a.expectedValue) {
- return b.expectedValue - a.expectedValue;
+ const evA = parseFloat(String(a.expectedValue)) || 0;
+ const evB = parseFloat(String(b.expectedValue)) || 0;
+ if (evB !== evA) {
+ return evB - evA;
}
return a.name.localeCompare(b.name);
});
diff --git a/app/models/participant-expected-value.ts b/app/models/participant-expected-value.ts
index bb455c2..a4f3296 100644
--- a/app/models/participant-expected-value.ts
+++ b/app/models/participant-expected-value.ts
@@ -6,7 +6,7 @@
*/
import { database } from "~/database/context";
-import { participantExpectedValues } from "~/database/schema";
+import { participantExpectedValues, participants } from "~/database/schema";
import { eq, and } from "drizzle-orm";
import type { ProbabilityDistribution, ScoringRules } from "~/services/ev-calculator";
import { calculateEV, validateProbabilities, normalizeProbabilities } from "~/services/ev-calculator";
@@ -95,6 +95,8 @@ export async function upsertParticipantEV(
const now = new Date();
+ let result: ParticipantEV;
+
if (existing.length > 0) {
// Update existing
const updated = await db
@@ -117,7 +119,7 @@ export async function upsertParticipantEV(
.where(eq(participantExpectedValues.id, existing[0].id))
.returning();
- return updated[0];
+ result = updated[0];
} else {
// Create new
const created = await db
@@ -141,8 +143,16 @@ export async function upsertParticipantEV(
})
.returning();
- return created[0];
+ result = created[0];
}
+
+ // Sync calculated EV to participants table for draft room ranking
+ await db
+ .update(participants)
+ .set({ expectedValue: expectedValue.toString(), updatedAt: now })
+ .where(eq(participants.id, participantId));
+
+ return result;
}
/**
@@ -211,6 +221,12 @@ export async function deleteParticipantEV(
eq(participantExpectedValues.sportsSeasonId, sportsSeasonId)
)
);
+
+ // Reset participant EV to 0
+ await db
+ .update(participants)
+ .set({ expectedValue: "0", updatedAt: new Date() })
+ .where(eq(participants.id, participantId));
}
/**
@@ -270,16 +286,23 @@ export async function recalculateEV(
const newEV = calculateEV(probabilities, newScoringRules);
const db = database();
+ const now = new Date();
const updated = await db
.update(participantExpectedValues)
.set({
expectedValue: newEV.toString(),
- calculatedAt: new Date(),
- updatedAt: new Date(),
+ calculatedAt: now,
+ updatedAt: now,
})
.where(eq(participantExpectedValues.id, existing.id))
.returning();
+ // Sync recalculated EV to participants table
+ await db
+ .update(participants)
+ .set({ expectedValue: newEV.toString(), updatedAt: now })
+ .where(eq(participants.id, participantId));
+
return updated[0];
}
diff --git a/app/routes/admin.sports-seasons.$id.participants.tsx b/app/routes/admin.sports-seasons.$id.participants.tsx
index e5caeaa..0b3c665 100644
--- a/app/routes/admin.sports-seasons.$id.participants.tsx
+++ b/app/routes/admin.sports-seasons.$id.participants.tsx
@@ -79,7 +79,7 @@ export async function action({ request, params }: Route.ActionArgs) {
name,
shortName: null,
externalId: null,
- expectedValue: 0,
+ expectedValue: "0",
});
}
@@ -103,7 +103,7 @@ export async function action({ request, params }: Route.ActionArgs) {
name: name.trim(),
shortName: null,
externalId: null,
- expectedValue: 0,
+ expectedValue: "0",
});
return { success: true };
diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx
index c4bd547..5eb0700 100644
--- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx
+++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx
@@ -144,6 +144,12 @@ export async function loader(args: any) {
desc(schema.participants.expectedValue),
asc(schema.participants.name)
);
+
+ // Parse decimal expectedValue (Drizzle returns strings for decimal columns)
+ availableParticipants = availableParticipants.map((p: any) => ({
+ ...p,
+ expectedValue: parseFloat(p.expectedValue) || 0,
+ }));
}
// Load user's team queue if they have a team
@@ -1054,7 +1060,7 @@ export default function DraftRoom() {
{participant.sport.name}
|
- {participant.expectedValue}
+ {participant.expectedValue ? participant.expectedValue.toFixed(1) : "—"}
|
|