di usage in website
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import Button from '@/components/ui/Button';
|
||||
import Input from '@/components/ui/Input';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { useCreateTeam } from '@/hooks/team';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
|
||||
@@ -14,14 +14,13 @@ interface CreateTeamFormProps {
|
||||
|
||||
export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormProps) {
|
||||
const router = useRouter();
|
||||
const { teamService } = useServices();
|
||||
const createTeamMutation = useCreateTeam();
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
tag: '',
|
||||
description: '',
|
||||
});
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
|
||||
const validateForm = () => {
|
||||
@@ -56,26 +55,26 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
|
||||
try {
|
||||
const result = await teamService.createTeam({
|
||||
createTeamMutation.mutate(
|
||||
{
|
||||
name: formData.name,
|
||||
tag: formData.tag.toUpperCase(),
|
||||
description: formData.description,
|
||||
});
|
||||
|
||||
const teamId = result.id;
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess(teamId);
|
||||
} else {
|
||||
router.push(`/teams/${teamId}`);
|
||||
},
|
||||
{
|
||||
onSuccess: (result) => {
|
||||
const teamId = result.id;
|
||||
if (onSuccess) {
|
||||
onSuccess(teamId);
|
||||
} else {
|
||||
router.push(`/teams/${teamId}`);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
alert(error instanceof Error ? error.message : 'Failed to create team');
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
alert(error instanceof Error ? error.message : 'Failed to create team');
|
||||
setSubmitting(false);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -89,7 +88,7 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
placeholder="Enter team name..."
|
||||
disabled={submitting}
|
||||
disabled={createTeamMutation.isPending}
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="text-danger-red text-xs mt-1">{errors.name}</p>
|
||||
@@ -106,7 +105,7 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
onChange={(e) => setFormData({ ...formData, tag: e.target.value.toUpperCase() })}
|
||||
placeholder="e.g., APEX"
|
||||
maxLength={4}
|
||||
disabled={submitting}
|
||||
disabled={createTeamMutation.isPending}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">Max 4 characters</p>
|
||||
{errors.tag && (
|
||||
@@ -124,7 +123,7 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
value={formData.description}
|
||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||
placeholder="Describe your team's goals and racing style..."
|
||||
disabled={submitting}
|
||||
disabled={createTeamMutation.isPending}
|
||||
/>
|
||||
{errors.description && (
|
||||
<p className="text-danger-red text-xs mt-1">{errors.description}</p>
|
||||
@@ -150,17 +149,17 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
disabled={submitting}
|
||||
disabled={createTeamMutation.isPending}
|
||||
className="flex-1"
|
||||
>
|
||||
{submitting ? 'Creating Team...' : 'Create Team'}
|
||||
{createTeamMutation.isPending ? 'Creating Team...' : 'Create Team'}
|
||||
</Button>
|
||||
{onCancel && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={onCancel}
|
||||
disabled={submitting}
|
||||
disabled={createTeamMutation.isPending}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
@@ -168,4 +167,4 @@ export default function CreateTeamForm({ onCancel, onSuccess }: CreateTeamFormPr
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,8 @@
|
||||
|
||||
import Button from '@/components/ui/Button';
|
||||
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
|
||||
type TeamMembershipStatus = 'active' | 'pending' | 'inactive';
|
||||
|
||||
interface TeamMembership {
|
||||
teamId: string;
|
||||
driverId: string;
|
||||
role: 'owner' | 'manager' | 'driver';
|
||||
status: TeamMembershipStatus;
|
||||
joinedAt: Date | string;
|
||||
}
|
||||
import { useTeamMembership, useJoinTeam, useLeaveTeam } from '@/hooks/team';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface JoinTeamButtonProps {
|
||||
teamId: string;
|
||||
@@ -26,76 +16,63 @@ export default function JoinTeamButton({
|
||||
requiresApproval = false,
|
||||
onUpdate,
|
||||
}: JoinTeamButtonProps) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const currentDriverId = useEffectiveDriverId();
|
||||
const [membership, setMembership] = useState<TeamMembership | null>(null);
|
||||
const { teamService, teamJoinService } = useServices();
|
||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
try {
|
||||
const m = await teamService.getMembership(teamId, currentDriverId);
|
||||
setMembership(m as TeamMembership | null);
|
||||
} catch (error) {
|
||||
console.error('Failed to load membership:', error);
|
||||
}
|
||||
};
|
||||
void load();
|
||||
}, [teamId, currentDriverId, teamService]);
|
||||
// Use hooks for data fetching
|
||||
const { data: membership, isLoading: loadingMembership } = useTeamMembership(teamId, currentDriverId || '');
|
||||
|
||||
const handleJoin = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
if (requiresApproval) {
|
||||
const existing = await teamService.getMembership(teamId, currentDriverId);
|
||||
if (existing) {
|
||||
throw new Error('Already a member or have a pending request');
|
||||
}
|
||||
|
||||
// Note: Team join request functionality would need to be added to teamService
|
||||
// For now, we'll use a placeholder
|
||||
console.log('Saving join request:', {
|
||||
id: `team-request-${Date.now()}`,
|
||||
teamId,
|
||||
driverId: currentDriverId,
|
||||
requestedAt: new Date(),
|
||||
});
|
||||
alert('Join request sent! Wait for team approval.');
|
||||
} else {
|
||||
// Note: Team join functionality would need to be added to teamService
|
||||
// For now, we'll use a placeholder
|
||||
console.log('Joining team:', { teamId, driverId: currentDriverId });
|
||||
alert('Successfully joined team!');
|
||||
}
|
||||
// Use hooks for mutations
|
||||
const joinTeamMutation = useJoinTeam({
|
||||
onSuccess: () => {
|
||||
onUpdate?.();
|
||||
} catch (error) {
|
||||
alert(error instanceof Error ? error.message : 'Failed to join team');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
const leaveTeamMutation = useLeaveTeam({
|
||||
onSuccess: () => {
|
||||
onUpdate?.();
|
||||
setShowConfirmation(false);
|
||||
},
|
||||
});
|
||||
|
||||
const handleJoin = () => {
|
||||
if (!currentDriverId) {
|
||||
alert('Please log in to join a team');
|
||||
return;
|
||||
}
|
||||
joinTeamMutation.mutate({
|
||||
teamId,
|
||||
driverId: currentDriverId,
|
||||
requiresApproval,
|
||||
});
|
||||
};
|
||||
|
||||
const handleLeave = async () => {
|
||||
const handleLeave = () => {
|
||||
if (!currentDriverId) {
|
||||
alert('Please log in to leave a team');
|
||||
return;
|
||||
}
|
||||
if (!confirm('Are you sure you want to leave this team?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// Note: Leave team functionality would need to be added to teamService
|
||||
// For now, we'll use a placeholder
|
||||
console.log('Leaving team:', { teamId, driverId: currentDriverId });
|
||||
alert('Successfully left team');
|
||||
onUpdate?.();
|
||||
} catch (error) {
|
||||
alert(error instanceof Error ? error.message : 'Failed to leave team');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
leaveTeamMutation.mutate({
|
||||
teamId,
|
||||
driverId: currentDriverId,
|
||||
});
|
||||
};
|
||||
|
||||
// Loading state
|
||||
if (loadingMembership) {
|
||||
return (
|
||||
<Button variant="primary" disabled>
|
||||
Loading...
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
// Already a member
|
||||
if (membership && membership.status === 'active') {
|
||||
if (membership && membership.isActive) {
|
||||
if (membership.role === 'owner') {
|
||||
return (
|
||||
<Button variant="secondary" disabled>
|
||||
@@ -108,9 +85,9 @@ export default function JoinTeamButton({
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={handleLeave}
|
||||
disabled={loading}
|
||||
disabled={leaveTeamMutation.isPending}
|
||||
>
|
||||
{loading ? 'Leaving...' : 'Leave Team'}
|
||||
{leaveTeamMutation.isPending ? 'Leaving...' : 'Leave Team'}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -120,9 +97,9 @@ export default function JoinTeamButton({
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleJoin}
|
||||
disabled={loading}
|
||||
disabled={joinTeamMutation.isPending || !currentDriverId}
|
||||
>
|
||||
{loading
|
||||
{joinTeamMutation.isPending
|
||||
? 'Processing...'
|
||||
: requiresApproval
|
||||
? 'Request to Join'
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState } from 'react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Input from '@/components/ui/Input';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
|
||||
import { useTeamJoinRequests, useUpdateTeam, useApproveJoinRequest, useRejectJoinRequest } from '@/hooks/team';
|
||||
import type { TeamJoinRequestViewModel } from '@/lib/view-models/TeamJoinRequestViewModel';
|
||||
import type { TeamDetailsViewModel } from '@/lib/view-models/TeamDetailsViewModel';
|
||||
import type { UpdateTeamViewModel } from '@/lib/view-models/UpdateTeamViewModel';
|
||||
|
||||
interface TeamAdminProps {
|
||||
team: Pick<TeamDetailsViewModel, 'id' | 'name' | 'tag' | 'description' | 'ownerId'>;
|
||||
@@ -16,10 +14,6 @@ interface TeamAdminProps {
|
||||
}
|
||||
|
||||
export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
const { teamJoinService, teamService } = useServices();
|
||||
const [joinRequests, setJoinRequests] = useState<TeamJoinRequestViewModel[]>([]);
|
||||
const [requestDrivers, setRequestDrivers] = useState<Record<string, DriverViewModel>>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [editedTeam, setEditedTeam] = useState({
|
||||
name: team.name,
|
||||
@@ -27,60 +21,63 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
description: team.description,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// Current build only supports read-only join requests. Driver hydration is
|
||||
// not provided by the API response, so we only display driverId.
|
||||
const currentUserId = team.ownerId;
|
||||
const isOwner = true;
|
||||
const requests = await teamJoinService.getJoinRequests(team.id, currentUserId, isOwner);
|
||||
setJoinRequests(requests);
|
||||
setRequestDrivers({});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
// Use hooks for data fetching
|
||||
const { data: joinRequests = [], isLoading: loading } = useTeamJoinRequests(
|
||||
team.id,
|
||||
team.ownerId,
|
||||
true
|
||||
);
|
||||
|
||||
void load();
|
||||
}, [team.id, team.name, team.tag, team.description, team.ownerId]);
|
||||
// Use hooks for mutations
|
||||
const updateTeamMutation = useUpdateTeam({
|
||||
onSuccess: () => {
|
||||
setEditMode(false);
|
||||
onUpdate();
|
||||
},
|
||||
onError: (error) => {
|
||||
alert(error instanceof Error ? error.message : 'Failed to update team');
|
||||
},
|
||||
});
|
||||
|
||||
const handleApprove = async (requestId: string) => {
|
||||
try {
|
||||
void requestId;
|
||||
await teamJoinService.approveJoinRequest();
|
||||
} catch (error) {
|
||||
const approveJoinRequestMutation = useApproveJoinRequest({
|
||||
onSuccess: () => {
|
||||
onUpdate();
|
||||
},
|
||||
onError: (error) => {
|
||||
alert(error instanceof Error ? error.message : 'Failed to approve request');
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const handleReject = async (requestId: string) => {
|
||||
try {
|
||||
void requestId;
|
||||
await teamJoinService.rejectJoinRequest();
|
||||
} catch (error) {
|
||||
const rejectJoinRequestMutation = useRejectJoinRequest({
|
||||
onSuccess: () => {
|
||||
onUpdate();
|
||||
},
|
||||
onError: (error) => {
|
||||
alert(error instanceof Error ? error.message : 'Failed to reject request');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleApprove = (requestId: string) => {
|
||||
// Note: The current API doesn't support approving specific requests
|
||||
// This would need the requestId to be passed to the service
|
||||
approveJoinRequestMutation.mutate();
|
||||
};
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
try {
|
||||
const result: UpdateTeamViewModel = await teamService.updateTeam(team.id, {
|
||||
const handleReject = (requestId: string) => {
|
||||
// Note: The current API doesn't support rejecting specific requests
|
||||
// This would need the requestId to be passed to the service
|
||||
rejectJoinRequestMutation.mutate();
|
||||
};
|
||||
|
||||
const handleSaveChanges = () => {
|
||||
updateTeamMutation.mutate({
|
||||
teamId: team.id,
|
||||
input: {
|
||||
name: editedTeam.name,
|
||||
tag: editedTeam.tag,
|
||||
description: editedTeam.description,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.successMessage);
|
||||
}
|
||||
|
||||
setEditMode(false);
|
||||
onUpdate();
|
||||
} catch (error) {
|
||||
alert(error instanceof Error ? error.message : 'Failed to update team');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -134,8 +131,8 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button variant="primary" onClick={handleSaveChanges}>
|
||||
Save Changes
|
||||
<Button variant="primary" onClick={handleSaveChanges} disabled={updateTeamMutation.isPending}>
|
||||
{updateTeamMutation.isPending ? 'Saving...' : 'Save Changes'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
@@ -177,9 +174,9 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
<div className="text-center py-8 text-gray-400">Loading requests...</div>
|
||||
) : joinRequests.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{joinRequests.map((request) => {
|
||||
const driver = requestDrivers[request.driverId] ?? null;
|
||||
|
||||
{joinRequests.map((request: TeamJoinRequestViewModel) => {
|
||||
// Note: Driver hydration is not provided by the API response
|
||||
// so we only display driverId
|
||||
return (
|
||||
<div
|
||||
key={request.requestId}
|
||||
@@ -187,30 +184,29 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
>
|
||||
<div className="flex items-center gap-4 flex-1">
|
||||
<div className="w-12 h-12 rounded-full bg-primary-blue/20 flex items-center justify-center text-lg font-bold text-white">
|
||||
{(driver?.name ?? request.driverId).charAt(0)}
|
||||
{request.driverId.charAt(0)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h4 className="text-white font-medium">{driver?.name ?? request.driverId}</h4>
|
||||
<h4 className="text-white font-medium">{request.driverId}</h4>
|
||||
<p className="text-sm text-gray-400">
|
||||
{driver?.country ?? 'Unknown'} • Requested {new Date(request.requestedAt).toLocaleDateString()}
|
||||
Requested {new Date(request.requestedAt).toLocaleDateString()}
|
||||
</p>
|
||||
{/* Request message is not part of current API contract */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => handleApprove(request.requestId)}
|
||||
disabled
|
||||
disabled={approveJoinRequestMutation.isPending}
|
||||
>
|
||||
Approve
|
||||
{approveJoinRequestMutation.isPending ? 'Approving...' : 'Approve'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={() => handleReject(request.requestId)}
|
||||
disabled
|
||||
disabled={rejectJoinRequestMutation.isPending}
|
||||
>
|
||||
Reject
|
||||
{rejectJoinRequestMutation.isPending ? 'Rejecting...' : 'Reject'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -240,4 +236,4 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import DriverIdentity from '@/components/drivers/DriverIdentity';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import type { TeamMemberViewModel } from '@/lib/view-models/TeamMemberViewModel';
|
||||
import { useTeamRoster } from '@/hooks/team';
|
||||
import { useState } from 'react';
|
||||
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
|
||||
|
||||
type TeamRole = 'owner' | 'admin' | 'member';
|
||||
|
||||
type TeamMembershipSummary = Pick<TeamMemberViewModel, 'driverId' | 'role' | 'joinedAt'>;
|
||||
type TeamMemberRole = 'owner' | 'manager' | 'member';
|
||||
|
||||
interface TeamRosterProps {
|
||||
teamId: string;
|
||||
memberships: TeamMembershipSummary[];
|
||||
memberships: any[];
|
||||
isAdmin: boolean;
|
||||
onRemoveMember?: (driverId: string) => void;
|
||||
onChangeRole?: (driverId: string, newRole: TeamRole) => void;
|
||||
@@ -25,38 +24,10 @@ export default function TeamRoster({
|
||||
onRemoveMember,
|
||||
onChangeRole,
|
||||
}: TeamRosterProps) {
|
||||
const { teamService, driverService } = useServices();
|
||||
const [teamMembers, setTeamMembers] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [sortBy, setSortBy] = useState<'role' | 'rating' | 'name'>('rating');
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// Get driver details for each membership
|
||||
const membersWithDetails = await Promise.all(
|
||||
memberships.map(async (m) => {
|
||||
const driver = await driverService.findById(m.driverId);
|
||||
return {
|
||||
driver: driver || { id: m.driverId, name: 'Unknown Driver', country: 'Unknown', position: 'N/A', races: '0', impressions: '0', team: 'None' },
|
||||
role: m.role,
|
||||
joinedAt: m.joinedAt,
|
||||
rating: null, // DriverDTO doesn't include rating
|
||||
overallRank: null, // DriverDTO doesn't include overallRank
|
||||
};
|
||||
})
|
||||
);
|
||||
setTeamMembers(membersWithDetails);
|
||||
} catch (error) {
|
||||
console.error('Failed to load team roster:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
void load();
|
||||
}, [memberships, teamService, driverService]);
|
||||
// Use hook for data fetching
|
||||
const { data: teamMembers = [], isLoading: loading } = useTeamRoster(memberships);
|
||||
|
||||
const getRoleBadgeColor = (role: TeamRole) => {
|
||||
switch (role) {
|
||||
@@ -69,15 +40,17 @@ export default function TeamRoster({
|
||||
}
|
||||
};
|
||||
|
||||
const getRoleLabel = (role: TeamRole) => {
|
||||
return role.charAt(0).toUpperCase() + role.slice(1);
|
||||
const getRoleLabel = (role: TeamRole | TeamMemberRole) => {
|
||||
// Convert manager to admin for display
|
||||
const displayRole = role === 'manager' ? 'admin' : role;
|
||||
return displayRole.charAt(0).toUpperCase() + displayRole.slice(1);
|
||||
};
|
||||
|
||||
function getRoleOrder(role: TeamRole): number {
|
||||
function getRoleOrder(role: TeamMemberRole): number {
|
||||
switch (role) {
|
||||
case 'owner':
|
||||
return 0;
|
||||
case 'admin':
|
||||
case 'manager':
|
||||
return 1;
|
||||
case 'member':
|
||||
return 2;
|
||||
@@ -145,6 +118,8 @@ export default function TeamRoster({
|
||||
{sortedMembers.map((member) => {
|
||||
const { driver, role, joinedAt, rating, overallRank } = member;
|
||||
|
||||
// Convert manager to admin for display purposes
|
||||
const displayRole: TeamRole = role === 'manager' ? 'admin' : (role as TeamRole);
|
||||
const canManageMembership = isAdmin && role !== 'owner';
|
||||
|
||||
return (
|
||||
@@ -153,7 +128,7 @@ export default function TeamRoster({
|
||||
className="flex items-center justify-between p-4 rounded-lg bg-deep-graphite border border-charcoal-outline hover:border-charcoal-outline/60 transition-colors"
|
||||
>
|
||||
<DriverIdentity
|
||||
driver={driver}
|
||||
driver={driver as DriverViewModel}
|
||||
href={`/drivers/${driver.id}?from=team&teamId=${teamId}`}
|
||||
contextLabel={getRoleLabel(role)}
|
||||
meta={
|
||||
@@ -185,7 +160,7 @@ export default function TeamRoster({
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
className="px-3 py-2 bg-iron-gray border-0 rounded text-white ring-1 ring-inset ring-charcoal-outline focus:ring-2 focus:ring-primary-blue transition-all duration-150 text-sm"
|
||||
value={role}
|
||||
value={displayRole}
|
||||
onChange={(e) =>
|
||||
onChangeRole?.(driver.id, e.target.value as TeamRole)
|
||||
}
|
||||
@@ -212,4 +187,4 @@ export default function TeamRoster({
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import { useServices } from '@/lib/services/ServiceProvider';
|
||||
import { useTeamStandings } from '@/hooks/team';
|
||||
|
||||
interface TeamStandingsProps {
|
||||
teamId: string;
|
||||
@@ -10,32 +9,7 @@ interface TeamStandingsProps {
|
||||
}
|
||||
|
||||
export default function TeamStandings({ teamId, leagues }: TeamStandingsProps) {
|
||||
const { leagueService } = useServices();
|
||||
const [standings, setStandings] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
try {
|
||||
// For demo purposes, create mock standings
|
||||
const mockStandings = leagues.map(leagueId => ({
|
||||
leagueId,
|
||||
leagueName: `League ${leagueId}`,
|
||||
position: Math.floor(Math.random() * 10) + 1,
|
||||
points: Math.floor(Math.random() * 100),
|
||||
wins: Math.floor(Math.random() * 5),
|
||||
racesCompleted: Math.floor(Math.random() * 10),
|
||||
}));
|
||||
setStandings(mockStandings);
|
||||
} catch (error) {
|
||||
console.error('Failed to load standings:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
void load();
|
||||
}, [teamId, leagues]);
|
||||
const { data: standings = [], isLoading: loading } = useTeamStandings(teamId, leagues);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -50,7 +24,7 @@ export default function TeamStandings({ teamId, leagues }: TeamStandingsProps) {
|
||||
<h3 className="text-xl font-semibold text-white mb-6">League Standings</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
{standings.map((standing) => (
|
||||
{standings.map((standing: any) => (
|
||||
<div
|
||||
key={standing.leagueId}
|
||||
className="p-4 rounded-lg bg-deep-graphite border border-charcoal-outline"
|
||||
|
||||
Reference in New Issue
Block a user