205 lines
6.2 KiB
TypeScript
205 lines
6.2 KiB
TypeScript
'use client';
|
|
|
|
import { JoinRequestItem } from '@/components/leagues/JoinRequestItem';
|
|
import { JoinRequestList } from '@/components/leagues/JoinRequestList';
|
|
import { EmptyState } from '@/ui/EmptyState';
|
|
import { LoadingWrapper } from '@/ui/LoadingWrapper';
|
|
import { useApproveJoinRequest } from "@/hooks/team/useApproveJoinRequest";
|
|
import { useRejectJoinRequest } from "@/hooks/team/useRejectJoinRequest";
|
|
import { useTeamJoinRequests } from "@/hooks/team/useTeamJoinRequests";
|
|
import { useUpdateTeam } from "@/hooks/team/useUpdateTeam";
|
|
import type { TeamJoinRequestViewModel } from '@/lib/view-models/TeamJoinRequestViewModel';
|
|
import { Button } from '@/ui/Button';
|
|
import { Panel } from '@/ui/Panel';
|
|
import { DangerZone } from '@/ui/DangerZone';
|
|
import { Input } from '@/ui/Input';
|
|
import { Text } from '@/ui/Text';
|
|
import { TextArea } from '@/ui/TextArea';
|
|
import { SectionHeader } from '@/ui/SectionHeader';
|
|
import { Box } from '@/ui/Box';
|
|
import { Group } from '@/ui/Group';
|
|
import { Stack } from '@/ui/Stack';
|
|
import React, { useState } from 'react';
|
|
|
|
interface TeamAdminProps {
|
|
team: {
|
|
id: string;
|
|
name: string;
|
|
tag: string;
|
|
description?: string;
|
|
ownerId: string;
|
|
};
|
|
onUpdate: () => void;
|
|
}
|
|
|
|
export function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
|
const [editMode, setEditMode] = useState(false);
|
|
const [editedTeam, setEditedTeam] = useState({
|
|
name: team.name,
|
|
tag: team.tag,
|
|
description: team.description || '',
|
|
});
|
|
|
|
// Use hooks for data fetching
|
|
const { data: joinRequests = [], isLoading: loading } = useTeamJoinRequests(
|
|
team.id,
|
|
team.ownerId,
|
|
true
|
|
);
|
|
|
|
// Use hooks for mutations
|
|
const updateTeamMutation = useUpdateTeam({
|
|
onSuccess: () => {
|
|
setEditMode(false);
|
|
onUpdate();
|
|
},
|
|
onError: (error) => {
|
|
alert(error instanceof Error ? error.message : 'Failed to update team');
|
|
},
|
|
});
|
|
|
|
const approveJoinRequestMutation = useApproveJoinRequest({
|
|
onSuccess: () => {
|
|
onUpdate();
|
|
},
|
|
onError: (error) => {
|
|
alert(error instanceof Error ? error.message : 'Failed to approve request');
|
|
},
|
|
});
|
|
|
|
const rejectJoinRequestMutation = useRejectJoinRequest({
|
|
onSuccess: () => {
|
|
onUpdate();
|
|
},
|
|
onError: (error) => {
|
|
alert(error instanceof Error ? error.message : 'Failed to reject request');
|
|
},
|
|
});
|
|
|
|
const handleApprove = () => {
|
|
approveJoinRequestMutation.mutate();
|
|
};
|
|
|
|
const handleReject = () => {
|
|
rejectJoinRequestMutation.mutate();
|
|
};
|
|
|
|
const handleSaveChanges = () => {
|
|
updateTeamMutation.mutate({
|
|
teamId: team.id,
|
|
input: {
|
|
name: editedTeam.name,
|
|
tag: editedTeam.tag,
|
|
description: editedTeam.description,
|
|
},
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Stack gap={6}>
|
|
<Panel
|
|
title="Team Settings"
|
|
actions={!editMode && (
|
|
<Button variant="secondary" size="sm" onClick={() => setEditMode(true)}>
|
|
Edit Details
|
|
</Button>
|
|
)}
|
|
>
|
|
{editMode ? (
|
|
<Stack gap={4}>
|
|
<Input
|
|
label="Team Name"
|
|
value={editedTeam.name}
|
|
onChange={(e) => setEditedTeam({ ...editedTeam, name: e.target.value })}
|
|
/>
|
|
|
|
<Input
|
|
label="Team Tag"
|
|
value={editedTeam.tag}
|
|
onChange={(e) => setEditedTeam({ ...editedTeam, tag: e.target.value })}
|
|
maxLength={4}
|
|
hint="Max 4 characters"
|
|
/>
|
|
|
|
<TextArea
|
|
label="Description"
|
|
rows={4}
|
|
value={editedTeam.description}
|
|
onChange={(e) => setEditedTeam({ ...editedTeam, description: e.target.value })}
|
|
/>
|
|
|
|
<Group gap={2}>
|
|
<Button variant="primary" onClick={handleSaveChanges} disabled={updateTeamMutation.isPending}>
|
|
{updateTeamMutation.isPending ? 'Saving...' : 'Save Changes'}
|
|
</Button>
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() => {
|
|
setEditMode(false);
|
|
setEditedTeam({
|
|
name: team.name,
|
|
tag: team.tag,
|
|
description: team.description || '',
|
|
});
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
</Group>
|
|
</Stack>
|
|
) : (
|
|
<Stack gap={4}>
|
|
<Stack gap={1}>
|
|
<Text size="sm" variant="low" block>Team Name</Text>
|
|
<Text variant="high" weight="medium" block>{team.name}</Text>
|
|
</Stack>
|
|
<Stack gap={1}>
|
|
<Text size="sm" variant="low" block>Team Tag</Text>
|
|
<Text variant="high" weight="medium" block>{team.tag}</Text>
|
|
</Stack>
|
|
<Stack gap={1}>
|
|
<Text size="sm" variant="low" block>Description</Text>
|
|
<Text variant="high" block>{team.description}</Text>
|
|
</Stack>
|
|
</Stack>
|
|
)}
|
|
</Panel>
|
|
|
|
<Panel title="Join Requests">
|
|
{loading ? (
|
|
<LoadingWrapper variant="spinner" message="Loading requests..." />
|
|
) : joinRequests.length > 0 ? (
|
|
<JoinRequestList>
|
|
{joinRequests.map((request: TeamJoinRequestViewModel) => (
|
|
<JoinRequestItem
|
|
key={request.requestId}
|
|
driverId={request.driverId}
|
|
requestedAt={request.requestedAt}
|
|
onApprove={() => handleApprove()}
|
|
onReject={() => handleReject()}
|
|
isApproving={approveJoinRequestMutation.isPending}
|
|
isRejecting={rejectJoinRequestMutation.isPending}
|
|
/>
|
|
))}
|
|
</JoinRequestList>
|
|
) : (
|
|
<EmptyState
|
|
title="No pending join requests"
|
|
description="When drivers request to join your team, they will appear here."
|
|
variant="minimal"
|
|
/>
|
|
)}
|
|
</Panel>
|
|
|
|
<DangerZone
|
|
title="Disband Team"
|
|
description="Permanently delete this team. This action cannot be undone."
|
|
>
|
|
<Button variant="danger" disabled>
|
|
Disband Team (Coming Soon)
|
|
</Button>
|
|
</DangerZone>
|
|
</Stack>
|
|
);
|
|
}
|