website refactor
This commit is contained in:
@@ -1,10 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Card from '@/ui/Card';
|
||||
import Button from '@/ui/Button';
|
||||
import Input from '@/ui/Input';
|
||||
import { useTeamJoinRequests, useUpdateTeam, useApproveJoinRequest, useRejectJoinRequest } from "@/lib/hooks/team";
|
||||
import React, { useState } from 'react';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Input } from '@/ui/Input';
|
||||
import { TextArea } from '@/ui/TextArea';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Heading } from '@/ui/Heading';
|
||||
import { JoinRequestList } from '@/ui/JoinRequestList';
|
||||
import { JoinRequestItem } from '@/ui/JoinRequestItem';
|
||||
import { DangerZone } from '@/ui/DangerZone';
|
||||
import { MinimalEmptyState } from '@/ui/EmptyState';
|
||||
import { useTeamJoinRequests, useUpdateTeam, useApproveJoinRequest, useRejectJoinRequest } from "@/hooks/team";
|
||||
import type { TeamJoinRequestViewModel } from '@/lib/view-models/TeamJoinRequestViewModel';
|
||||
|
||||
interface TeamAdminProps {
|
||||
@@ -18,7 +27,7 @@ interface TeamAdminProps {
|
||||
onUpdate: () => void;
|
||||
}
|
||||
|
||||
export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
export function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [editedTeam, setEditedTeam] = useState({
|
||||
name: team.name,
|
||||
@@ -62,13 +71,13 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const handleApprove = (requestId: string) => {
|
||||
const handleApprove = () => {
|
||||
// Note: The current API doesn't support approving specific requests
|
||||
// This would need the requestId to be passed to the service
|
||||
approveJoinRequestMutation.mutate();
|
||||
};
|
||||
|
||||
const handleReject = (requestId: string) => {
|
||||
const handleReject = () => {
|
||||
// Note: The current API doesn't support rejecting specific requests
|
||||
// This would need the requestId to be passed to the service
|
||||
rejectJoinRequestMutation.mutate();
|
||||
@@ -86,56 +95,51 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Stack gap={6}>
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h3 className="text-xl font-semibold text-white">Team Settings</h3>
|
||||
<Box display="flex" alignItems="center" justifyContent="between" mb={6}>
|
||||
<Heading level={3}>Team Settings</Heading>
|
||||
{!editMode && (
|
||||
<Button variant="secondary" onClick={() => setEditMode(true)}>
|
||||
Edit Details
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
{editMode ? (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-400 mb-2">
|
||||
<Stack gap={4}>
|
||||
<Box>
|
||||
<Text as="label" size="sm" weight="medium" color="text-gray-400" block mb={2}>
|
||||
Team Name
|
||||
</label>
|
||||
</Text>
|
||||
<Input
|
||||
type="text"
|
||||
value={editedTeam.name}
|
||||
onChange={(e) => setEditedTeam({ ...editedTeam, name: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-400 mb-2">
|
||||
<Box>
|
||||
<Text as="label" size="sm" weight="medium" color="text-gray-400" block mb={2}>
|
||||
Team Tag
|
||||
</label>
|
||||
</Text>
|
||||
<Input
|
||||
type="text"
|
||||
value={editedTeam.tag}
|
||||
onChange={(e) => setEditedTeam({ ...editedTeam, tag: e.target.value })}
|
||||
maxLength={4}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">Max 4 characters</p>
|
||||
</div>
|
||||
<Text size="xs" color="text-gray-500" block mt={1}>Max 4 characters</Text>
|
||||
</Box>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-400 mb-2">
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
className="w-full px-3 py-3 bg-iron-gray border-0 rounded-md text-white ring-1 ring-inset ring-charcoal-outline focus:ring-2 focus:ring-primary-blue transition-all duration-150 text-sm resize-none"
|
||||
rows={4}
|
||||
value={editedTeam.description}
|
||||
onChange={(e) => setEditedTeam({ ...editedTeam, description: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<TextArea
|
||||
label="Description"
|
||||
rows={4}
|
||||
value={editedTeam.description}
|
||||
onChange={(e) => setEditedTeam({ ...editedTeam, description: e.target.value })}
|
||||
/>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Stack direction="row" gap={2}>
|
||||
<Button variant="primary" onClick={handleSaveChanges} disabled={updateTeamMutation.isPending}>
|
||||
{updateTeamMutation.isPending ? 'Saving...' : 'Save Changes'}
|
||||
</Button>
|
||||
@@ -152,93 +156,63 @@ export default function TeamAdmin({ team, onUpdate }: TeamAdminProps) {
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Stack>
|
||||
</Stack>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="text-sm text-gray-400">Team Name</div>
|
||||
<div className="text-white font-medium">{team.name}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-gray-400">Team Tag</div>
|
||||
<div className="text-white font-medium">{team.tag}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-gray-400">Description</div>
|
||||
<div className="text-white">{team.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Stack gap={4}>
|
||||
<Box>
|
||||
<Text size="sm" color="text-gray-400" block>Team Name</Text>
|
||||
<Text color="text-white" weight="medium" block>{team.name}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="sm" color="text-gray-400" block>Team Tag</Text>
|
||||
<Text color="text-white" weight="medium" block>{team.tag}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="sm" color="text-gray-400" block>Description</Text>
|
||||
<Text color="text-white" block>{team.description}</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<h3 className="text-xl font-semibold text-white mb-6">Join Requests</h3>
|
||||
<Heading level={3} mb={6}>Join Requests</Heading>
|
||||
|
||||
{loading ? (
|
||||
<div className="text-center py-8 text-gray-400">Loading requests...</div>
|
||||
<Box textAlign="center" py={8}>
|
||||
<Text color="text-gray-400">Loading requests...</Text>
|
||||
</Box>
|
||||
) : joinRequests.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{joinRequests.map((request: TeamJoinRequestViewModel) => {
|
||||
// Note: Driver hydration is not provided by the API response
|
||||
// so we only display driverId
|
||||
return (
|
||||
<div
|
||||
key={request.requestId}
|
||||
className="flex items-center justify-between p-4 rounded-lg bg-deep-graphite border border-charcoal-outline"
|
||||
>
|
||||
<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">
|
||||
{request.driverId.charAt(0)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h4 className="text-white font-medium">{request.driverId}</h4>
|
||||
<p className="text-sm text-gray-400">
|
||||
Requested {new Date(request.requestedAt).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => handleApprove(request.requestId)}
|
||||
disabled={approveJoinRequestMutation.isPending}
|
||||
>
|
||||
{approveJoinRequestMutation.isPending ? 'Approving...' : 'Approve'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={() => handleReject(request.requestId)}
|
||||
disabled={rejectJoinRequestMutation.isPending}
|
||||
>
|
||||
{rejectJoinRequestMutation.isPending ? 'Rejecting...' : 'Reject'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<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>
|
||||
) : (
|
||||
<div className="text-center py-8 text-gray-400">
|
||||
No pending join requests
|
||||
</div>
|
||||
<MinimalEmptyState
|
||||
title="No pending join requests"
|
||||
description="When drivers request to join your team, they will appear here."
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<h3 className="text-xl font-semibold text-white mb-4">Danger Zone</h3>
|
||||
<div className="space-y-4">
|
||||
<div className="p-4 rounded-lg bg-danger-red/10 border border-danger-red/30">
|
||||
<h4 className="text-white font-medium mb-2">Disband Team</h4>
|
||||
<p className="text-sm text-gray-400 mb-4">
|
||||
Permanently delete this team. This action cannot be undone.
|
||||
</p>
|
||||
<Button variant="danger" disabled>
|
||||
Disband Team (Coming Soon)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user