wip
This commit is contained in:
23
apps/website/lib/leagueCovers.ts
Normal file
23
apps/website/lib/leagueCovers.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
function hashString(input: string): number {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < input.length; i += 1) {
|
||||
hash = (hash * 31 + input.charCodeAt(i)) | 0;
|
||||
}
|
||||
return Math.abs(hash);
|
||||
}
|
||||
|
||||
const GRADIENTS: string[] = [
|
||||
'bg-gradient-to-r from-blue-500/80 via-indigo-500/80 to-purple-500/80',
|
||||
'bg-gradient-to-r from-emerald-500/80 via-teal-500/80 to-cyan-500/80',
|
||||
'bg-gradient-to-r from-amber-500/80 via-orange-500/80 to-rose-500/80',
|
||||
'bg-gradient-to-r from-fuchsia-500/80 via-purple-500/80 to-sky-500/80',
|
||||
'bg-gradient-to-r from-lime-500/80 via-emerald-500/80 to-green-500/80',
|
||||
'bg-gradient-to-r from-slate-500/80 via-slate-600/80 to-slate-700/80',
|
||||
];
|
||||
|
||||
export function getLeagueCoverClasses(leagueId: string): string {
|
||||
const index = hashString(leagueId) % GRADIENTS.length;
|
||||
const baseLayout =
|
||||
'w-full h-32 rounded-lg overflow-hidden border border-charcoal-outline/60';
|
||||
return baseLayout + ' ' + GRADIENTS[index];
|
||||
}
|
||||
71
apps/website/lib/leagueRoles.ts
Normal file
71
apps/website/lib/leagueRoles.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { MembershipRole } from '@/lib/racingLegacyFacade';
|
||||
|
||||
export type LeagueRole = MembershipRole;
|
||||
|
||||
export function isLeagueOwnerRole(role: LeagueRole): boolean {
|
||||
return role === 'owner';
|
||||
}
|
||||
|
||||
export function isLeagueAdminRole(role: LeagueRole): boolean {
|
||||
return role === 'admin';
|
||||
}
|
||||
|
||||
export function isLeagueStewardRole(role: LeagueRole): boolean {
|
||||
return role === 'steward';
|
||||
}
|
||||
|
||||
export function isLeagueMemberRole(role: LeagueRole): boolean {
|
||||
return role === 'member';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for roles that should be treated as having elevated permissions.
|
||||
* This keeps UI logic open for future roles like steward, streamer, sponsor.
|
||||
*/
|
||||
export function isLeagueAdminOrHigherRole(role: LeagueRole): boolean {
|
||||
return role === 'owner' || role === 'admin' || role === 'steward';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordering helper for sorting memberships in tables.
|
||||
*/
|
||||
export function getLeagueRoleOrder(role: LeagueRole): number {
|
||||
const order: Record<LeagueRole, number> = {
|
||||
owner: 0,
|
||||
admin: 1,
|
||||
steward: 2,
|
||||
member: 3,
|
||||
};
|
||||
return order[role] ?? 99;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized display configuration for league membership roles.
|
||||
*/
|
||||
export function getLeagueRoleDisplay(
|
||||
role: LeagueRole,
|
||||
): { text: string; badgeClasses: string } {
|
||||
switch (role) {
|
||||
case 'owner':
|
||||
return {
|
||||
text: 'Owner',
|
||||
badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
|
||||
};
|
||||
case 'admin':
|
||||
return {
|
||||
text: 'Admin',
|
||||
badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',
|
||||
};
|
||||
case 'steward':
|
||||
return {
|
||||
text: 'Steward',
|
||||
badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',
|
||||
};
|
||||
case 'member':
|
||||
default:
|
||||
return {
|
||||
text: 'Member',
|
||||
badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
MembershipRole,
|
||||
MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import { getDriverAvatar, getTeamLogo, getLeagueBanner, memberships as seedMemberships, leagues as seedLeagues } from '@gridpilot/testing-support';
|
||||
|
||||
export type { MembershipRole, MembershipStatus };
|
||||
|
||||
@@ -97,6 +98,69 @@ function generateId(prefix: string): string {
|
||||
return `${prefix}-${idCounter++}`;
|
||||
}
|
||||
|
||||
// Initialize league memberships from static seed data
|
||||
(function initializeLeagueMembershipsFromSeed() {
|
||||
if (leagueMemberships.size > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const membershipsByLeague = new Map<string, LeagueMembership[]>();
|
||||
|
||||
// Create base active memberships from seed
|
||||
for (const membership of seedMemberships) {
|
||||
const list = membershipsByLeague.get(membership.leagueId) ?? [];
|
||||
const joinedAt = new Date(2024, 0, 1 + (idCounter % 28)).toISOString();
|
||||
|
||||
list.push({
|
||||
leagueId: membership.leagueId,
|
||||
driverId: membership.driverId,
|
||||
role: 'member',
|
||||
status: 'active',
|
||||
joinedAt,
|
||||
});
|
||||
|
||||
membershipsByLeague.set(membership.leagueId, list);
|
||||
}
|
||||
|
||||
// Ensure league owners are represented as owners in memberships
|
||||
for (const league of seedLeagues) {
|
||||
const list = membershipsByLeague.get(league.id) ?? [];
|
||||
const existingOwnerMembership = list.find((m) => m.driverId === league.ownerId);
|
||||
|
||||
if (existingOwnerMembership) {
|
||||
existingOwnerMembership.role = 'owner';
|
||||
} else {
|
||||
const joinedAt = new Date(2024, 0, 1 + (idCounter % 28)).toISOString();
|
||||
list.unshift({
|
||||
leagueId: league.id,
|
||||
driverId: league.ownerId,
|
||||
role: 'owner',
|
||||
status: 'active',
|
||||
joinedAt,
|
||||
});
|
||||
}
|
||||
|
||||
membershipsByLeague.set(league.id, list);
|
||||
}
|
||||
|
||||
// Store into facade-local maps
|
||||
for (const [leagueId, list] of membershipsByLeague.entries()) {
|
||||
leagueMemberships.set(leagueId, list);
|
||||
}
|
||||
})();
|
||||
|
||||
export function getDriverAvatarUrl(driverId: string): string {
|
||||
return getDriverAvatar(driverId);
|
||||
}
|
||||
|
||||
export function getTeamLogoUrl(teamId: string): string {
|
||||
return getTeamLogo(teamId);
|
||||
}
|
||||
|
||||
export function getLeagueBannerUrl(leagueId: string): string {
|
||||
return getLeagueBanner(leagueId);
|
||||
}
|
||||
|
||||
/**
|
||||
* League membership API
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user