feat(257,253): revert status, assign-to-me, map pin, activate client
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { RefreshCw, Ticket, Plus, Send, RotateCcw, User } from "lucide-react";
|
||||
import { RefreshCw, Ticket, Plus, Send, RotateCcw, User, MapPin, Zap } from "lucide-react";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/Card";
|
||||
import { Table, TableHead, TableBody, TableRow, Th, Td, EmptyState } from "@/components/ui/Table";
|
||||
@@ -120,6 +120,14 @@ export default function TicketsPage() {
|
||||
onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to create ticket"),
|
||||
});
|
||||
|
||||
const activateClient = useMutation({
|
||||
mutationFn: async (clientId: string) => {
|
||||
await api.patch(`/api/v1/clients/${clientId}`, { isActive: true });
|
||||
},
|
||||
onSuccess: () => { toast.success("Client activated! 🎉"); refetch(); refetchDetail(); },
|
||||
onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to activate client"),
|
||||
});
|
||||
|
||||
const revertStatus = useMutation({
|
||||
mutationFn: async ({ id, status }: { id: string; status: string }) => {
|
||||
await api.patch(`/api/v1/tickets/${id}`, { status });
|
||||
@@ -226,6 +234,21 @@ export default function TicketsPage() {
|
||||
<div><span className="text-gray-500">Status</span><p><Badge variant={statusVariant[detail.status] ?? "muted"}>{detail.status}</Badge></p></div>
|
||||
<div className="col-span-2"><span className="text-gray-500">Created</span><p>{formatDate(detail.createdAt)}</p></div>
|
||||
{detail.description && <div className="col-span-2"><span className="text-gray-500">Description</span><p className="mt-1 text-gray-800 whitespace-pre-wrap">{detail.description}</p></div>}
|
||||
{/* Installation: show Google Maps link using client address */}
|
||||
{detail.type === "INSTALLATION" && detail.client && (
|
||||
<div className="col-span-2">
|
||||
<span className="text-gray-500">Map</span>
|
||||
<p className="mt-0.5">
|
||||
<a
|
||||
href={`https://www.google.com/maps/search/${encodeURIComponent([(ticketDetail as any)?.client?.address, detail.client.firstName + " " + detail.client.lastName].filter(Boolean).join(", "))}`}
|
||||
target="_blank" rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-blue-600 hover:underline text-sm"
|
||||
>
|
||||
<MapPin size={13} /> View on Google Maps
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Status actions */}
|
||||
@@ -240,6 +263,13 @@ export default function TicketsPage() {
|
||||
<RotateCcw size={13} className="mr-1" /> Revert to {prevStatus[detail.status].replace("_", " ")}
|
||||
</Button>
|
||||
)}
|
||||
{/* Installation ticket RESOLVED → show Activate Client button */}
|
||||
{detail.type === "INSTALLATION" && detail.status === "RESOLVED" && detail.clientId && (
|
||||
<Button size="sm" variant="outline" onClick={() => activateClient.mutate(detail.clientId!)} isLoading={activateClient.isPending}
|
||||
className="text-green-700 border-green-300 hover:bg-green-50">
|
||||
<Zap size={13} className="mr-1" /> Activate Client
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Comments */}
|
||||
|
||||
Reference in New Issue
Block a user