feat: add team settings route and logo URL field to teams table

This commit is contained in:
Chris Parsons 2025-10-14 22:04:37 -07:00
parent 025ba82cb2
commit 6c0684f3d7
7 changed files with 1208 additions and 9 deletions

View file

@ -6,6 +6,7 @@ export default [
route("leagues/new", "routes/leagues/new.tsx"),
route("leagues/:leagueId", "routes/leagues/$leagueId.tsx"),
route("leagues/:leagueId/settings", "routes/leagues/$leagueId.settings.tsx"),
route("teams/:teamId/settings", "routes/teams/$teamId.settings.tsx"),
route("api/webhooks/clerk", "routes/api/webhooks/clerk.ts"),
route("user-profile", "routes/user-profile.tsx"),
route("how-to-play", "routes/how-to-play.tsx"),

View file

@ -134,13 +134,17 @@ export default function LeagueHome({ loaderData }: Route.ComponentProps) {
useEffect(() => {
if (searchParams.get("updated") === "true") {
toast.success("League updated successfully");
toast.success("Team updated successfully");
setSearchParams({});
}
if (searchParams.get("joined") === "true") {
toast.success("Welcome to the league! You've been assigned a team.");
setSearchParams({});
}
if (searchParams.get("left") === "true") {
toast.success("You have left the league. Your team is now available.");
setSearchParams({});
}
}, [searchParams, setSearchParams]);
const handleCopyInviteLink = async () => {
@ -163,14 +167,22 @@ export default function LeagueHome({ loaderData }: Route.ComponentProps) {
<div className="flex items-center justify-between mb-2">
<h1 className="text-4xl font-bold">{league.name}</h1>
<div className="flex gap-2">
{isUserCommissioner && (
{teams.find((t) => t.ownerId === currentUserId) && (
<Button variant="outline" asChild>
<Link to={`/leagues/${league.id}/settings`}>Settings</Link>
<Link
to={`/teams/${teams.find((t) => t.ownerId === currentUserId)?.id}/settings`}
>
Team Settings
</Link>
</Button>
)}
{isUserCommissioner && (
<Button variant="outline" asChild>
<Link to={`/leagues/${league.id}/settings`}>
League Settings
</Link>
</Button>
)}
<Button variant="outline" asChild>
<Link to="/">Back to Home</Link>
</Button>
</div>
</div>
{season && (
@ -224,14 +236,17 @@ export default function LeagueHome({ loaderData }: Route.ComponentProps) {
<CardHeader>
<CardTitle>Teams</CardTitle>
<CardDescription>
{teams.length} team{teams.length !== 1 ? "s" : ""} in this league
{teams.length} team{teams.length !== 1 ? "s" : ""} in this
league
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-3">
{teams.map((team) => {
const isOwned = team.ownerId === currentUserId;
const ownerName = team.ownerId ? ownerMap[team.ownerId] : null;
const ownerName = team.ownerId
? ownerMap[team.ownerId]
: null;
return (
<Card
key={team.id}
@ -307,7 +322,9 @@ export default function LeagueHome({ loaderData }: Route.ComponentProps) {
<p className="font-medium">
{commissionerName || "Unknown User"}
{commissioner.userId === currentUserId && (
<span className="ml-2 text-xs text-primary">(You)</span>
<span className="ml-2 text-xs text-primary">
(You)
</span>
)}
</p>
</div>

View file

@ -0,0 +1,213 @@
import { Form, redirect, useNavigate } from "react-router";
import { getAuth } from "@clerk/react-router/server";
import type { Route } from "./+types/$teamId.settings";
import {
findTeamById,
updateTeam,
removeTeamOwner,
} from "~/models/team";
import { findSeasonById } from "~/models/season";
import { Button } from "~/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "~/components/ui/alert-dialog";
export async function loader(args: Route.LoaderArgs) {
const { params } = args;
const { teamId } = params;
const { userId } = await getAuth(args);
if (!userId) {
throw new Response("You must be logged in", { status: 401 });
}
const team = await findTeamById(teamId);
if (!team) {
throw new Response("Team not found", { status: 404 });
}
// Only the team owner can access settings
if (team.ownerId !== userId) {
throw new Response("You do not have access to this team", { status: 403 });
}
const season = await findSeasonById(team.seasonId);
if (!season) {
throw new Response("Season not found", { status: 404 });
}
return { team, season };
}
export async function action(args: Route.ActionArgs) {
const { params, request } = args;
const { teamId } = params;
const { userId } = await getAuth(args);
if (!userId) {
throw new Response("You must be logged in", { status: 401 });
}
const team = await findTeamById(teamId);
if (!team) {
throw new Response("Team not found", { status: 404 });
}
// Only the team owner can modify settings
if (team.ownerId !== userId) {
throw new Response("You do not have access to this team", { status: 403 });
}
const formData = await request.formData();
const intent = formData.get("intent");
if (intent === "update") {
const name = formData.get("name");
const logoUrl = formData.get("logoUrl");
if (!name || typeof name !== "string") {
return { error: "Team name is required" };
}
await updateTeam(teamId, {
name: name.trim(),
logoUrl: logoUrl && typeof logoUrl === "string" ? logoUrl.trim() : undefined,
});
const season = await findSeasonById(team.seasonId);
return redirect(`/leagues/${season?.leagueId}?updated=true`);
}
if (intent === "leave") {
await removeTeamOwner(teamId);
const season = await findSeasonById(team.seasonId);
return redirect(`/leagues/${season?.leagueId}?left=true`);
}
return { error: "Invalid action" };
}
export default function TeamSettings({ loaderData }: Route.ComponentProps) {
const { team, season } = loaderData;
const navigate = useNavigate();
return (
<div className="container mx-auto py-8 px-4">
<div className="max-w-2xl mx-auto">
<div className="mb-8">
<div className="flex items-center justify-between mb-2">
<h1 className="text-4xl font-bold">Team Settings</h1>
<Button
variant="outline"
onClick={() => navigate(`/leagues/${season.leagueId}`)}
>
Back to League
</Button>
</div>
<p className="text-muted-foreground">
Manage your team settings and preferences
</p>
</div>
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Team Information</CardTitle>
<CardDescription>
Update your team name and logo
</CardDescription>
</CardHeader>
<CardContent>
<Form method="post" className="space-y-4">
<input type="hidden" name="intent" value="update" />
<div className="space-y-2">
<Label htmlFor="name">Team Name</Label>
<Input
id="name"
name="name"
type="text"
defaultValue={team.name}
required
maxLength={255}
/>
</div>
<div className="space-y-2">
<Label htmlFor="logoUrl">Team Logo URL (optional)</Label>
<Input
id="logoUrl"
name="logoUrl"
type="url"
defaultValue={team.logoUrl || ""}
placeholder="https://example.com/logo.png"
maxLength={512}
/>
<p className="text-xs text-muted-foreground">
Enter a URL to an image for your team logo
</p>
</div>
<Button type="submit">Save Changes</Button>
</Form>
</CardContent>
</Card>
<Card className="border-destructive">
<CardHeader>
<CardTitle className="text-destructive">Danger Zone</CardTitle>
<CardDescription>
Irreversible actions for your team
</CardDescription>
</CardHeader>
<CardContent>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Leave League</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This will remove you as the owner of "{team.name}" and make the team
available for others to claim. This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Form method="post">
<input type="hidden" name="intent" value="leave" />
<AlertDialogAction type="submit" className="bg-destructive hover:bg-destructive/90">
Leave League
</AlertDialogAction>
</Form>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</CardContent>
</Card>
</div>
</div>
</div>
);
}

View file

@ -79,6 +79,7 @@ export const teams = pgTable("teams", {
.notNull()
.references(() => seasons.id, { onDelete: "cascade" }),
name: varchar("name", { length: 255 }).notNull(),
logoUrl: varchar("logo_url", { length: 512 }),
ownerId: varchar("owner_id", { length: 255 }), // Clerk user ID, nullable
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),

View file

@ -0,0 +1 @@
ALTER TABLE "teams" ADD COLUMN "logo_url" varchar(512);

View file

@ -0,0 +1,959 @@
{
"id": "18540fa4-0d1d-4b45-914b-4bf80ad5dadd",
"prevId": "93dd6587-4fbf-4269-8777-db6a88e40d38",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.commissioners": {
"name": "commissioners",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"league_id": {
"name": "league_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"commissioners_league_id_leagues_id_fk": {
"name": "commissioners_league_id_leagues_id_fk",
"tableFrom": "commissioners",
"tableTo": "leagues",
"columnsFrom": [
"league_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.leagues": {
"name": "leagues",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"created_by": {
"name": "created_by",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"current_season_id": {
"name": "current_season_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.participant_results": {
"name": "participant_results",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"participant_id": {
"name": "participant_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"sports_season_id": {
"name": "sports_season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"final_position": {
"name": "final_position",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"points_awarded": {
"name": "points_awarded",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"qualifying_points": {
"name": "qualifying_points",
"type": "numeric(10, 2)",
"primaryKey": false,
"notNull": false
},
"notes": {
"name": "notes",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"participant_results_participant_id_participants_id_fk": {
"name": "participant_results_participant_id_participants_id_fk",
"tableFrom": "participant_results",
"tableTo": "participants",
"columnsFrom": [
"participant_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"participant_results_sports_season_id_sports_seasons_id_fk": {
"name": "participant_results_sports_season_id_sports_seasons_id_fk",
"tableFrom": "participant_results",
"tableTo": "sports_seasons",
"columnsFrom": [
"sports_season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.participants": {
"name": "participants",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"sports_season_id": {
"name": "sports_season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"short_name": {
"name": "short_name",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"participants_sports_season_id_sports_seasons_id_fk": {
"name": "participants_sports_season_id_sports_seasons_id_fk",
"tableFrom": "participants",
"tableTo": "sports_seasons",
"columnsFrom": [
"sports_season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.season_sports": {
"name": "season_sports",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"season_id": {
"name": "season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"sports_season_id": {
"name": "sports_season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"season_sports_season_id_seasons_id_fk": {
"name": "season_sports_season_id_seasons_id_fk",
"tableFrom": "season_sports",
"tableTo": "seasons",
"columnsFrom": [
"season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"season_sports_sports_season_id_sports_seasons_id_fk": {
"name": "season_sports_sports_season_id_sports_seasons_id_fk",
"tableFrom": "season_sports",
"tableTo": "sports_seasons",
"columnsFrom": [
"sports_season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.season_template_sports": {
"name": "season_template_sports",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"template_id": {
"name": "template_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"sports_season_id": {
"name": "sports_season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"season_template_sports_template_id_season_templates_id_fk": {
"name": "season_template_sports_template_id_season_templates_id_fk",
"tableFrom": "season_template_sports",
"tableTo": "season_templates",
"columnsFrom": [
"template_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"season_template_sports_sports_season_id_sports_seasons_id_fk": {
"name": "season_template_sports_sports_season_id_sports_seasons_id_fk",
"tableFrom": "season_template_sports",
"tableTo": "sports_seasons",
"columnsFrom": [
"sports_season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.season_templates": {
"name": "season_templates",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"year": {
"name": "year",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"is_active": {
"name": "is_active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.seasons": {
"name": "seasons",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"league_id": {
"name": "league_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"year": {
"name": "year",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "season_status",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'pre_draft'"
},
"template_id": {
"name": "template_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"flex_spots": {
"name": "flex_spots",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"invite_code": {
"name": "invite_code",
"type": "varchar(20)",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"seasons_league_id_leagues_id_fk": {
"name": "seasons_league_id_leagues_id_fk",
"tableFrom": "seasons",
"tableTo": "leagues",
"columnsFrom": [
"league_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"seasons_template_id_season_templates_id_fk": {
"name": "seasons_template_id_season_templates_id_fk",
"tableFrom": "seasons",
"tableTo": "season_templates",
"columnsFrom": [
"template_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_invite_code_unique": {
"name": "seasons_invite_code_unique",
"nullsNotDistinct": false,
"columns": [
"invite_code"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.sports": {
"name": "sports",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "sport_type",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"icon_url": {
"name": "icon_url",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"sports_slug_unique": {
"name": "sports_slug_unique",
"nullsNotDistinct": false,
"columns": [
"slug"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.sports_seasons": {
"name": "sports_seasons",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"sport_id": {
"name": "sport_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"year": {
"name": "year",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_date": {
"name": "start_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_date": {
"name": "end_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "sports_season_status",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'upcoming'"
},
"scoring_type": {
"name": "scoring_type",
"type": "scoring_type",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"sports_seasons_sport_id_sports_id_fk": {
"name": "sports_seasons_sport_id_sports_id_fk",
"tableFrom": "sports_seasons",
"tableTo": "sports",
"columnsFrom": [
"sport_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.teams": {
"name": "teams",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"season_id": {
"name": "season_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"logo_url": {
"name": "logo_url",
"type": "varchar(512)",
"primaryKey": false,
"notNull": false
},
"owner_id": {
"name": "owner_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"teams_season_id_seasons_id_fk": {
"name": "teams_season_id_seasons_id_fk",
"tableFrom": "teams",
"tableTo": "seasons",
"columnsFrom": [
"season_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"clerk_id": {
"name": "clerk_id",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"username": {
"name": "username",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"display_name": {
"name": "display_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"first_name": {
"name": "first_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"last_name": {
"name": "last_name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"image_url": {
"name": "image_url",
"type": "varchar(512)",
"primaryKey": false,
"notNull": false
},
"is_admin": {
"name": "is_admin",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_clerk_id_unique": {
"name": "users_clerk_id_unique",
"nullsNotDistinct": false,
"columns": [
"clerk_id"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
"public.scoring_type": {
"name": "scoring_type",
"schema": "public",
"values": [
"playoffs",
"regular_season",
"majors"
]
},
"public.season_status": {
"name": "season_status",
"schema": "public",
"values": [
"pre_draft",
"draft",
"active",
"completed"
]
},
"public.sport_type": {
"name": "sport_type",
"schema": "public",
"values": [
"team",
"individual"
]
},
"public.sports_season_status": {
"name": "sports_season_status",
"schema": "public",
"values": [
"upcoming",
"active",
"completed"
]
}
},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View file

@ -85,6 +85,13 @@
"when": 1760501621605,
"tag": "0011_gifted_mystique",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1760504208398,
"tag": "0012_yielding_phil_sheldon",
"breakpoints": true
}
]
}