|
|
@@ -16,6 +16,13 @@ import {
|
|
|
TableHeader,
|
|
|
TableRow,
|
|
|
} from "@/components/ui/table";
|
|
|
+import {
|
|
|
+ ContextMenu,
|
|
|
+ ContextMenuContent,
|
|
|
+ ContextMenuItem,
|
|
|
+ ContextMenuTrigger,
|
|
|
+} from "@/components/ui/context-menu";
|
|
|
+import { TableCellLink } from "@/components/table-cell-link";
|
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
|
import { Switch } from "@/components/ui/switch";
|
|
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
|
|
@@ -24,10 +31,12 @@ import {
|
|
|
AlertTriangle,
|
|
|
ArrowRight,
|
|
|
Bell,
|
|
|
+ Car,
|
|
|
Check,
|
|
|
ClipboardCheck,
|
|
|
ClipboardList,
|
|
|
Clock,
|
|
|
+ ExternalLink,
|
|
|
Eye,
|
|
|
EyeOff,
|
|
|
FileText,
|
|
|
@@ -283,6 +292,7 @@ export function DashboardClient({
|
|
|
}) {
|
|
|
const formatCurrency = useFormatCurrency();
|
|
|
const t = useTranslations("dashboard");
|
|
|
+ const tcm = useTranslations("common.contextMenu");
|
|
|
const tAudit = useTranslations("audit");
|
|
|
const distUnit = unitSystem === "metric" ? "km" : "mi";
|
|
|
const router = useRouter();
|
|
|
@@ -1266,30 +1276,43 @@ export function DashboardClient({
|
|
|
) : (
|
|
|
stats.recentServices.map((s) => {
|
|
|
const displayTotal = s.totalAmount > 0 ? s.totalAmount : s.cost;
|
|
|
+ const recordHref = s.vehicle ? `/vehicles/${s.vehicle.id}/service/${s.id}` : `/sales/${s.id}`;
|
|
|
+ const rowCustomer = s.customer ?? s.vehicle?.customer;
|
|
|
return (
|
|
|
+ <ContextMenu key={s.id} modal={false}>
|
|
|
+ <ContextMenuTrigger asChild>
|
|
|
<TableRow
|
|
|
- key={s.id}
|
|
|
className={`cursor-pointer transition-opacity ${navigatingId === s.id ? "opacity-50" : ""}`}
|
|
|
onClick={() => {
|
|
|
setNavigatingId(s.id);
|
|
|
- router.push(s.vehicle ? `/vehicles/${s.vehicle.id}/service/${s.id}` : `/sales/${s.id}`);
|
|
|
+ router.push(recordHref);
|
|
|
}}
|
|
|
>
|
|
|
<TableCell className="font-mono text-xs">
|
|
|
{formatDate(new Date(s.startDateTime ?? s.serviceDate))}
|
|
|
</TableCell>
|
|
|
<TableCell>
|
|
|
- <div>
|
|
|
- {s.vehicle?.licensePlate && (
|
|
|
- <span className="font-mono text-sm">{s.vehicle.licensePlate}</span>
|
|
|
- )}
|
|
|
- <p className="text-xs text-muted-foreground">
|
|
|
- {s.vehicle ? `${s.vehicle.year} ${s.vehicle.make} ${s.vehicle.model}` : "-"}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
+ {s.vehicle ? (
|
|
|
+ <TableCellLink href={`/vehicles/${s.vehicle.id}`} block>
|
|
|
+ {s.vehicle.licensePlate && (
|
|
|
+ <span className="font-mono text-sm">{s.vehicle.licensePlate}</span>
|
|
|
+ )}
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ {s.vehicle.year} {s.vehicle.make} {s.vehicle.model}
|
|
|
+ </p>
|
|
|
+ </TableCellLink>
|
|
|
+ ) : (
|
|
|
+ <p className="text-xs text-muted-foreground">-</p>
|
|
|
+ )}
|
|
|
</TableCell>
|
|
|
<TableCell className="hidden sm:table-cell text-muted-foreground">
|
|
|
- {(s.customer ?? s.vehicle?.customer)?.name || "-"}
|
|
|
+ {rowCustomer ? (
|
|
|
+ <TableCellLink href={`/customers/${rowCustomer.id}`}>
|
|
|
+ {rowCustomer.name}
|
|
|
+ </TableCellLink>
|
|
|
+ ) : (
|
|
|
+ "-"
|
|
|
+ )}
|
|
|
</TableCell>
|
|
|
<TableCell className="font-medium">{s.title}</TableCell>
|
|
|
{stats.isAdmin && (
|
|
|
@@ -1303,6 +1326,31 @@ export function DashboardClient({
|
|
|
</TableCell>
|
|
|
)}
|
|
|
</TableRow>
|
|
|
+ </ContextMenuTrigger>
|
|
|
+ <ContextMenuContent className="min-w-52">
|
|
|
+ <ContextMenuItem
|
|
|
+ onClick={() => {
|
|
|
+ setNavigatingId(s.id);
|
|
|
+ router.push(recordHref);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <ExternalLink className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("open")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ {s.vehicle && (
|
|
|
+ <ContextMenuItem onClick={() => router.push(`/vehicles/${s.vehicle?.id}`)}>
|
|
|
+ <Car className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("openVehicle")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ )}
|
|
|
+ {rowCustomer && (
|
|
|
+ <ContextMenuItem onClick={() => router.push(`/customers/${rowCustomer.id}`)}>
|
|
|
+ <Users className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("openCustomer")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ )}
|
|
|
+ </ContextMenuContent>
|
|
|
+ </ContextMenu>
|
|
|
);
|
|
|
})
|
|
|
)}
|
|
|
@@ -1337,27 +1385,41 @@ export function DashboardClient({
|
|
|
</TableCell>
|
|
|
</TableRow>
|
|
|
) : (
|
|
|
- stats.todaysServices.map((s) => (
|
|
|
+ stats.todaysServices.map((s) => {
|
|
|
+ const recordHref = s.vehicle ? `/vehicles/${s.vehicle.id}/service/${s.id}` : `/sales/${s.id}`;
|
|
|
+ const rowCustomer = s.customer ?? s.vehicle?.customer;
|
|
|
+ return (
|
|
|
+ <ContextMenu key={s.id} modal={false}>
|
|
|
+ <ContextMenuTrigger asChild>
|
|
|
<TableRow
|
|
|
- key={s.id}
|
|
|
className={`cursor-pointer transition-opacity ${navigatingId === s.id ? "opacity-50" : ""}`}
|
|
|
onClick={() => {
|
|
|
setNavigatingId(s.id);
|
|
|
- router.push(s.vehicle ? `/vehicles/${s.vehicle.id}/service/${s.id}` : `/sales/${s.id}`);
|
|
|
+ router.push(recordHref);
|
|
|
}}
|
|
|
>
|
|
|
<TableCell>
|
|
|
- <div>
|
|
|
- {s.vehicle?.licensePlate && (
|
|
|
- <span className="font-mono text-sm font-medium">{s.vehicle.licensePlate}</span>
|
|
|
- )}
|
|
|
- <p className="text-xs text-muted-foreground">
|
|
|
- {s.vehicle ? `${s.vehicle.year} ${s.vehicle.make} ${s.vehicle.model}` : "-"}
|
|
|
- </p>
|
|
|
- </div>
|
|
|
+ {s.vehicle ? (
|
|
|
+ <TableCellLink href={`/vehicles/${s.vehicle.id}`} block>
|
|
|
+ {s.vehicle.licensePlate && (
|
|
|
+ <span className="font-mono text-sm font-medium">{s.vehicle.licensePlate}</span>
|
|
|
+ )}
|
|
|
+ <p className="text-xs text-muted-foreground">
|
|
|
+ {s.vehicle.year} {s.vehicle.make} {s.vehicle.model}
|
|
|
+ </p>
|
|
|
+ </TableCellLink>
|
|
|
+ ) : (
|
|
|
+ <p className="text-xs text-muted-foreground">-</p>
|
|
|
+ )}
|
|
|
</TableCell>
|
|
|
<TableCell className="hidden sm:table-cell text-muted-foreground">
|
|
|
- {(s.customer ?? s.vehicle?.customer)?.name || "-"}
|
|
|
+ {rowCustomer ? (
|
|
|
+ <TableCellLink href={`/customers/${rowCustomer.id}`}>
|
|
|
+ {rowCustomer.name}
|
|
|
+ </TableCellLink>
|
|
|
+ ) : (
|
|
|
+ "-"
|
|
|
+ )}
|
|
|
</TableCell>
|
|
|
<TableCell className="font-medium">{s.title}</TableCell>
|
|
|
<TableCell>
|
|
|
@@ -1374,7 +1436,33 @@ export function DashboardClient({
|
|
|
{s.techName || "-"}
|
|
|
</TableCell>
|
|
|
</TableRow>
|
|
|
- ))
|
|
|
+ </ContextMenuTrigger>
|
|
|
+ <ContextMenuContent className="min-w-52">
|
|
|
+ <ContextMenuItem
|
|
|
+ onClick={() => {
|
|
|
+ setNavigatingId(s.id);
|
|
|
+ router.push(recordHref);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <ExternalLink className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("open")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ {s.vehicle && (
|
|
|
+ <ContextMenuItem onClick={() => router.push(`/vehicles/${s.vehicle?.id}`)}>
|
|
|
+ <Car className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("openVehicle")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ )}
|
|
|
+ {rowCustomer && (
|
|
|
+ <ContextMenuItem onClick={() => router.push(`/customers/${rowCustomer.id}`)}>
|
|
|
+ <Users className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("openCustomer")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ )}
|
|
|
+ </ContextMenuContent>
|
|
|
+ </ContextMenu>
|
|
|
+ );
|
|
|
+ })
|
|
|
)}
|
|
|
</TableBody>
|
|
|
</Table>
|
|
|
@@ -1480,8 +1568,9 @@ export function DashboardClient({
|
|
|
const vehicleLabel = obs.vehicle.licensePlate
|
|
|
?? `${obs.vehicle.year} ${obs.vehicle.make}`;
|
|
|
return (
|
|
|
+ <ContextMenu key={obs.id} modal={false}>
|
|
|
+ <ContextMenuTrigger asChild>
|
|
|
<TableRow
|
|
|
- key={obs.id}
|
|
|
className="cursor-pointer"
|
|
|
onClick={() => router.push(`/vehicles/${obs.vehicle.id}?tab=findings`)}
|
|
|
>
|
|
|
@@ -1494,7 +1583,9 @@ export function DashboardClient({
|
|
|
</Badge>
|
|
|
</TableCell>
|
|
|
<TableCell className="py-1.5 font-mono text-xs text-muted-foreground truncate">
|
|
|
- {vehicleLabel}
|
|
|
+ <TableCellLink href={`/vehicles/${obs.vehicle.id}`}>
|
|
|
+ {vehicleLabel}
|
|
|
+ </TableCellLink>
|
|
|
</TableCell>
|
|
|
<TableCell className="py-1.5 text-xs font-medium truncate max-w-0">
|
|
|
{obs.description}
|
|
|
@@ -1503,6 +1594,20 @@ export function DashboardClient({
|
|
|
{formatRelativeTime(obs.createdAt)}
|
|
|
</TableCell>
|
|
|
</TableRow>
|
|
|
+ </ContextMenuTrigger>
|
|
|
+ <ContextMenuContent className="min-w-52">
|
|
|
+ <ContextMenuItem
|
|
|
+ onClick={() => router.push(`/vehicles/${obs.vehicle.id}?tab=findings`)}
|
|
|
+ >
|
|
|
+ <ExternalLink className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("open")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ <ContextMenuItem onClick={() => router.push(`/vehicles/${obs.vehicle.id}`)}>
|
|
|
+ <Car className="mr-2 h-4 w-4" />
|
|
|
+ {tcm("openVehicle")}
|
|
|
+ </ContextMenuItem>
|
|
|
+ </ContextMenuContent>
|
|
|
+ </ContextMenu>
|
|
|
);
|
|
|
})}
|
|
|
</TableBody>
|