feat(users): implement inspector tabs and server actions
This commit is contained in:
@@ -59,6 +59,11 @@ import {
|
||||
} from '../data/mockUserCrmData';
|
||||
import { formatCurrency } from '@/data/mockData';
|
||||
import { ActionButtons } from './ActionButtons';
|
||||
import { OverviewTab } from './tabs/OverviewTab';
|
||||
import { BookingsTab } from './tabs/BookingsTab';
|
||||
import { SecurityTab } from './tabs/SecurityTab';
|
||||
import { SupportTab } from './tabs/SupportTab';
|
||||
import { AuditTab } from './tabs/AuditTab';
|
||||
import { toast } from 'sonner';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
@@ -78,7 +83,6 @@ export function UserInspectorSheet({
|
||||
onSendNotification,
|
||||
}: UserInspectorSheetProps) {
|
||||
const [activeTab, setActiveTab] = useState('overview');
|
||||
const [noteContent, setNoteContent] = useState('');
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
@@ -215,138 +219,37 @@ export function UserInspectorSheet({
|
||||
<TabsList className="w-full justify-start h-9 bg-transparent p-0">
|
||||
<TabsTrigger value="overview" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Overview</TabsTrigger>
|
||||
<TabsTrigger value="orders" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Orders</TabsTrigger>
|
||||
<TabsTrigger value="admin" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Admin Notes</TabsTrigger>
|
||||
<TabsTrigger value="security" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Security</TabsTrigger>
|
||||
<TabsTrigger value="support" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Support</TabsTrigger>
|
||||
<TabsTrigger value="admin" className="h-9 rounded-none border-b-2 border-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent px-4 text-xs">Audit</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
<ScrollArea className="flex-1 bg-secondary/5">
|
||||
<div className="p-4 space-y-6">
|
||||
<div className="p-4">
|
||||
{/* Tab 1: Overview */}
|
||||
<TabsContent value="overview" className="m-0 space-y-6">
|
||||
{/* Contact Info */}
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3">Contact Information</h3>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex items-center gap-3">
|
||||
<Mail className="h-3.5 w-3.5 text-primary/60" />
|
||||
<span className="text-foreground">{user.email}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Phone className="h-3.5 w-3.5 text-primary/60" />
|
||||
<span className="text-foreground">{user.countryCode} {user.phone}</span>
|
||||
</div>
|
||||
{user.lastDevice && (
|
||||
<div className="flex items-center gap-3">
|
||||
<MapPin className="h-3.5 w-3.5 text-primary/60" />
|
||||
<span className="text-foreground">{user.lastDevice.location}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="border-dashed" />
|
||||
|
||||
{/* Last Activity */}
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3">Last Activity</h3>
|
||||
<div className="flex items-start gap-3 p-3 bg-white border border-border/50 rounded-lg shadow-sm">
|
||||
<div className="mt-0.5">
|
||||
<Clock className="h-4 w-4 text-blue-500" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium">Scanned at <span className="text-foreground font-semibold">Tech Summit 2026</span></p>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">2 hours ago • Verified by Staff</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="border-dashed" />
|
||||
|
||||
{/* Tags */}
|
||||
<div>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3">Tags</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{user.tags.map((tag) => (
|
||||
<Badge key={tag.id} variant="outline" className={cn("rounded-md px-2 py-0.5 font-normal", tag.color)}>
|
||||
{tag.name}
|
||||
</Badge>
|
||||
))}
|
||||
<Button variant="outline" size="sm" className="h-6 rounded-md px-2 text-xs border-dashed gap-1 text-muted-foreground hover:text-foreground">
|
||||
<Plus className="h-3 w-3" /> Add
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<TabsContent value="overview" className="m-0">
|
||||
<OverviewTab user={user} notes={notes.length > 0 ? notes[0].content : ''} />
|
||||
</TabsContent>
|
||||
|
||||
{/* Tab 2: Orders */}
|
||||
<TabsContent value="orders" className="m-0">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="hover:bg-transparent">
|
||||
<TableHead className="h-8 text-xs font-medium">Event</TableHead>
|
||||
<TableHead className="h-8 text-xs font-medium text-right">Date</TableHead>
|
||||
<TableHead className="h-8 text-xs font-medium text-right">Amount</TableHead>
|
||||
<TableHead className="h-8 text-xs font-medium text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{bookings.slice(0, 5).map((booking) => (
|
||||
<TableRow key={booking.id} className="hover:bg-transparent border-0">
|
||||
<TableCell className="py-2 text-sm font-medium">
|
||||
{booking.eventName}
|
||||
<div className="text-[10px] text-muted-foreground font-normal">{booking.ticketType} x{booking.quantity}</div>
|
||||
</TableCell>
|
||||
<TableCell className="py-2 text-xs text-right text-muted-foreground">
|
||||
{new Date(booking.eventDate).toLocaleDateString('en-IN', { day: 'numeric', month: 'short' })}
|
||||
</TableCell>
|
||||
<TableCell className="py-2 text-xs text-right font-medium">
|
||||
{formatCurrency(booking.amount)}
|
||||
</TableCell>
|
||||
<TableCell className="py-2 text-right">
|
||||
<Badge variant="outline" className="text-[10px] h-5 px-1.5 font-normal">
|
||||
{booking.status}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{bookings.length === 0 && (
|
||||
<div className="text-center py-8 text-xs text-muted-foreground">No orders found.</div>
|
||||
)}
|
||||
<BookingsTab bookings={bookings} />
|
||||
</TabsContent>
|
||||
|
||||
{/* Tab 3: Admin Notes */}
|
||||
<TabsContent value="admin" className="m-0 space-y-4">
|
||||
<div className="p-3 bg-amber-50 border border-amber-200 rounded-lg space-y-2">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<AlertTriangle className="h-3.5 w-3.5 text-amber-600" />
|
||||
<span className="text-xs font-bold text-amber-800 uppercase tracking-wide">Internal Notes</span>
|
||||
</div>
|
||||
<Textarea
|
||||
className="min-h-[100px] border- amber-200/50 bg-white/50 focus-visible:ring-amber-500/30 text-sm resize-none"
|
||||
placeholder="Add private notes about this user..."
|
||||
value={noteContent}
|
||||
onChange={(e) => setNoteContent(e.target.value)}
|
||||
/>
|
||||
<div className="flex justify-end">
|
||||
<Button size="sm" className="h-7 text-xs bg-amber-600 hover:bg-amber-700 text-white border-none shadow-none">
|
||||
Save Note
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Tab 3: Security */}
|
||||
<TabsContent value="security" className="m-0">
|
||||
<SecurityTab user={user} />
|
||||
</TabsContent>
|
||||
|
||||
<div className="space-y-3">
|
||||
{notes.map((note) => (
|
||||
<div key={note.id} className="relative pl-4 border-l-2 border-border/50 py-1">
|
||||
<p className="text-sm text-foreground">{note.content}</p>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="text-[10px] font-medium text-muted-foreground">{note.authorName}</span>
|
||||
<span className="text-[10px] text-muted-foreground/60">• {new Date(note.createdAt).toLocaleDateString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* Tab 4: Support */}
|
||||
<TabsContent value="support" className="m-0">
|
||||
<SupportTab user={user} />
|
||||
</TabsContent>
|
||||
|
||||
{/* Tab 5: Audit (Admin Notes / Activity) */}
|
||||
<TabsContent value="admin" className="m-0">
|
||||
<AuditTab userId={user.id} />
|
||||
</TabsContent>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
Reference in New Issue
Block a user