Fix BetterAuth field mapping and add owner-prefixed team names
- Fix auth.server.ts: use camelCase Drizzle field names for BetterAuth adapter (was snake_case, causing user inserts to fail); add generateId: "uuid" so PostgreSQL UUID columns accept generated IDs - Add prependOwnerToTeamName / stripOwnerFromTeamName utilities - Invite join, league creation, and settings assign/remove all now manage the owner-prefix on team names atomically Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e201ecd28a
commit
d2282a263e
5 changed files with 82 additions and 14 deletions
|
|
@ -23,16 +23,21 @@ export const auth = betterAuth({
|
|||
provider: "pg",
|
||||
usePlural: true,
|
||||
}),
|
||||
advanced: {
|
||||
database: {
|
||||
generateId: "uuid",
|
||||
},
|
||||
},
|
||||
user: {
|
||||
fields: {
|
||||
name: "display_name",
|
||||
image: "image_url",
|
||||
name: "displayName",
|
||||
image: "imageUrl",
|
||||
},
|
||||
additionalFields: {
|
||||
firstName: { type: "string", required: false, fieldName: "first_name" },
|
||||
lastName: { type: "string", required: false, fieldName: "last_name" },
|
||||
firstName: { type: "string", required: false, fieldName: "firstName" },
|
||||
lastName: { type: "string", required: false, fieldName: "lastName" },
|
||||
username: { type: "string", required: false, fieldName: "username" },
|
||||
isAdmin: { type: "boolean", defaultValue: false, fieldName: "is_admin" },
|
||||
isAdmin: { type: "boolean", defaultValue: false, fieldName: "isAdmin" },
|
||||
},
|
||||
},
|
||||
emailAndPassword: {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import {
|
|||
claimTeam,
|
||||
isUserLeagueMember,
|
||||
findUserById,
|
||||
getUserDisplayName,
|
||||
} from "~/models";
|
||||
import { prependOwnerToTeamName } from "~/utils/team-names";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
|
|
@ -105,7 +105,8 @@ export async function action(args: Route.ActionArgs) {
|
|||
|
||||
// Claim the first available team, setting owner and name atomically
|
||||
const team = availableTeams[0];
|
||||
const teamName = `Team ${getUserDisplayName(user) ?? "Member"}`;
|
||||
const username = user.username ?? user.displayName ?? "Member";
|
||||
const teamName = prependOwnerToTeamName(team.name, username);
|
||||
await claimTeam(team.id, userId, teamName);
|
||||
|
||||
// Redirect to league page
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ import {
|
|||
removeCommissionerByLeagueAndUser,
|
||||
} from "~/models/commissioner";
|
||||
import { findCurrentSeasonWithSports, updateSeason, type NewSeason } from "~/models/season";
|
||||
import { findTeamsBySeasonId, deleteTeam, removeTeamOwner, claimTeam } from "~/models/team";
|
||||
import { findTeamsBySeasonId, deleteTeam, removeTeamOwner, claimTeam, findTeamById } from "~/models/team";
|
||||
import { findAllUsers, findUsersByIds, findUserById, getUserDisplayName, isUserAdmin } from "~/models/user";
|
||||
import { prependOwnerToTeamName, stripOwnerFromTeamName, generateUniqueTeamNames } from "~/utils/team-names";
|
||||
import { unlinkSportFromSeason, linkMultipleSportsToSeason } from "~/models/season-sport";
|
||||
import { findDraftableSportsSeasons, findSportsSeasonsByIds } from "~/models/sports-season";
|
||||
import { findDraftSlotsBySeasonId, setDraftOrder, randomizeDraftOrder } from "~/models/draft-slot";
|
||||
|
|
@ -400,7 +401,23 @@ export async function action(args: Route.ActionArgs) {
|
|||
}
|
||||
|
||||
try {
|
||||
await removeTeamOwner(teamId);
|
||||
const team = await findTeamById(teamId);
|
||||
if (team?.ownerId) {
|
||||
const owner = await findUserById(team.ownerId);
|
||||
const username = owner?.username ?? owner?.displayName;
|
||||
if (username) {
|
||||
const strippedName = stripOwnerFromTeamName(team.name, username);
|
||||
await removeTeamOwner(teamId);
|
||||
if (strippedName !== team.name) {
|
||||
const { renameTeam } = await import("~/models/team");
|
||||
await renameTeam(teamId, strippedName);
|
||||
}
|
||||
} else {
|
||||
await removeTeamOwner(teamId);
|
||||
}
|
||||
} else {
|
||||
await removeTeamOwner(teamId);
|
||||
}
|
||||
return { success: true, message: "Owner removed successfully" };
|
||||
} catch (error) {
|
||||
logger.error("Error removing team owner:", error);
|
||||
|
|
@ -438,12 +455,18 @@ export async function action(args: Route.ActionArgs) {
|
|||
|
||||
// Check if the target team already has an owner
|
||||
const targetTeam = teams.find(team => team.id === teamId);
|
||||
if (targetTeam?.ownerId) {
|
||||
if (!targetTeam) {
|
||||
return { error: "Team not found" };
|
||||
}
|
||||
if (targetTeam.ownerId) {
|
||||
return { error: "This team already has an owner. Remove the current owner first." };
|
||||
}
|
||||
|
||||
try {
|
||||
const teamName = `Team ${getUserDisplayName(assignedUser) ?? "Member"}`;
|
||||
const teamName = prependOwnerToTeamName(
|
||||
targetTeam.name,
|
||||
assignedUser.username ?? assignedUser.displayName ?? "Member"
|
||||
);
|
||||
await claimTeam(teamId, assignedUserId, teamName);
|
||||
|
||||
return { success: true, message: "Owner assigned successfully" };
|
||||
|
|
@ -718,11 +741,12 @@ export async function action(args: Route.ActionArgs) {
|
|||
|
||||
// Add or remove teams as needed
|
||||
if (newTeamCount > currentTeamCount) {
|
||||
const newNames = generateUniqueTeamNames(newTeamCount - currentTeamCount);
|
||||
const teamsToAdd = Array.from(
|
||||
{ length: newTeamCount - currentTeamCount },
|
||||
(_, i) => ({
|
||||
seasonId: season.id,
|
||||
name: `Team ${currentTeamCount + i + 1}`,
|
||||
name: newNames[i],
|
||||
ownerId: null as null,
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { createManyTeams } from "~/models/team";
|
|||
import { findActiveSeasonTemplates, findSeasonTemplateWithSportsSeasons } from "~/models/season-template";
|
||||
import { findDraftableSportsSeasons } from "~/models/sports-season";
|
||||
import { findUserById, updateUser } from "~/models/user";
|
||||
import { generateUniqueTeamNames } from "~/utils/team-names";
|
||||
import { generateUniqueTeamNames, prependOwnerToTeamName } from "~/utils/team-names";
|
||||
import { format } from "date-fns";
|
||||
import { CalendarClock, Check, Star, Swords, Trophy } from "lucide-react";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
|
|
@ -247,9 +247,13 @@ export async function action(args: Route.ActionArgs) {
|
|||
|
||||
const joinAsPlayer = formData.get("joinAsPlayer") === "on";
|
||||
const teamNames = generateUniqueTeamNames(teamCountNum);
|
||||
const creator = await findUserById(userId);
|
||||
const creatorUsername = creator?.username ?? creator?.displayName;
|
||||
const teams = teamNames.map((teamName, i) => ({
|
||||
seasonId: season.id,
|
||||
name: teamName,
|
||||
name: joinAsPlayer && i === 0 && creatorUsername
|
||||
? prependOwnerToTeamName(teamName, creatorUsername)
|
||||
: teamName,
|
||||
ownerId: joinAsPlayer && i === 0 ? userId : null,
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -75,3 +75,37 @@ export function generateUniqueTeamNames(count: number): string[] {
|
|||
|
||||
return Array.from(names);
|
||||
}
|
||||
|
||||
function toTitleCase(str: string): string {
|
||||
if (!str) return str;
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
function possessiveSuffix(name: string): string {
|
||||
return name.endsWith("s") ? "'" : "'s";
|
||||
}
|
||||
|
||||
export function prependOwnerToTeamName(
|
||||
baseName: string,
|
||||
username: string
|
||||
): string {
|
||||
const titleName = toTitleCase(username);
|
||||
return `${titleName}${possessiveSuffix(titleName)} ${baseName}`;
|
||||
}
|
||||
|
||||
export function stripOwnerFromTeamName(
|
||||
teamName: string,
|
||||
username: string
|
||||
): string {
|
||||
const titleName = toTitleCase(username);
|
||||
const prefixWithS = `${titleName}'s `;
|
||||
const prefixWithoutS = `${titleName}' `;
|
||||
|
||||
if (teamName.startsWith(prefixWithS)) {
|
||||
return teamName.slice(prefixWithS.length);
|
||||
}
|
||||
if (teamName.startsWith(prefixWithoutS)) {
|
||||
return teamName.slice(prefixWithoutS.length);
|
||||
}
|
||||
return teamName;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue