Skip to content

Commit ee166fe

Browse files
committed
fix: premium admin redesign, AI summary sync, and global timezone consistency
1 parent d939522 commit ee166fe

File tree

3 files changed

+43
-24
lines changed

3 files changed

+43
-24
lines changed

Frontend/src/admin/pages/AdminTicketDetail.jsx

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { Select } from "../../components/ui/select";
1515
import TicketChat from "../../components/shared/TicketChat";
1616
import { formatTicketId } from "../../utils/format";
1717
import SLABadge from "../components/SLABadge";
18+
import { formatFullTimestamp, formatTimelineDate } from "../../utils/dateUtils";
19+
import TicketTimeline from "../../user/components/TicketTimeline"; // Reuse the 6-step timeline
1820

1921
const AdminTicketDetail = () => {
2022
const { ticket_id } = useParams();
@@ -173,13 +175,10 @@ const AdminTicketDetail = () => {
173175

174176
if (!ticket) return null;
175177

176-
const displayCategory = ticket.category || 'Uncategorized';
177-
const displayPriority = ticket.priority || 'Medium';
178-
const displaySubcategory = ticket.subcategory || 'General';
179-
const displayStatus = ticket.status || 'Open';
180-
const displaySummary = ticket.subject || 'No Summary';
181-
const displayText = ticket.description || displaySummary;
182178
const confidence = ticket.metadata?.confidence || 0.85;
179+
const entities = ticket.metadata?.entities || ticket.entities || [];
180+
const displaySummary = ticket.summary || ticket.subject || 'No Summary';
181+
const displayText = ticket.description || ticket.text || displaySummary;
183182

184183
return (
185184
<div className="space-y-6 relative pb-20 animate-in fade-in duration-700">
@@ -210,9 +209,9 @@ const AdminTicketDetail = () => {
210209
</div>
211210

212211
<div className="flex items-center gap-2 w-full md:w-auto">
213-
{!displayStatus?.toLowerCase()?.includes('resolv') ? (
212+
{!ticket.status?.toLowerCase()?.includes('resolv') ? (
214213
<>
215-
{displayStatus?.toLowerCase() !== 'in progress' && (
214+
{ticket.status?.toLowerCase() !== 'in progress' && (
216215
<button
217216
onClick={handleAccept}
218217
disabled={!!isUpdating}
@@ -265,7 +264,7 @@ const AdminTicketDetail = () => {
265264
<h3 className="text-sm font-black text-slate-900 uppercase italic tracking-tight flex items-center gap-2">
266265
<MessageSquare size={18} className="text-indigo-600" /> User Input Payload
267266
</h3>
268-
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest">Captured {new Date(ticket.created_at).toLocaleTimeString()}</span>
267+
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-widest italic">{formatFullTimestamp(ticket.created_at)}</span>
269268
</div>
270269
<div className="p-8 space-y-6">
271270
<div className="p-8 bg-slate-900 text-white rounded-3xl border-l-[6px] border-indigo-600 shadow-2xl shadow-slate-900/10">
@@ -301,6 +300,15 @@ const AdminTicketDetail = () => {
301300
currentUserRole="admin"
302301
/>
303302
</div>
303+
304+
{/* Integrated Journey Timeline */}
305+
<Card className="border-none shadow-xl shadow-slate-200/40 rounded-[2rem] overflow-hidden bg-white p-8">
306+
<div className="flex items-center gap-3 mb-6">
307+
<Clock size={18} className="text-emerald-500" />
308+
<h3 className="text-sm font-black text-slate-900 uppercase italic tracking-tight">Full Lifecycle Journey</h3>
309+
</div>
310+
<TicketTimeline ticket={ticket} />
311+
</Card>
304312
</div>
305313

306314
{/* 2. AI Analytics Column (Right - 4 cols) */}
@@ -328,12 +336,12 @@ const AdminTicketDetail = () => {
328336
<div className="grid grid-cols-1 gap-3">
329337
<div className="flex items-center justify-between p-3 bg-white border border-slate-100 rounded-xl shadow-sm">
330338
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest flex items-center gap-2"><Briefcase size={12} className="text-indigo-400" /> Category</span>
331-
<span className="text-[11px] font-black text-slate-900 uppercase italic">{displayCategory}</span>
339+
<span className="text-[11px] font-black text-slate-900 uppercase italic">{ticket.category}</span>
332340
</div>
333341
<div className="flex items-center justify-between p-3 bg-white border border-slate-100 rounded-xl shadow-sm">
334342
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest flex items-center gap-2"><BarChart3 size={12} className="text-amber-400" /> Priority</span>
335-
<span className={`text-[11px] font-black uppercase italic ${displayPriority?.toLowerCase() === 'high' ? 'text-red-600' : 'text-slate-900'}`}>
336-
{displayPriority}
343+
<span className={`text-[11px] font-black uppercase italic ${ticket.priority?.toLowerCase() === 'high' ? 'text-red-600' : 'text-slate-900'}`}>
344+
{ticket.priority}
337345
</span>
338346
</div>
339347
</div>
@@ -354,13 +362,13 @@ const AdminTicketDetail = () => {
354362
</div>
355363

356364
{/* Extracted Artifacts (Entities) */}
357-
{ticket.entities && ticket.entities.length > 0 && (
365+
{entities && entities.length > 0 && (
358366
<div className="space-y-3">
359367
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest italic">Identified Entities</label>
360368
<div className="flex flex-wrap gap-2">
361-
{ticket.entities.map((e, idx) => (
369+
{entities.map((e, idx) => (
362370
<span key={idx} className="px-3 py-1 bg-indigo-50 text-indigo-600 text-[9px] font-black uppercase tracking-widest rounded-lg border border-indigo-100">
363-
{String(e)}
371+
{typeof e === 'object' ? e.text : String(e)}
364372
</span>
365373
))}
366374
</div>

Frontend/src/admin/pages/AdminTickets.jsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
import { Select } from "../../components/ui/select";
2525
import { formatTicketId } from "../../utils/format";
2626
import SLABadge from "../components/SLABadge";
27+
import { formatFullTimestamp, formatTimelineDate } from "../../utils/dateUtils";
2728

2829
const AdminTickets = () => {
2930
const navigate = useNavigate();
@@ -175,10 +176,11 @@ const AdminTickets = () => {
175176
}, [tickets, searchQuery]);
176177

177178
const getPriorityStyle = (priority) => {
178-
const p = priority?.toLowerCase();
179+
const p = String(priority || '').toLowerCase();
179180
if (p === 'high' || p === 'critical') return 'text-red-600 bg-red-50 border-red-100';
180181
if (p === 'medium') return 'text-amber-600 bg-amber-50 border-amber-100';
181-
return 'text-emerald-600 bg-emerald-50 border-emerald-100';
182+
if (p === 'low') return 'text-emerald-600 bg-emerald-50 border-emerald-100';
183+
return 'text-slate-500 bg-slate-50 border-slate-100'; // Default
182184
};
183185

184186
const getConfidenceColor = (conf) => {
@@ -311,15 +313,20 @@ const AdminTickets = () => {
311313
{/* Subject */}
312314
<td className="px-6 py-6">
313315
<div className="flex flex-col">
314-
<span className="text-xs font-bold text-slate-700 truncate max-w-[200px]">{ticket.subject}</span>
315-
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest">{ticket.category}</span>
316+
<span className="text-xs font-bold text-slate-700 truncate max-w-[200px]" title={ticket.summary || ticket.subject}>
317+
{ticket.summary || ticket.subject}
318+
</span>
319+
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
320+
{ticket.category}
321+
<span className="text-[9px] font-medium text-slate-300">{formatTimelineDate(ticket.created_at)}</span>
322+
</span>
316323
</div>
317324
</td>
318325

319326
{/* Priority (Editable) */}
320327
<td className="px-6 py-6">
321328
<Select
322-
value={ticket.priority}
329+
value={String(ticket.priority || 'medium').toLowerCase()}
323330
onChange={(e) => handleUpdateTicket(ticket.id, { priority: e.target.value })}
324331
buttonClassName={`px-3 py-1.5 rounded-xl text-[9px] font-black uppercase tracking-wider border outline-none cursor-pointer transition-all flex items-center justify-between ${getPriorityStyle(ticket.priority)}`}
325332
options={priorities.filter(p => p !== 'All').map(p => ({ value: p.toLowerCase(), label: p }))}
@@ -341,7 +348,7 @@ const AdminTickets = () => {
341348
<div className="flex items-center gap-2">
342349
<div className={`w-1.5 h-1.5 rounded-full ${ticket.status?.toLowerCase() === 'resolved' || ticket.status?.toLowerCase() === 'closed' ? 'bg-emerald-400' : 'bg-amber-500 animate-pulse'}`}></div>
343350
<Select
344-
value={ticket.status}
351+
value={String(ticket.status || 'open').toLowerCase()}
345352
onChange={(e) => handleUpdateTicket(ticket.id, { status: e.target.value })}
346353
buttonClassName="bg-transparent text-[10px] font-black text-slate-600 uppercase tracking-widest outline-none cursor-pointer flex justify-between items-center w-full"
347354
options={statuses.filter(s => s !== 'All').map(s => ({ value: s.toLowerCase(), label: s }))}

backend/main.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,13 @@ def get_now_ist():
604604
except Exception:
605605
pass
606606

607-
# Generate a concise 1-2 line summary for the UI
608-
summary = text[:100] + "..." if len(text) > 100 else text
609-
if gemini_analysis["image_description"]:
607+
# Generate a concise 1-2 line summary for the UI using AI
608+
if gemini_service:
609+
summary = gemini_service.get_summary(text)
610+
else:
611+
summary = text[:100] + "..." if len(text) > 100 else text
612+
613+
if gemini_analysis.get("image_description") and "Image Report" not in summary:
610614
summary = f"Image Report: {summary}"
611615

612616
return TicketResponse(

0 commit comments

Comments
 (0)