diff --git a/components/dashboard/Chart.tsx b/components/dashboard/Chart.tsx index c03c6f8..2512f16 100644 --- a/components/dashboard/Chart.tsx +++ b/components/dashboard/Chart.tsx @@ -17,6 +17,7 @@ import { formatNumber, formatDuration } from '@/lib/utils/format' import { ArrowUpRightIcon, ArrowDownRightIcon, DownloadIcon, BarChartIcon } from '@ciphera-net/ui' import { Button } from '@ciphera-net/ui' import { Checkbox } from '@ciphera-net/ui' +import ExportModal from './ExportModal' const COLORS = { brand: '#FD5E0F', @@ -42,7 +43,7 @@ const CHART_COLORS_DARK = { tooltipBorder: '#404040', } -interface DailyStat { +export interface DailyStat { date: string pageviews: number visitors: number @@ -163,6 +164,7 @@ function formatAxisValue(value: number): string { export default function Chart({ data, prevData, stats, prevStats, interval }: ChartProps) { const [metric, setMetric] = useState('visitors') const [showComparison, setShowComparison] = useState(false) + const [isExportModalOpen, setIsExportModalOpen] = useState(false) const { resolvedTheme } = useTheme() const colors = useMemo( @@ -213,17 +215,7 @@ export default function Chart({ data, prevData, stats, prevStats, interval }: Ch } const handleExport = () => { - const csvContent = "data:text/csv;charset=utf-8," - + "Date,Pageviews,Visitors\n" - + data.map(row => `${new Date(row.date).toISOString()},${row.pageviews},${row.visitors}`).join("\n") - - const encodedUri = encodeURI(csvContent) - const link = document.createElement("a") - link.setAttribute("href", encodedUri) - link.setAttribute("download", `pulse_export_${new Date().toISOString().split('T')[0]}.csv`) - document.body.appendChild(link) - link.click() - document.body.removeChild(link) + setIsExportModalOpen(true) } const metrics = [ @@ -502,6 +494,11 @@ export default function Chart({ data, prevData, stats, prevStats, interval }: Ch )} + setIsExportModalOpen(false)} + data={data} + /> ) } diff --git a/components/dashboard/ExportModal.tsx b/components/dashboard/ExportModal.tsx new file mode 100644 index 0000000..0dd378a --- /dev/null +++ b/components/dashboard/ExportModal.tsx @@ -0,0 +1,171 @@ +'use client' + +import { useState } from 'react' +import { Modal, Button, Checkbox, Input, Select } from '@ciphera-net/ui' +import type { DailyStat } from './Chart' + +interface ExportModalProps { + isOpen: boolean + onClose: () => void + data: DailyStat[] +} + +type ExportFormat = 'csv' | 'json' + +export default function ExportModal({ isOpen, onClose, data }: ExportModalProps) { + const [format, setFormat] = useState('csv') + const [filename, setFilename] = useState(`pulse_export_${new Date().toISOString().split('T')[0]}`) + const [includeHeader, setIncludeHeader] = useState(true) + const [selectedFields, setSelectedFields] = useState>({ + date: true, + pageviews: true, + visitors: true, + bounce_rate: true, + avg_duration: true, + }) + + const handleFieldChange = (field: keyof DailyStat, checked: boolean) => { + setSelectedFields((prev) => ({ ...prev, [field]: checked })) + } + + const handleExport = () => { + // Filter fields + const fields = (Object.keys(selectedFields) as Array).filter((k) => selectedFields[k]) + + // Prepare data + const exportData = data.map((item) => { + const filteredItem: Partial = {} + fields.forEach((field) => { + filteredItem[field] = item[field] + }) + return filteredItem + }) + + let content = '' + let mimeType = '' + let extension = '' + + if (format === 'csv') { + const header = fields.join(',') + const rows = exportData.map((row) => + fields.map((field) => { + const val = row[field] + if (field === 'date' && typeof val === 'string') { + return new Date(val).toISOString() + } + return val + }).join(',') + ) + content = (includeHeader ? header + '\n' : '') + rows.join('\n') + mimeType = 'text/csv;charset=utf-8;' + extension = 'csv' + } else { + content = JSON.stringify(exportData, null, 2) + mimeType = 'application/json;charset=utf-8;' + extension = 'json' + } + + const blob = new Blob([content], { type: mimeType }) + const url = URL.createObjectURL(blob) + const link = document.createElement('a') + link.setAttribute('href', url) + link.setAttribute('download', `${filename || 'export'}.${extension}`) + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + onClose() + } + + return ( + +
+ {/* Filename & Format */} +
+
+ + setFilename(e.target.value)} + placeholder="filename" + /> +
+
+ +