feat(users): implement advanced user actions (notifications, moderation, support, audit)
This commit is contained in:
134
src/features/users/components/dialogs/ReceiptViewer.tsx
Normal file
134
src/features/users/components/dialogs/ReceiptViewer.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Download, Printer, Copy, CreditCard } from 'lucide-react';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { formatCurrency } from '@/data/mockData';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
interface ReceiptViewerProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
booking: any; // Using any for now, ideally UserBooking
|
||||
}
|
||||
|
||||
export function ReceiptViewer({
|
||||
open,
|
||||
onOpenChange,
|
||||
booking
|
||||
}: ReceiptViewerProps) {
|
||||
if (!booking) return null;
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
navigator.clipboard.writeText(text);
|
||||
toast.success("Copied to clipboard");
|
||||
};
|
||||
|
||||
// Mock calculations for the receipt
|
||||
const basePrice = booking.amount * 0.9;
|
||||
const tax = booking.amount * 0.1;
|
||||
const fee = 2.50; // Mock processing fee
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-[480px] p-0 overflow-hidden flex flex-col bg-white">
|
||||
<div className="bg-slate-900 p-6 text-white text-center rounded-t-lg">
|
||||
<div className="w-12 h-12 bg-white/10 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<CreditCard className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<h2 className="text-xl font-bold tracking-tight">Receipt from Eventify</h2>
|
||||
<p className="text-slate-400 text-sm mt-1">Thank you for your business.</p>
|
||||
</div>
|
||||
|
||||
<ScrollArea className="max-h-[60vh]">
|
||||
<div className="p-6 space-y-6">
|
||||
{/* Meta Data */}
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-wider">Order ID</p>
|
||||
<div className="flex items-center gap-1 font-mono font-medium hover:text-primary cursor-pointer" onClick={() => copyToClipboard(booking.id)}>
|
||||
{booking.id.substring(0, 12)}...
|
||||
<Copy className="h-3 w-3 opacity-50" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-wider">Date</p>
|
||||
<p className="font-medium">{new Date(booking.createdAt).toLocaleDateString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="bg-slate-100" />
|
||||
|
||||
{/* Customer Info */}
|
||||
<div>
|
||||
<p className="text-muted-foreground text-xs uppercase tracking-wider mb-2">Billed To</p>
|
||||
<p className="font-semibold text-sm">User ID: {booking.userId}</p>
|
||||
<p className="text-sm text-slate-500">Payment Method: Visa •••• 4242</p>
|
||||
</div>
|
||||
|
||||
{/* Line Items */}
|
||||
<div className="bg-slate-50 p-4 rounded-lg border border-slate-100">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-xs text-muted-foreground text-left border-b border-slate-200">
|
||||
<th className="pb-2 font-medium">Description</th>
|
||||
<th className="pb-2 font-medium text-right">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100">
|
||||
<tr>
|
||||
<td className="py-3">
|
||||
<p className="font-medium text-slate-900">{booking.eventName}</p>
|
||||
<p className="text-xs text-slate-500">{booking.ticketType} x {booking.quantity}</p>
|
||||
</td>
|
||||
<td className="py-3 text-right tabular-nums text-slate-900">
|
||||
{formatCurrency(basePrice)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-2 text-slate-500">Processing Fees</td>
|
||||
<td className="py-2 text-right tabular-nums text-slate-500">{formatCurrency(fee)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-2 text-slate-500">Tax (10%)</td>
|
||||
<td className="py-2 text-right tabular-nums text-slate-500">{formatCurrency(tax)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td className="pt-3 font-bold text-slate-900">Total</td>
|
||||
<td className="pt-3 font-bold text-right tabular-nums text-slate-900">{formatCurrency(booking.amount + fee)}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Status */}
|
||||
<div className="flex justify-center">
|
||||
<Badge variant="outline" className="px-3 py-1 font-normal text-slate-500 border-slate-200 bg-slate-50">
|
||||
Status: <span className="font-semibold text-slate-900 ml-1">{booking.status}</span>
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<div className="p-4 border-t border-slate-100 bg-slate-50 flex gap-2 justify-end">
|
||||
<Button variant="outline" size="sm" onClick={() => window.print()}>
|
||||
<Printer className="mr-2 h-4 w-4" /> Print
|
||||
</Button>
|
||||
<Button variant="default" size="sm">
|
||||
<Download className="mr-2 h-4 w-4" /> Download PDF
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user