142 lines
3.8 KiB
TypeScript
142 lines
3.8 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import Button from '@/components/ui/Button';
|
|
import {
|
|
getJoinTeamUseCase,
|
|
getLeaveTeamUseCase,
|
|
getGetDriverTeamQuery,
|
|
getTeamMembershipRepository,
|
|
} from '@/lib/di-container';
|
|
import { useEffectiveDriverId } from '@/lib/currentDriver';
|
|
import type { TeamMembership } from '@gridpilot/racing';
|
|
|
|
interface JoinTeamButtonProps {
|
|
teamId: string;
|
|
requiresApproval?: boolean;
|
|
onUpdate?: () => void;
|
|
}
|
|
|
|
export default function JoinTeamButton({
|
|
teamId,
|
|
requiresApproval = false,
|
|
onUpdate,
|
|
}: JoinTeamButtonProps) {
|
|
const [loading, setLoading] = useState(false);
|
|
const currentDriverId = useEffectiveDriverId();
|
|
const [membership, setMembership] = useState<TeamMembership | null>(null);
|
|
const [currentTeamName, setCurrentTeamName] = useState<string | null>(null);
|
|
const [currentTeamId, setCurrentTeamId] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
const load = async () => {
|
|
const membershipRepo = getTeamMembershipRepository();
|
|
const m = await membershipRepo.getMembership(teamId, currentDriverId);
|
|
setMembership(m);
|
|
|
|
const driverTeamQuery = getGetDriverTeamQuery();
|
|
const driverTeam = await driverTeamQuery.execute({ driverId: currentDriverId });
|
|
if (driverTeam) {
|
|
setCurrentTeamId(driverTeam.team.id);
|
|
setCurrentTeamName(driverTeam.team.name);
|
|
} else {
|
|
setCurrentTeamId(null);
|
|
setCurrentTeamName(null);
|
|
}
|
|
};
|
|
void load();
|
|
}, [teamId, currentDriverId]);
|
|
|
|
const handleJoin = async () => {
|
|
setLoading(true);
|
|
try {
|
|
if (requiresApproval) {
|
|
const membershipRepo = getTeamMembershipRepository();
|
|
const existing = await membershipRepo.getMembership(teamId, currentDriverId);
|
|
if (existing) {
|
|
throw new Error('Already a member or have a pending request');
|
|
}
|
|
|
|
await membershipRepo.saveJoinRequest({
|
|
id: `team-request-${Date.now()}`,
|
|
teamId,
|
|
driverId: currentDriverId,
|
|
requestedAt: new Date(),
|
|
});
|
|
alert('Join request sent! Wait for team approval.');
|
|
} else {
|
|
const useCase = getJoinTeamUseCase();
|
|
await useCase.execute({ teamId, driverId: currentDriverId });
|
|
alert('Successfully joined team!');
|
|
}
|
|
onUpdate?.();
|
|
} catch (error) {
|
|
alert(error instanceof Error ? error.message : 'Failed to join team');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleLeave = async () => {
|
|
if (!confirm('Are you sure you want to leave this team?')) {
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
const useCase = getLeaveTeamUseCase();
|
|
await useCase.execute({ teamId, driverId: currentDriverId });
|
|
alert('Successfully left team');
|
|
onUpdate?.();
|
|
} catch (error) {
|
|
alert(error instanceof Error ? error.message : 'Failed to leave team');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
// Already a member
|
|
if (membership && membership.status === 'active') {
|
|
if (membership.role === 'owner') {
|
|
return (
|
|
<Button variant="secondary" disabled>
|
|
Team Owner
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
variant="danger"
|
|
onClick={handleLeave}
|
|
disabled={loading}
|
|
>
|
|
{loading ? 'Leaving...' : 'Leave Team'}
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
// Already on another team
|
|
if (currentTeamId && currentTeamId !== teamId) {
|
|
return (
|
|
<Button variant="secondary" disabled>
|
|
Already on {currentTeamName}
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
// Can join
|
|
return (
|
|
<Button
|
|
variant="primary"
|
|
onClick={handleJoin}
|
|
disabled={loading}
|
|
>
|
|
{loading
|
|
? 'Processing...'
|
|
: requiresApproval
|
|
? 'Request to Join'
|
|
: 'Join Team'}
|
|
</Button>
|
|
);
|
|
} |