File size: 6,012 Bytes
9dfccd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { useState } from 'react'
import { apiFetch } from '@/lib/http'
import { cn } from '@/lib/utils'

type ExportFormat = 'csv' | 'pdf'
type ExportScope  = 'queries' | 'topics' | 'health' | 'escalations' | 'full'

const SCOPES: Array<{ id: ExportScope; label: string; desc: string }> = [
  { id: 'queries',     label: 'Query analytics',      desc: 'Volume, success rate, response times' },
  { id: 'topics',      label: 'Top topics',           desc: 'Most-queried subjects'                },
  { id: 'health',      label: 'Knowledge health',     desc: 'Coverage, freshness, accuracy scores' },
  { id: 'escalations', label: 'Escalations',          desc: 'Unresolved queries by frequency'      },
  { id: 'full',        label: 'Full report',          desc: 'All of the above combined'            },
]

export function AnalyticsExport() {
  const [scope,      setScope]      = useState<ExportScope>('full')
  const [format,     setFormat]     = useState<ExportFormat>('csv')
  const [dateRange,  setDateRange]  = useState('30d')
  const [exporting,  setExporting]  = useState(false)

  async function handleExport() {
    setExporting(true)
    try {
      const res = await apiFetch(
        `/api/analytics/export?scope=${scope}&format=${format}&date_range=${dateRange}`,
      )
      const blob        = await res.blob()
      const ext         = format === 'pdf' ? 'pdf' : 'csv'
      const filename    = `godspeed-analytics-${scope}-${dateRange}.${ext}`
      const url         = URL.createObjectURL(blob)
      const a           = document.createElement('a')
      a.href            = url
      a.download        = filename
      a.click()
      URL.revokeObjectURL(url)
    } finally {
      setExporting(false)
    }
  }

  return (
    <div className="rounded-xl border border-surface-subtle p-5">
      <p className="mb-4 text-sm font-medium text-stone-500">Export Analytics</p>

      <div className="flex flex-col gap-5 sm:flex-row sm:items-end">
        {/* Scope */}
        <div className="flex-1">
          <label className="mb-1.5 block text-xs font-medium text-stone-500">Report scope</label>
          <div className="flex flex-col gap-1.5">
            {SCOPES.map((s) => (
              <label
                key={s.id}
                className={cn(
                  'flex cursor-pointer items-start gap-3 rounded-lg border p-3 transition-colors',
                  scope === s.id
                    ? 'border-brand bg-amber-50 dark:bg-amber-950/20'
                    : 'border-surface-subtle hover:border-stone-300',
                )}
              >
                <input
                  type="radio"
                  name="scope"
                  value={s.id}
                  checked={scope === s.id}
                  onChange={() => setScope(s.id)}
                  className="mt-0.5 accent-amber-700"
                />
                <div>
                  <p className="text-sm font-medium">{s.label}</p>
                  <p className="text-xs text-stone-400">{s.desc}</p>
                </div>
              </label>
            ))}
          </div>
        </div>

        {/* Format + date range + button */}
        <div className="flex flex-col gap-4 sm:w-48">
          <div>
            <label className="mb-1.5 block text-xs font-medium text-stone-500">Format</label>
            <div className="flex rounded-lg border border-surface-subtle text-sm">
              {(['csv', 'pdf'] as const).map((f) => (
                <button
                  key={f}
                  onClick={() => setFormat(f)}
                  className={cn(
                    'flex-1 py-2 transition-colors first:rounded-l-lg last:rounded-r-lg font-medium uppercase tracking-wide',
                    format === f
                      ? 'bg-brand text-white'
                      : 'text-stone-500 hover:text-stone-700',
                  )}
                >
                  {f}
                </button>
              ))}
            </div>
          </div>

          <div>
            <label className="mb-1.5 block text-xs font-medium text-stone-500">Date range</label>
            <select
              value={dateRange}
              onChange={(e) => setDateRange(e.target.value)}
              className="w-full rounded-lg border border-surface-subtle bg-white px-3 py-2 text-sm dark:bg-stone-900"
            >
              <option value="7d">Last 7 days</option>
              <option value="30d">Last 30 days</option>
              <option value="90d">Last 90 days</option>
              <option value="all">All time</option>
            </select>
          </div>

          <button
            onClick={handleExport}
            disabled={exporting}
            className={cn(
              'flex items-center justify-center gap-2 rounded-lg py-2.5 text-sm font-semibold transition-colors',
              exporting
                ? 'cursor-not-allowed bg-stone-200 text-stone-400 dark:bg-stone-700'
                : 'bg-brand text-white hover:bg-brand/90',
            )}
          >
            {exporting ? (
              <>
                <svg className="h-4 w-4 animate-spin" viewBox="0 0 24 24" fill="none">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                </svg>
                Exporting…
              </>
            ) : (
              <>
                <svg className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                  <path fillRule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clipRule="evenodd" />
                </svg>
                Download {format.toUpperCase()}
              </>
            )}
          </button>
        </div>
      </div>
    </div>
  )
}