Complete frontend implementation with: - Next.js 16 with App Router and TypeScript - Tailwind CSS v4 with custom violet theme - shadcn/ui components with Lucide React icons - Landing page with hero, services, pricing, testimonials, FAQ - Service selection page with toggle - Login/Register pages with social auth UI - Multi-step checkout flow - Client dashboard with stats, projects, support tickets - Billing page with subscription, payment methods, invoices - All mock data and TypeScript types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
'use client'
|
|
import { Circle, CircleCheck } from 'lucide-react'
|
|
|
|
import Link from 'next/link'
|
|
import type { SupportTicket } from '@/lib/types'
|
|
import { Badge } from '@/components/ui/badge'
|
|
|
|
const statusIcons: Record<SupportTicket['status'], React.ComponentType<{ className?: string }>> = {
|
|
open: Circle,
|
|
'in-progress': Circle,
|
|
resolved: CircleCheck,
|
|
closed: CircleCheck,
|
|
}
|
|
|
|
const statusColors: Record<SupportTicket['status'], string> = {
|
|
open: 'bg-emerald-500/10 text-emerald-400',
|
|
'in-progress': 'bg-blue-500/10 text-blue-400',
|
|
resolved: 'bg-gray-500/10 text-gray-400',
|
|
closed: 'bg-gray-500/10 text-gray-400',
|
|
}
|
|
|
|
const priorityColors: Record<SupportTicket['priority'], string> = {
|
|
low: '',
|
|
medium: 'bg-orange-500/10 text-orange-400',
|
|
high: 'bg-red-500/10 text-red-400',
|
|
}
|
|
|
|
interface SupportTicketItemProps {
|
|
ticket: SupportTicket
|
|
}
|
|
|
|
export function SupportTicketItem({ ticket }: SupportTicketItemProps) {
|
|
return (
|
|
<Link
|
|
href={`/dashboard/support/${ticket.id}`}
|
|
className="flex items-start gap-4 p-4 rounded-xl hover:bg-white/5 transition-colors group"
|
|
>
|
|
{/* Status indicator */}
|
|
<div className="flex-shrink-0 mt-1">
|
|
{ticket.status === 'open' || ticket.status === 'in-progress' ? (
|
|
<Circle className={`w-5 h-5 ${ticket.status === 'open' ? 'text-emerald-400' : 'text-blue-400'}`} />
|
|
) : (
|
|
<CircleCheck className="w-5 h-5 text-gray-400" />
|
|
)}
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<h4 className="font-semibold text-foreground truncate">{ticket.subject}</h4>
|
|
{ticket.priority === 'high' && (
|
|
<Badge className={`${priorityColors[ticket.priority]} text-xs`}>
|
|
High Priority
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
<p className="text-sm text-muted-foreground line-clamp-2">
|
|
{ticket.description}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Ticket number */}
|
|
<div className="flex-shrink-0 text-right">
|
|
<div className="text-xs text-muted-foreground">#{ticket.id}</div>
|
|
<Badge className={`mt-1 ${statusColors[ticket.status]}`}>
|
|
{ticket.status}
|
|
</Badge>
|
|
</div>
|
|
</Link>
|
|
)
|
|
}
|