feat: sticky modal header with Autotask icon + close X, remove bottom nav bar

- Header always visible: ticket icon, number, title (truncated), ExternalLink icon
  to Autotask, X close button — all in a fixed top bar
- showCloseButton={false} on DialogContent, replaced with custom header buttons
- Modal is now flex-col h-85vh: header shrinks-to-content, body scrolls
- Removed Close/Open in Autotask bottom action bar entirely
This commit is contained in:
lorentz 2026-03-23 11:30:31 -04:00
parent be61c30204
commit f0da6b203a

View file

@ -4,8 +4,7 @@ import { useState, useEffect, useMemo } from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogClose,
} from '@/components/ui/dialog';
import {
Collapsible,
@ -13,7 +12,6 @@ import {
CollapsibleTrigger,
} from '@/components/ui/collapsible';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Separator } from '@/components/ui/separator';
import {
Ticket as TicketIcon,
@ -29,6 +27,7 @@ import {
Timer,
Bot,
UserCircle,
X,
} from 'lucide-react';
// noteType values that are system/automated (workflow rules, monitoring, auto-close, etc.)
@ -230,16 +229,44 @@ export function TicketDetailModal({ ticketNumber, open, onOpenChange }: TicketDe
return `${hours.toFixed(2)}h`;
};
const autotaskUrl = ticket
? `https://ww1.autotask.net/Mvc/ServiceDesk/TicketDetail.mvc?workspace=False&ids%5B0%5D=${ticket.id}&ticketId=${ticket.id}`
: null;
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl w-[90vw] max-h-[85vh] overflow-y-auto">
<DialogHeader className="pb-0">
<DialogTitle className="flex items-center gap-2 text-base">
<TicketIcon className="h-4 w-4 shrink-0" />
<span className="font-mono text-blue-600 dark:text-blue-400">{ticketNumber}</span>
{ticket && <span className="text-muted-foreground font-normal truncate">{ticket.title}</span>}
</DialogTitle>
</DialogHeader>
<DialogContent
showCloseButton={false}
className="max-w-4xl w-[90vw] h-[85vh] flex flex-col p-0 gap-0 overflow-hidden"
>
{/* Sticky header */}
<div className="flex items-center gap-2 px-4 py-3 border-b shrink-0 min-w-0">
<TicketIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
<span className="font-mono text-sm font-semibold text-blue-600 dark:text-blue-400 shrink-0">{ticketNumber}</span>
<span className="text-sm text-muted-foreground truncate flex-1 min-w-0">
{ticket?.title ?? (loading ? 'Loading…' : '')}
</span>
<div className="flex items-center gap-1 shrink-0 ml-2">
{autotaskUrl && (
<a
href={autotaskUrl}
target="_blank"
rel="noopener noreferrer"
title="Open in Autotask"
className="inline-flex h-7 w-7 items-center justify-center rounded-sm opacity-70 hover:opacity-100 transition-opacity"
>
<ExternalLink className="h-4 w-4" />
</a>
)}
<DialogClose className="inline-flex h-7 w-7 items-center justify-center rounded-sm opacity-70 hover:opacity-100 transition-opacity">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogClose>
</div>
</div>
{/* Scrollable body */}
<div className="flex-1 overflow-y-auto overflow-x-hidden min-w-0 p-4">
{loading && (
<div className="flex items-center justify-center py-6">
@ -446,26 +473,9 @@ export function TicketDetailModal({ ticketNumber, open, onOpenChange }: TicketDe
</CollapsibleContent>
</Collapsible>
{/* Actions */}
<div className="flex justify-end gap-2 pt-1">
<Button variant="outline" size="sm" onClick={() => onOpenChange(false)}>
Close
</Button>
<Button
size="sm"
onClick={() => {
window.open(
`https://ww1.autotask.net/Mvc/ServiceDesk/TicketDetail.mvc?workspace=False&ids%5B0%5D=${ticket.id}&ticketId=${ticket.id}`,
'_blank'
);
}}
>
<ExternalLink className="h-4 w-4 mr-2" />
Open in Autotask
</Button>
</div>
</div>
)}
</div>
</DialogContent>
</Dialog>
);