feat: breadcrumb nav, grouped properties sidebar, larger status selector, transitions
This commit is contained in:
@@ -19,6 +19,7 @@ import type {
|
||||
PreviewResult,
|
||||
UpdateResult,
|
||||
} from "@/lib/types";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const STATUS_COLORS: Record<string, string> = {
|
||||
@@ -85,7 +86,7 @@ function TransactionBubble({
|
||||
|
||||
return (
|
||||
<div className="flex justify-center py-2">
|
||||
<span className="text-xs text-[#8a8f98]">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{message} · {timeAgo}
|
||||
</span>
|
||||
</div>
|
||||
@@ -109,28 +110,28 @@ function TransactionBubble({
|
||||
style={{
|
||||
backgroundColor: isAgent
|
||||
? getInitialColor(tx.creator_id)
|
||||
: "#191a1b",
|
||||
: "var(--muted)",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="text-[11px] font-semibold"
|
||||
style={{ color: isAgent ? "#f7f8f8" : "#8a8f98" }}
|
||||
style={{ color: isAgent ? "#f7f8f8" : "var(--muted-foreground)" }}
|
||||
>
|
||||
{getInitial(tx.creator_id)}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"max-w-[75%] rounded-lg px-3 py-2",
|
||||
"max-w-[75%] rounded-lg px-3 py-2 transition-all duration-150",
|
||||
isAgent
|
||||
? "bg-[#5e6ad2]/15 text-[#f7f8f8]"
|
||||
? "bg-primary/15 text-foreground"
|
||||
: isInternal
|
||||
? "bg-[#191a1b] border border-[rgba(255,255,255,0.05)] text-[#f7f8f8]"
|
||||
: "bg-[#191a1b] text-[#f7f8f8]"
|
||||
? "bg-muted border border-border text-foreground"
|
||||
: "bg-muted text-foreground"
|
||||
)}
|
||||
>
|
||||
{isInternal && (
|
||||
<div className="text-[10px] font-semibold text-[#f59e0b] mb-0.5 uppercase tracking-wider">
|
||||
<div className="text-[10px] font-semibold text-chart-3 mb-0.5 uppercase tracking-wider">
|
||||
Internal note
|
||||
</div>
|
||||
)}
|
||||
@@ -139,7 +140,7 @@ function TransactionBubble({
|
||||
? String((tx.data as Record<string, unknown>).body)
|
||||
: tx.transaction_type}
|
||||
</p>
|
||||
<p className="text-[10px] text-[#8a8f98] mt-1">{timeAgo}</p>
|
||||
<p className="text-[10px] text-muted-foreground mt-1">{timeAgo}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -262,17 +263,17 @@ export default function TicketDetailPage({
|
||||
<div className="flex-1 p-4 space-y-4">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<div key={i} className="flex gap-3">
|
||||
<div className="w-6 h-6 rounded-full bg-[#191a1b] animate-pulse" />
|
||||
<div className="w-6 h-6 rounded-full bg-muted animate-pulse" />
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="h-3 bg-[#191a1b] rounded animate-pulse w-3/4" />
|
||||
<div className="h-3 bg-[#191a1b] rounded animate-pulse w-1/2" />
|
||||
<div className="h-3 bg-muted rounded animate-pulse w-3/4" />
|
||||
<div className="h-3 bg-muted rounded animate-pulse w-1/2" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="w-80 bg-[#0f1011] border-l border-[rgba(255,255,255,0.05)] p-4 space-y-3">
|
||||
<div className="w-80 bg-sidebar border-l border-border p-4 space-y-3">
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<div key={i} className="h-6 bg-[#191a1b] rounded animate-pulse" />
|
||||
<div key={i} className="h-6 bg-muted rounded animate-pulse" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -282,10 +283,10 @@ export default function TicketDetailPage({
|
||||
if (error && !ticket) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<p className="text-red-400 text-sm">{error}</p>
|
||||
<p className="text-destructive text-sm">{error}</p>
|
||||
<button
|
||||
onClick={fetchData}
|
||||
className="mt-2 text-sm text-[#7170ff] hover:text-[#828fff]"
|
||||
className="mt-2 text-sm text-primary hover:text-primary/80 transition-all duration-150"
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
@@ -296,7 +297,7 @@ export default function TicketDetailPage({
|
||||
if (!ticket) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full">
|
||||
<p className="text-[#8a8f98] text-sm">Ticket not found</p>
|
||||
<p className="text-muted-foreground text-sm">Ticket not found</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -311,28 +312,31 @@ export default function TicketDetailPage({
|
||||
{/* Left panel — conversation */}
|
||||
<div className="flex-1 flex flex-col min-w-0">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3 px-4 py-2.5 border-b border-[rgba(255,255,255,0.05)]">
|
||||
<div className="flex items-center gap-3 px-4 py-2.5 border-b border-border">
|
||||
<Link
|
||||
href="/"
|
||||
className="w-7 h-7 flex items-center justify-center rounded-md hover:bg-[rgba(255,255,255,0.05)] text-[#8a8f98] hover:text-[#d0d6e0] transition-colors flex-shrink-0"
|
||||
className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-all duration-150"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4" />
|
||||
<ArrowLeftIcon className="w-3.5 h-3.5" />
|
||||
All tickets
|
||||
</Link>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h1 className="text-sm font-semibold text-[#f7f8f8] truncate">
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<div className="px-4 py-3 border-b border-border">
|
||||
<h1 className="text-sm font-semibold text-foreground truncate">
|
||||
{ticket.subject}
|
||||
</h1>
|
||||
<p className="text-xs text-[#8a8f98]">
|
||||
{ticket.id.slice(0, 8)} · {queue?.name || ticket.queue_id}
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
<span className="font-mono">{ticket.id.slice(0, 8)}</span> · {queue?.name || ticket.queue_id}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Conversation */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{transactions.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center py-20">
|
||||
<p className="text-sm text-[#8a8f98]">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
No activity yet
|
||||
</p>
|
||||
</div>
|
||||
@@ -343,16 +347,16 @@ export default function TicketDetailPage({
|
||||
</div>
|
||||
|
||||
{/* Reply box */}
|
||||
<div className="border-t border-[rgba(255,255,255,0.05)] bg-[#0f1011] p-3">
|
||||
<div className="border-t border-border bg-sidebar p-3">
|
||||
{/* Toggle tabs */}
|
||||
<div className="flex gap-0.5 mb-2 p-0.5 rounded-lg bg-[#08090a] w-fit">
|
||||
<div className="flex gap-0.5 mb-2 p-0.5 rounded-lg bg-background w-fit">
|
||||
<button
|
||||
onClick={() => setReplyMode("public")}
|
||||
className={cn(
|
||||
"px-2.5 py-1 rounded-md text-xs font-medium transition-colors",
|
||||
"px-2.5 py-1 rounded-md text-xs font-medium transition-all duration-150",
|
||||
replyMode === "public"
|
||||
? "bg-[#5e6ad2] text-[#f7f8f8]"
|
||||
: "text-[#8a8f98] hover:text-[#d0d6e0]"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
Reply
|
||||
@@ -360,10 +364,10 @@ export default function TicketDetailPage({
|
||||
<button
|
||||
onClick={() => setReplyMode("internal")}
|
||||
className={cn(
|
||||
"px-2.5 py-1 rounded-md text-xs font-medium transition-colors",
|
||||
"px-2.5 py-1 rounded-md text-xs font-medium transition-all duration-150",
|
||||
replyMode === "internal"
|
||||
? "bg-[#5e6ad2] text-[#f7f8f8]"
|
||||
: "text-[#8a8f98] hover:text-[#d0d6e0]"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
Internal note
|
||||
@@ -376,19 +380,19 @@ export default function TicketDetailPage({
|
||||
onChange={(e) => setReplyText(e.target.value)}
|
||||
placeholder="Reply to this ticket..."
|
||||
rows={2}
|
||||
className="flex-1 px-3 py-2 rounded-lg bg-[#08090a] border border-[rgba(255,255,255,0.08)] text-sm text-[#f7f8f8] placeholder:text-[#8a8f98] outline-none focus:border-[#5e6ad2] focus:ring-1 focus:ring-[#5e6ad2] resize-none"
|
||||
className="flex-1 px-3 py-2 rounded-lg bg-background border border-border text-sm text-foreground placeholder:text-muted-foreground outline-none focus:border-primary focus:ring-1 focus:ring-primary resize-none transition-all duration-150"
|
||||
/>
|
||||
<div className="flex items-center gap-1">
|
||||
<button className="w-8 h-8 flex items-center justify-center rounded-lg text-[#8a8f98] hover:text-[#d0d6e0] hover:bg-[rgba(255,255,255,0.05)] transition-colors" title="Attach file (coming soon)">
|
||||
<button className="w-8 h-8 flex items-center justify-center rounded-lg text-muted-foreground hover:text-foreground hover:bg-accent transition-all duration-150" title="Attach file (coming soon)">
|
||||
<PaperclipIcon className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
disabled={!replyText.trim()}
|
||||
className={cn(
|
||||
"w-8 h-8 flex items-center justify-center rounded-lg transition-colors",
|
||||
"w-8 h-8 flex items-center justify-center rounded-lg transition-all duration-150",
|
||||
replyText.trim()
|
||||
? "bg-[#5e6ad2] text-[#f7f8f8] hover:bg-[#7170ff]"
|
||||
: "bg-[#191a1b] text-[#8a8f98] cursor-not-allowed"
|
||||
? "bg-primary text-primary-foreground hover:bg-primary/80"
|
||||
: "bg-muted text-muted-foreground cursor-not-allowed"
|
||||
)}
|
||||
>
|
||||
<SendIcon className="w-4 h-4" />
|
||||
@@ -399,27 +403,27 @@ export default function TicketDetailPage({
|
||||
</div>
|
||||
|
||||
{/* Right panel — properties */}
|
||||
<div className="w-80 flex-shrink-0 bg-[#0f1011] border-l border-[rgba(255,255,255,0.05)] flex flex-col overflow-y-auto">
|
||||
<div className="p-4 space-y-4">
|
||||
{/* Status */}
|
||||
<div className="w-80 flex-shrink-0 bg-sidebar border-l border-border flex flex-col overflow-y-auto">
|
||||
<div className="p-4 space-y-5">
|
||||
{/* Section: Status */}
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
|
||||
Status
|
||||
</label>
|
||||
</h3>
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setStatusSelectOpen(!statusSelectOpen)}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 rounded-lg border border-[rgba(255,255,255,0.08)] bg-[#08090a] text-sm hover:border-[rgba(255,255,255,0.15)] transition-colors"
|
||||
className="w-full flex items-center gap-3 px-4 py-2.5 rounded-lg border border-border bg-background text-sm hover:border-foreground/20 transition-all duration-150"
|
||||
>
|
||||
<span
|
||||
className="w-2.5 h-2.5 rounded-full flex-shrink-0"
|
||||
className="w-3 h-3 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: currentStatusColor }}
|
||||
/>
|
||||
<span className="text-[#f7f8f8] font-medium flex-1 text-left">
|
||||
<span className="text-foreground font-medium flex-1 text-left">
|
||||
{currentStatusLabel}
|
||||
</span>
|
||||
<svg
|
||||
className="w-4 h-4 text-[#8a8f98]"
|
||||
className="w-4 h-4 text-muted-foreground"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -434,7 +438,7 @@ export default function TicketDetailPage({
|
||||
</button>
|
||||
|
||||
{statusSelectOpen && (
|
||||
<div className="absolute top-full left-0 right-0 mt-1 z-10 bg-[#191a1b] border border-[rgba(255,255,255,0.08)] rounded-lg shadow-xl overflow-hidden">
|
||||
<div className="absolute top-full left-0 right-0 mt-1 z-10 bg-popover border border-border rounded-lg shadow-xl overflow-hidden">
|
||||
{ALL_STATUSES.map((status) => {
|
||||
const color = STATUS_COLORS[status];
|
||||
const label = STATUS_LABELS[status];
|
||||
@@ -445,19 +449,19 @@ export default function TicketDetailPage({
|
||||
onClick={() => handleStatusSelect(status)}
|
||||
disabled={isCurrent}
|
||||
className={cn(
|
||||
"w-full flex items-center gap-2 px-3 py-2 text-sm text-left transition-colors",
|
||||
"w-full flex items-center gap-3 px-4 py-2.5 text-sm text-left transition-all duration-150",
|
||||
isCurrent
|
||||
? "bg-[rgba(255,255,255,0.03)] text-[#8a8f98] cursor-default"
|
||||
: "text-[#d0d6e0] hover:bg-[rgba(255,255,255,0.05)]"
|
||||
? "bg-accent text-muted-foreground cursor-default"
|
||||
: "text-foreground hover:bg-accent"
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className="w-2.5 h-2.5 rounded-full flex-shrink-0"
|
||||
className="w-3 h-3 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
{label}
|
||||
{isCurrent && (
|
||||
<span className="text-xs text-[#8a8f98] ml-auto">
|
||||
<span className="text-xs text-muted-foreground ml-auto">
|
||||
current
|
||||
</span>
|
||||
)}
|
||||
@@ -471,10 +475,10 @@ export default function TicketDetailPage({
|
||||
|
||||
{/* Status change preview */}
|
||||
{preview && (
|
||||
<div className="p-3 rounded-lg bg-[#08090a] border border-[rgba(255,255,255,0.08)]">
|
||||
<p className="text-xs text-[#8a8f98] mb-2">
|
||||
<div className="p-3 rounded-lg bg-background border border-border">
|
||||
<p className="text-xs text-muted-foreground mb-2">
|
||||
Preview: changing to{" "}
|
||||
<span className="text-[#f7f8f8] font-medium">
|
||||
<span className="text-foreground font-medium">
|
||||
{STATUS_LABELS[pendingStatus || ""]}
|
||||
</span>
|
||||
</p>
|
||||
@@ -483,15 +487,15 @@ export default function TicketDetailPage({
|
||||
{preview.prepared_scrips.map((scrip) => (
|
||||
<div
|
||||
key={scrip.scripId}
|
||||
className="text-xs text-[#d0d6e0] flex items-center gap-1.5"
|
||||
className="text-xs text-foreground flex items-center gap-1.5"
|
||||
>
|
||||
<span className="w-2 h-2 rounded-full bg-[#f59e0b] flex-shrink-0" />
|
||||
<span className="w-2 h-2 rounded-full bg-chart-3 flex-shrink-0" />
|
||||
{scrip.scripName}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-xs text-[#8a8f98] mb-3">
|
||||
<p className="text-xs text-muted-foreground mb-3">
|
||||
No scrips will fire
|
||||
</p>
|
||||
)}
|
||||
@@ -499,7 +503,7 @@ export default function TicketDetailPage({
|
||||
<button
|
||||
onClick={handleApplyStatus}
|
||||
disabled={applyLoading}
|
||||
className="px-2.5 py-1 rounded-md text-xs font-medium bg-[#5e6ad2] hover:bg-[#7170ff] text-[#f7f8f8] disabled:opacity-50 transition-colors"
|
||||
className="px-2.5 py-1 rounded-md text-xs font-medium bg-primary hover:bg-primary/80 text-primary-foreground disabled:opacity-50 transition-all duration-150"
|
||||
>
|
||||
{applyLoading
|
||||
? "Applying..."
|
||||
@@ -508,7 +512,7 @@ export default function TicketDetailPage({
|
||||
<button
|
||||
onClick={handleCancelStatus}
|
||||
disabled={applyLoading}
|
||||
className="px-2.5 py-1 rounded-md text-xs font-medium text-[#8a8f98] hover:text-[#d0d6e0] transition-colors"
|
||||
className="px-2.5 py-1 rounded-md text-xs font-medium text-muted-foreground hover:text-foreground transition-all duration-150"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
@@ -517,27 +521,27 @@ export default function TicketDetailPage({
|
||||
)}
|
||||
|
||||
{previewError && (
|
||||
<div className="p-2 rounded-lg bg-red-400/5 border border-red-400/10">
|
||||
<p className="text-xs text-red-400">{previewError}</p>
|
||||
<div className="p-2 rounded-lg bg-destructive/5 border border-destructive/10">
|
||||
<p className="text-xs text-destructive">{previewError}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{scripResults && (
|
||||
<div className="p-3 rounded-lg bg-[#08090a] border border-[rgba(255,255,255,0.08)]">
|
||||
<p className="text-xs text-[#8a8f98] mb-2">Scrip results:</p>
|
||||
<div className="p-3 rounded-lg bg-background border border-border">
|
||||
<p className="text-xs text-muted-foreground mb-2">Scrip results:</p>
|
||||
<div className="space-y-1">
|
||||
{scripResults.map((result) => (
|
||||
<div
|
||||
key={result.scripId}
|
||||
className={cn(
|
||||
"text-xs flex items-center gap-1.5",
|
||||
result.success ? "text-[#22c55e]" : "text-red-400"
|
||||
result.success ? "text-[#22c55e]" : "text-destructive"
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"w-2 h-2 rounded-full flex-shrink-0",
|
||||
result.success ? "bg-[#22c55e]" : "bg-red-400"
|
||||
result.success ? "bg-[#22c55e]" : "bg-destructive"
|
||||
)}
|
||||
/>
|
||||
{result.message}
|
||||
@@ -546,58 +550,75 @@ export default function TicketDetailPage({
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setScripResults(null)}
|
||||
className="mt-2 text-xs text-[#8a8f98] hover:text-[#d0d6e0]"
|
||||
className="mt-2 text-xs text-muted-foreground hover:text-foreground transition-all duration-150"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Priority (placeholder) */}
|
||||
<Separator />
|
||||
|
||||
{/* Section: Assignment */}
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
Priority
|
||||
</label>
|
||||
<div className="px-3 py-2 rounded-lg border border-[rgba(255,255,255,0.05)] bg-[#08090a] text-sm text-[#8a8f98]">
|
||||
Not set
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
|
||||
Assignment
|
||||
</h3>
|
||||
|
||||
{/* Assignee */}
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
<div className="mb-3">
|
||||
<label className="block text-[11px] font-medium text-muted-foreground mb-1">
|
||||
Assignee
|
||||
</label>
|
||||
{ticket.owner_id ? (
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg border border-[rgba(255,255,255,0.08)] bg-[#08090a]">
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg border border-border bg-background transition-all duration-150 hover:border-foreground/20">
|
||||
<div
|
||||
className="w-5 h-5 rounded-full flex items-center justify-center flex-shrink-0"
|
||||
style={{
|
||||
backgroundColor: getInitialColor(ticket.owner_id),
|
||||
}}
|
||||
>
|
||||
<span className="text-[10px] font-semibold text-[#f7f8f8]">
|
||||
<span className="text-[10px] font-semibold text-primary-foreground">
|
||||
{getInitial(ticket.owner_id)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-sm text-[#f7f8f8]">
|
||||
<span className="text-sm text-foreground">
|
||||
{ticket.owner_id}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="px-3 py-2 rounded-lg border border-[rgba(255,255,255,0.05)] bg-[#08090a] text-sm text-[#8a8f98]">
|
||||
<div className="px-3 py-2 rounded-lg border border-border bg-background text-sm text-muted-foreground">
|
||||
Unassigned
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Queue */}
|
||||
{/* Priority (placeholder) */}
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
<label className="block text-[11px] font-medium text-muted-foreground mb-1">
|
||||
Priority
|
||||
</label>
|
||||
<div className="px-3 py-2 rounded-lg border border-border bg-background text-sm text-muted-foreground">
|
||||
Not set
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Section: Details */}
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
|
||||
Details
|
||||
</h3>
|
||||
|
||||
{/* Queue */}
|
||||
<div className="mb-3">
|
||||
<label className="block text-[11px] font-medium text-muted-foreground mb-1">
|
||||
Queue
|
||||
</label>
|
||||
<div className="px-3 py-2 rounded-lg border border-[rgba(255,255,255,0.08)] bg-[#08090a]">
|
||||
<span className="text-sm text-[#f7f8f8]">
|
||||
<div className="px-3 py-2 rounded-lg border border-border bg-background">
|
||||
<span className="text-sm text-foreground">
|
||||
{queue?.name || ticket.queue_id}
|
||||
</span>
|
||||
</div>
|
||||
@@ -605,20 +626,20 @@ export default function TicketDetailPage({
|
||||
|
||||
{/* Custom fields */}
|
||||
{ticket.custom_fields && ticket.custom_fields.length > 0 && (
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
<div className="mb-3">
|
||||
<label className="block text-[11px] font-medium text-muted-foreground mb-1">
|
||||
Custom fields
|
||||
</label>
|
||||
<div className="space-y-1.5">
|
||||
{ticket.custom_fields.map((cf) => (
|
||||
<div
|
||||
key={cf.id}
|
||||
className="flex justify-between items-center px-3 py-1.5 rounded-lg border border-[rgba(255,255,255,0.05)] bg-[#08090a]"
|
||||
className="flex justify-between items-center px-3 py-1.5 rounded-lg border border-border bg-background"
|
||||
>
|
||||
<span className="text-xs text-[#8a8f98]">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{cf.custom_field?.name || cf.custom_field_id}
|
||||
</span>
|
||||
<span className="text-xs text-[#f7f8f8] font-medium">
|
||||
<span className="text-xs text-foreground font-medium">
|
||||
{cf.value}
|
||||
</span>
|
||||
</div>
|
||||
@@ -629,30 +650,27 @@ export default function TicketDetailPage({
|
||||
|
||||
{/* Dates */}
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#8a8f98] mb-1.5 uppercase tracking-wider">
|
||||
Dates
|
||||
</label>
|
||||
<div className="space-y-1 text-xs">
|
||||
<div className="flex justify-between px-1">
|
||||
<span className="text-[#8a8f98]">Created</span>
|
||||
<span className="text-[#d0d6e0] tabular-nums">
|
||||
<div className="space-y-1.5 text-xs">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Created</span>
|
||||
<span className="text-foreground tabular-nums">
|
||||
{formatDistanceToNow(new Date(ticket.created_at), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between px-1">
|
||||
<span className="text-[#8a8f98]">Updated</span>
|
||||
<span className="text-[#d0d6e0] tabular-nums">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Updated</span>
|
||||
<span className="text-foreground tabular-nums">
|
||||
{formatDistanceToNow(new Date(ticket.updated_at), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
{ticket.resolved_at && (
|
||||
<div className="flex justify-between px-1">
|
||||
<span className="text-[#8a8f98]">Resolved</span>
|
||||
<span className="text-[#d0d6e0] tabular-nums">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Resolved</span>
|
||||
<span className="text-foreground tabular-nums">
|
||||
{formatDistanceToNow(new Date(ticket.resolved_at), {
|
||||
addSuffix: true,
|
||||
})}
|
||||
@@ -664,5 +682,6 @@ export default function TicketDetailPage({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user