Allow commissioners to add league members as co-commissioners

Non-admin commissioners can now add users who already own a team in
the league as co-commissioners. Admins still see the full user list.
Previously the add-commissioner form was admin-only.

https://claude.ai/code/session_01NSRMSYtb7jSFbngDS8okn3
This commit is contained in:
Claude 2026-02-20 16:33:28 +00:00
parent a8ab5b6fd3
commit fd1510cd7d
No known key found for this signature in database

View file

@ -126,11 +126,15 @@ export async function loader(args: Route.LoaderArgs) {
: null; : null;
}) })
); );
const ownerMap = new Map( const validOwners = owners.filter((o): o is NonNullable<typeof o> => o !== null);
owners const ownerMap = new Map(validOwners.map((o) => [o.clerkId, o.name]));
.filter((o): o is NonNullable<typeof o> => o !== null)
.map((o) => [o.clerkId, o.name]) // League members (team owners) - available to all commissioners for adding co-commissioners
); const leagueMembers = validOwners.map((o) => ({
id: o.id,
clerkId: o.clerkId,
name: o.name,
}));
return { return {
league, league,
@ -142,6 +146,7 @@ export async function loader(args: Route.LoaderArgs) {
draftSlots, draftSlots,
isAdmin, isAdmin,
allUsers, allUsers,
leagueMembers,
ownerMap: Object.fromEntries(ownerMap), ownerMap: Object.fromEntries(ownerMap),
commissioners: commissionerUserData, commissioners: commissionerUserData,
currentUserId: userId, currentUserId: userId,
@ -544,7 +549,7 @@ export async function action(args: Route.ActionArgs) {
} }
export default function LeagueSettings({ loaderData, actionData }: Route.ComponentProps) { export default function LeagueSettings({ loaderData, actionData }: Route.ComponentProps) {
const { league, season, teams, teamCount, teamsWithOwners, allSportsSeasons, draftSlots, isAdmin, allUsers, ownerMap, commissioners, currentUserId } = loaderData; const { league, season, teams, teamCount, teamsWithOwners, allSportsSeasons, draftSlots, isAdmin, allUsers, leagueMembers, ownerMap, commissioners, currentUserId } = loaderData;
const navigation = useNavigation(); const navigation = useNavigation();
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [selectedSports, setSelectedSports] = useState<Set<string>>( const [selectedSports, setSelectedSports] = useState<Set<string>>(
@ -1170,17 +1175,17 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
))} ))}
</div> </div>
{isAdmin && ( <div className="border-t pt-4">
<div className="border-t pt-4"> <p className="text-sm font-medium mb-3">Add Commissioner</p>
<p className="text-sm font-medium mb-3">Add Commissioner</p> <Form method="post" className="flex gap-2">
<Form method="post" className="flex gap-2"> <input type="hidden" name="intent" value="add-commissioner" />
<input type="hidden" name="intent" value="add-commissioner" /> <Select name="userClerkId" required>
<Select name="userClerkId" required> <SelectTrigger className="flex-1">
<SelectTrigger className="flex-1"> <SelectValue placeholder="Select a user" />
<SelectValue placeholder="Select a user" /> </SelectTrigger>
</SelectTrigger> <SelectContent>
<SelectContent> {isAdmin ? (
{allUsers.map((user) => { allUsers.map((user) => {
const alreadyCommissioner = commissioners.some( const alreadyCommissioner = commissioners.some(
(c) => c.userId === user.clerkId (c) => c.userId === user.clerkId
); );
@ -1194,20 +1199,36 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
{alreadyCommissioner && " (already commissioner)"} {alreadyCommissioner && " (already commissioner)"}
</SelectItem> </SelectItem>
); );
})} })
</SelectContent> ) : (
</Select> leagueMembers.map((member) => {
<Button const alreadyCommissioner = commissioners.some(
type="submit" (c) => c.userId === member.clerkId
variant="outline" );
size="sm" return (
disabled={navigation.state === "submitting"} <SelectItem
> key={member.id}
Add value={member.clerkId}
</Button> disabled={alreadyCommissioner}
</Form> >
</div> {member.name || "Unknown"}
)} {alreadyCommissioner && " (already commissioner)"}
</SelectItem>
);
})
)}
</SelectContent>
</Select>
<Button
type="submit"
variant="outline"
size="sm"
disabled={navigation.state === "submitting"}
>
Add
</Button>
</Form>
</div>
</CardContent> </CardContent>
</Card> </Card>