import React from 'react' import { useSiteContext } from '../../site-context' import { popover } from '../../components/popover' import classNames from 'classnames' import { Spinner } from '../../components/icons' import { ArrowDownTrayIcon, ExclamationCircleIcon } from '@heroicons/react/24/outline' import { useDashboardStateContext } from '../../dashboard-state-context' import { useGraphIntervalContext } from '../graph/graph-interval-context' import { createCsvExportRequestBody } from './csv-export-body' import * as api from '../../api' import { DateRange } from '../../stats-query' import { DashboardState } from '../../dashboard-state' import { hasConversionGoalFilter, hasPageFilter } from '../../util/filters' import { trackEvent } from '../../dogfood' import { Tooltip } from '../../util/tooltip' import { useBodyPortalRef } from '../breakdowns' export enum ExportStatus { idle = 'idle', exporting = 'exporting', error = 'error' } function durationBucket(ms: number): string { const s = ms / 1000 if (s >= 20) return '20s+' const floor = Math.floor(s / 2) * 2 return `${floor}-${floor + 2}s` } function dogfoodTrackCsvExport( isSuccess: boolean, dashboardState: DashboardState, startedAt: number ): void { trackEvent('csv_export', { is_success: String(isSuccess), goal_filter: String(hasConversionGoalFilter(dashboardState)), page_filter: String(hasPageFilter(dashboardState)), period: dashboardState.period, duration_bucket: durationBucket(performance.now() - startedAt) }) } export function CsvExport({ exportStatus, setExportStatus }: { exportStatus: ExportStatus setExportStatus: (v: ExportStatus) => void }) { const site = useSiteContext() const { dashboardState } = useDashboardStateContext() const { selectedInterval } = useGraphIntervalContext() const canStartExport = exportStatus === ExportStatus.idle const startExport = async () => { if (!canStartExport) return setExportStatus(ExportStatus.exporting) const startedAt = performance.now() try { const body = createCsvExportRequestBody(dashboardState, selectedInterval) const blob = await api.csvExport(site, body) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = constructFilename(site.domain, body.date_range) document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) setExportStatus(ExportStatus.idle) dogfoodTrackCsvExport(true, dashboardState, startedAt) } catch { setExportStatus(ExportStatus.error) dogfoodTrackCsvExport(false, dashboardState, startedAt) } } return ( ) } function ExportFailedBubble() { const portalRef = useBodyPortalRef() return ( ) } function constructFilename(domain: string, dateRange: DateRange) { const dateRangeText = Array.isArray(dateRange) ? `${dateRange[0]} to ${dateRange[1]}` : dateRange return `Plausible export ${domain} ${dateRangeText} .zip` }