wip
This commit is contained in:
@@ -5,11 +5,19 @@ import Button from '@/components/ui/Button';
|
||||
import {
|
||||
getJoinTeamUseCase,
|
||||
getLeaveTeamUseCase,
|
||||
getGetDriverTeamUseCase,
|
||||
getTeamMembershipRepository,
|
||||
} from '@/lib/di-container';
|
||||
import { useEffectiveDriverId } from '@/lib/currentDriver';
|
||||
import type { TeamMembership } from '@gridpilot/racing';
|
||||
|
||||
type TeamMembershipStatus = 'active' | 'pending' | 'inactive';
|
||||
|
||||
interface TeamMembership {
|
||||
teamId: string;
|
||||
driverId: string;
|
||||
role: 'owner' | 'manager' | 'driver';
|
||||
status: TeamMembershipStatus;
|
||||
joinedAt: Date | string;
|
||||
}
|
||||
|
||||
interface JoinTeamButtonProps {
|
||||
teamId: string;
|
||||
@@ -25,25 +33,12 @@ export default function JoinTeamButton({
|
||||
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 driverTeamUseCase = getGetDriverTeamUseCase();
|
||||
await driverTeamUseCase.execute({ driverId: currentDriverId });
|
||||
const viewModel = driverTeamUseCase.presenter.getViewModel();
|
||||
if (viewModel.result) {
|
||||
setCurrentTeamId(viewModel.result.team.id);
|
||||
setCurrentTeamName(viewModel.result.team.name);
|
||||
} else {
|
||||
setCurrentTeamId(null);
|
||||
setCurrentTeamName(null);
|
||||
}
|
||||
setMembership(m as TeamMembership | null);
|
||||
};
|
||||
void load();
|
||||
}, [teamId, currentDriverId]);
|
||||
@@ -117,15 +112,6 @@ export default function JoinTeamButton({
|
||||
);
|
||||
}
|
||||
|
||||
// Already on another team
|
||||
if (currentTeamId && currentTeamId !== teamId) {
|
||||
return (
|
||||
<Button variant="secondary" disabled>
|
||||
Already on {currentTeamName}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
// Can join
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -39,7 +39,13 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const viewModel = await loadTeamAdminViewModel(team as any);
|
||||
const viewModel = await loadTeamAdminViewModel({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
tag: team.tag,
|
||||
description: team.description,
|
||||
ownerId: team.ownerId,
|
||||
});
|
||||
setJoinRequests(viewModel.requests);
|
||||
|
||||
const driversById: Record<string, DriverDTO> = {};
|
||||
|
||||
@@ -29,9 +29,9 @@ interface TeamCardProps {
|
||||
totalRaces?: number;
|
||||
performanceLevel?: 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
||||
isRecruiting?: boolean;
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed';
|
||||
specialization?: 'endurance' | 'sprint' | 'mixed' | undefined;
|
||||
region?: string;
|
||||
languages?: string[];
|
||||
languages?: string[] | undefined;
|
||||
leagues?: string[];
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
getTeamRosterViewModel,
|
||||
type TeamRosterViewModel,
|
||||
} from '@/lib/presenters/TeamRosterPresenter';
|
||||
|
||||
type TeamRole = 'owner' | 'manager' | 'driver';
|
||||
import type { TeamRole } from '@gridpilot/racing/domain/types/TeamMembership';
|
||||
|
||||
interface TeamMembershipSummary {
|
||||
driverId: string;
|
||||
@@ -39,7 +38,14 @@ export default function TeamRoster({
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const vm = await getTeamRosterViewModel(memberships);
|
||||
const fullMemberships = memberships.map((m) => ({
|
||||
teamId,
|
||||
driverId: m.driverId,
|
||||
role: m.role,
|
||||
joinedAt: m.joinedAt,
|
||||
status: 'active' as const,
|
||||
}));
|
||||
const vm = await getTeamRosterViewModel(fullMemberships);
|
||||
setViewModel(vm);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -64,6 +70,19 @@ export default function TeamRoster({
|
||||
return role.charAt(0).toUpperCase() + role.slice(1);
|
||||
};
|
||||
|
||||
function getRoleOrder(role: TeamRole): number {
|
||||
switch (role) {
|
||||
case 'owner':
|
||||
return 0;
|
||||
case 'manager':
|
||||
return 1;
|
||||
case 'driver':
|
||||
return 2;
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
const sortedMembers = viewModel
|
||||
? [...viewModel.members].sort((a, b) => {
|
||||
switch (sortBy) {
|
||||
@@ -73,8 +92,7 @@ export default function TeamRoster({
|
||||
return ratingB - ratingA;
|
||||
}
|
||||
case 'role': {
|
||||
const roleOrder: Record<TeamRole, number> = { owner: 0, manager: 1, driver: 2 };
|
||||
return roleOrder[a.role] - roleOrder[b.role];
|
||||
return getRoleOrder(a.role) - getRoleOrder(b.role);
|
||||
}
|
||||
case 'name': {
|
||||
return a.driver.name.localeCompare(b.driver.name);
|
||||
@@ -110,7 +128,7 @@ export default function TeamRoster({
|
||||
<label className="text-sm text-gray-400">Sort by:</label>
|
||||
<select
|
||||
value={sortBy}
|
||||
onChange={(e) => setSortBy(e.target.value as any)}
|
||||
onChange={(e) => setSortBy(e.target.value as typeof sortBy)}
|
||||
className="px-3 py-1 bg-deep-graphite border border-charcoal-outline rounded text-white text-sm focus:outline-none focus:ring-2 focus:ring-primary-blue"
|
||||
>
|
||||
<option value="rating">Rating</option>
|
||||
|
||||
Reference in New Issue
Block a user