Add CSV export functionality for admin orders
- Created exportCSV utility with convertToCSV, downloadCSV, formatExportDate, formatExportIDR - Added export button to AdminOrders page with loading state - Export includes all order fields: ID, email, total, status, payment method, date, refund info - CSV format compatible with Excel and Google Sheets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,9 +13,10 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { formatIDR, formatDateTime } from "@/lib/format";
|
||||
import { Eye, CheckCircle, XCircle, Video, ExternalLink, Trash2, AlertTriangle, RefreshCw, Link as LinkIcon } from "lucide-react";
|
||||
import { Eye, CheckCircle, XCircle, Video, ExternalLink, Trash2, AlertTriangle, RefreshCw, Link as LinkIcon, Download } from "lucide-react";
|
||||
import { toast } from "@/hooks/use-toast";
|
||||
import { getPaymentStatusLabel, getPaymentStatusColor, canRefundOrder, canCancelOrder, canMarkAsPaid } from "@/lib/statusHelpers";
|
||||
import { convertToCSV, downloadCSV, formatExportDate, formatExportIDR } from "@/lib/exportCSV";
|
||||
|
||||
interface Order {
|
||||
id: string;
|
||||
@@ -64,6 +65,7 @@ export default function AdminOrders() {
|
||||
const [selectedSlotId, setSelectedSlotId] = useState<string | null>(null);
|
||||
const [newMeetLink, setNewMeetLink] = useState("");
|
||||
const [creatingMeetLink, setCreatingMeetLink] = useState(false);
|
||||
const [exporting, setExporting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!authLoading) {
|
||||
@@ -280,6 +282,62 @@ export default function AdminOrders() {
|
||||
);
|
||||
};
|
||||
|
||||
const handleExportOrders = async () => {
|
||||
setExporting(true);
|
||||
try {
|
||||
// Fetch all orders with full details
|
||||
const { data: ordersData, error } = await supabase
|
||||
.from("orders")
|
||||
.select("*, profile:profiles(email)")
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Transform data for CSV export
|
||||
const csvData = (ordersData as Order[]).map((order) => ({
|
||||
"Order ID": order.id,
|
||||
"Email": order.profile?.email || "",
|
||||
"Total": formatExportIDR(order.total_amount),
|
||||
"Status": getPaymentStatusLabel(order.payment_status),
|
||||
"Metode Pembayaran": order.payment_method || "",
|
||||
"Referensi": order.payment_reference || "",
|
||||
"Tanggal": formatExportDate(order.created_at),
|
||||
"Refund Amount": order.refunded_amount ? formatExportIDR(order.refunded_amount) : "",
|
||||
"Refund Reason": order.refund_reason || "",
|
||||
"Refunded At": order.refunded_at ? formatExportDate(order.refunded_at) : "",
|
||||
}));
|
||||
|
||||
// Convert to CSV
|
||||
const headers = [
|
||||
"Order ID",
|
||||
"Email",
|
||||
"Total",
|
||||
"Status",
|
||||
"Metode Pembayaran",
|
||||
"Referensi",
|
||||
"Tanggal",
|
||||
"Refund Amount",
|
||||
"Refund Reason",
|
||||
"Refunded At",
|
||||
];
|
||||
const csv = convertToCSV(csvData, headers);
|
||||
|
||||
// Download CSV
|
||||
const filename = `orders-${new Date().toISOString().split('T')[0]}.csv`;
|
||||
downloadCSV(csv, filename);
|
||||
|
||||
toast({ title: "Berhasil", description: "Data order berhasil di-export" });
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: error.message || "Gagal men-export data order",
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (authLoading || loading) {
|
||||
return (
|
||||
<AppLayout>
|
||||
@@ -294,8 +352,21 @@ export default function AdminOrders() {
|
||||
return (
|
||||
<AppLayout>
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<h1 className="text-4xl font-bold mb-2">Manajemen Order</h1>
|
||||
<p className="text-muted-foreground mb-8">Kelola semua pesanan</p>
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Manajemen Order</h1>
|
||||
<p className="text-muted-foreground">Kelola semua pesanan</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleExportOrders}
|
||||
variant="outline"
|
||||
className="gap-2 border-2"
|
||||
disabled={exporting || orders.length === 0}
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
{exporting ? "Men-export..." : "Export Orders"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card className="border-2 border-border hidden md:block">
|
||||
<CardContent className="p-0">
|
||||
|
||||
Reference in New Issue
Block a user