208 lines
5.6 KiB
TypeScript
208 lines
5.6 KiB
TypeScript
/**
|
|
* In-memory league membership data for alpha prototype
|
|
*/
|
|
|
|
export type MembershipRole = 'owner' | 'admin' | 'steward' | 'member';
|
|
export type MembershipStatus = 'active' | 'pending' | 'none';
|
|
|
|
export interface LeagueMembership {
|
|
leagueId: string;
|
|
driverId: string;
|
|
role: MembershipRole;
|
|
status: MembershipStatus;
|
|
joinedAt: Date;
|
|
}
|
|
|
|
export interface JoinRequest {
|
|
id: string;
|
|
leagueId: string;
|
|
driverId: string;
|
|
requestedAt: Date;
|
|
message?: string;
|
|
}
|
|
|
|
// In-memory storage
|
|
let memberships: LeagueMembership[] = [];
|
|
let joinRequests: JoinRequest[] = [];
|
|
|
|
// Current driver ID (matches the one in di-container)
|
|
const CURRENT_DRIVER_ID = 'driver-1';
|
|
|
|
// Initialize with seed data
|
|
export function initializeMembershipData() {
|
|
memberships = [
|
|
{
|
|
leagueId: 'league-1',
|
|
driverId: CURRENT_DRIVER_ID,
|
|
role: 'owner',
|
|
status: 'active',
|
|
joinedAt: new Date('2024-01-15'),
|
|
},
|
|
{
|
|
leagueId: 'league-1',
|
|
driverId: 'driver-2',
|
|
role: 'member',
|
|
status: 'active',
|
|
joinedAt: new Date('2024-02-01'),
|
|
},
|
|
{
|
|
leagueId: 'league-1',
|
|
driverId: 'driver-3',
|
|
role: 'admin',
|
|
status: 'active',
|
|
joinedAt: new Date('2024-02-15'),
|
|
},
|
|
];
|
|
|
|
joinRequests = [];
|
|
}
|
|
|
|
// Get membership for a driver in a league
|
|
export function getMembership(leagueId: string, driverId: string): LeagueMembership | null {
|
|
return memberships.find(m => m.leagueId === leagueId && m.driverId === driverId) || null;
|
|
}
|
|
|
|
// Get all members for a league
|
|
export function getLeagueMembers(leagueId: string): LeagueMembership[] {
|
|
return memberships.filter(m => m.leagueId === leagueId && m.status === 'active');
|
|
}
|
|
|
|
// Get pending join requests for a league
|
|
export function getJoinRequests(leagueId: string): JoinRequest[] {
|
|
return joinRequests.filter(r => r.leagueId === leagueId);
|
|
}
|
|
|
|
// Join a league
|
|
export function joinLeague(leagueId: string, driverId: string): void {
|
|
const existing = getMembership(leagueId, driverId);
|
|
if (existing) {
|
|
throw new Error('Already a member or have a pending request');
|
|
}
|
|
|
|
memberships.push({
|
|
leagueId,
|
|
driverId,
|
|
role: 'member',
|
|
status: 'active',
|
|
joinedAt: new Date(),
|
|
});
|
|
}
|
|
|
|
// Request to join a league (for invite-only leagues)
|
|
export function requestToJoin(leagueId: string, driverId: string, message?: string): void {
|
|
const existing = getMembership(leagueId, driverId);
|
|
if (existing) {
|
|
throw new Error('Already a member or have a pending request');
|
|
}
|
|
|
|
const existingRequest = joinRequests.find(r => r.leagueId === leagueId && r.driverId === driverId);
|
|
if (existingRequest) {
|
|
throw new Error('Join request already pending');
|
|
}
|
|
|
|
joinRequests.push({
|
|
id: `request-${Date.now()}`,
|
|
leagueId,
|
|
driverId,
|
|
requestedAt: new Date(),
|
|
message,
|
|
});
|
|
}
|
|
|
|
// Leave a league
|
|
export function leaveLeague(leagueId: string, driverId: string): void {
|
|
const membership = getMembership(leagueId, driverId);
|
|
if (!membership) {
|
|
throw new Error('Not a member of this league');
|
|
}
|
|
|
|
if (membership.role === 'owner') {
|
|
throw new Error('League owner cannot leave. Transfer ownership first.');
|
|
}
|
|
|
|
memberships = memberships.filter(m => !(m.leagueId === leagueId && m.driverId === driverId));
|
|
}
|
|
|
|
// Approve join request
|
|
export function approveJoinRequest(requestId: string): void {
|
|
const request = joinRequests.find(r => r.id === requestId);
|
|
if (!request) {
|
|
throw new Error('Join request not found');
|
|
}
|
|
|
|
memberships.push({
|
|
leagueId: request.leagueId,
|
|
driverId: request.driverId,
|
|
role: 'member',
|
|
status: 'active',
|
|
joinedAt: new Date(),
|
|
});
|
|
|
|
joinRequests = joinRequests.filter(r => r.id !== requestId);
|
|
}
|
|
|
|
// Reject join request
|
|
export function rejectJoinRequest(requestId: string): void {
|
|
joinRequests = joinRequests.filter(r => r.id !== requestId);
|
|
}
|
|
|
|
// Remove member (admin action)
|
|
export function removeMember(leagueId: string, driverId: string, removedBy: string): void {
|
|
const removerMembership = getMembership(leagueId, removedBy);
|
|
if (!removerMembership || (removerMembership.role !== 'owner' && removerMembership.role !== 'admin')) {
|
|
throw new Error('Only owners and admins can remove members');
|
|
}
|
|
|
|
const targetMembership = getMembership(leagueId, driverId);
|
|
if (!targetMembership) {
|
|
throw new Error('Member not found');
|
|
}
|
|
|
|
if (targetMembership.role === 'owner') {
|
|
throw new Error('Cannot remove league owner');
|
|
}
|
|
|
|
memberships = memberships.filter(m => !(m.leagueId === leagueId && m.driverId === driverId));
|
|
}
|
|
|
|
// Update member role
|
|
export function updateMemberRole(
|
|
leagueId: string,
|
|
driverId: string,
|
|
newRole: MembershipRole,
|
|
updatedBy: string
|
|
): void {
|
|
const updaterMembership = getMembership(leagueId, updatedBy);
|
|
if (!updaterMembership || updaterMembership.role !== 'owner') {
|
|
throw new Error('Only league owner can change roles');
|
|
}
|
|
|
|
const targetMembership = getMembership(leagueId, driverId);
|
|
if (!targetMembership) {
|
|
throw new Error('Member not found');
|
|
}
|
|
|
|
if (newRole === 'owner') {
|
|
throw new Error('Use transfer ownership to change owner');
|
|
}
|
|
|
|
memberships = memberships.map(m =>
|
|
m.leagueId === leagueId && m.driverId === driverId
|
|
? { ...m, role: newRole }
|
|
: m
|
|
);
|
|
}
|
|
|
|
// Check if driver is owner or admin
|
|
export function isOwnerOrAdmin(leagueId: string, driverId: string): boolean {
|
|
const membership = getMembership(leagueId, driverId);
|
|
return membership?.role === 'owner' || membership?.role === 'admin';
|
|
}
|
|
|
|
// Get current driver ID
|
|
export function getCurrentDriverId(): string {
|
|
return CURRENT_DRIVER_ID;
|
|
}
|
|
|
|
// Initialize on module load
|
|
initializeMembershipData(); |