import {useEffect, useState} from 'react' import { Area, AreaChart, CartesianGrid, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts' import {useT} from 'web/lib/locale' import {getCompletedProfilesCreations, getProfilesCreations} from 'web/lib/supabase/users' // ─── Helpers ────────────────────────────────────────────────────────────────── function buildCounts(rows: any[]) { const counts: Record = {} for (const r of rows) { const date = new Date(r.created_time).toISOString().split('T')[0] counts[date] = (counts[date] || 0) + 1 } return counts } function cumulativeFromCounts(counts: Record, sortedDates: string[]) { const out: Record = {} let prev = 0 for (const d of sortedDates) { prev += counts[d] || 0 out[d] = prev } return out } function toISODate(d: Date) { return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())) .toISOString() .split('T')[0] } function addDays(d: Date, days: number) { const nd = new Date(d) nd.setUTCDate(nd.getUTCDate() + days) return nd } function buildDailyRange(startStr: string, endStr: string) { const out: string[] = [] const start = new Date(startStr + 'T00:00:00.000Z') const end = new Date(endStr + 'T00:00:00.000Z') for (let d = start; d <= end; d = addDays(d, 1)) out.push(toISODate(d)) return out } function formatDate(ts: number) { return new Date(ts).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit', }) } // ─── Custom Tooltip ─────────────────────────────────────────────────────────── function CustomTooltip({active, payload, label}: any) { if (!active || !payload?.length) return null const date = payload[0]?.payload?.date ? new Date(payload[0].payload.date).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric', }) : formatDate(label) return (

{date}

{payload.map((entry: any) => (
{entry.name} {entry.value.toLocaleString()}
))}
) } // ─── Custom Legend ──────────────────────────────────────────────────────────── function CustomLegend({payload}: any) { return (
{payload?.map((entry: any) => (
{entry.value}
))}
) } // ─── Chart ──────────────────────────────────────────────────────────────────── export default function ChartMembers() { const [data, setData] = useState([]) const [chartHeight, setChartHeight] = useState(380) const [loading, setLoading] = useState(true) const t = useT() useEffect(() => { function applyHeight() { setChartHeight(window.innerWidth < 420 ? 280 : 380) } applyHeight() window.addEventListener('resize', applyHeight) return () => window.removeEventListener('resize', applyHeight) }, []) useEffect(() => { async function load() { const [allProfiles, completedProfiles] = await Promise.all([ getProfilesCreations(), getCompletedProfilesCreations(), ]) const countsAll = buildCounts(allProfiles) const countsCompleted = buildCounts(completedProfiles) const allDates = Object.keys(countsAll) const completedDates = Object.keys(countsCompleted) const sorted = [...allDates, ...completedDates].sort((a, b) => a.localeCompare(b)) const minDateStr = sorted[0] const maxDateStr = sorted[sorted.length - 1] const dates = buildDailyRange(minDateStr, maxDateStr) const cumAll = cumulativeFromCounts(countsAll, dates) const cumCompleted = cumulativeFromCounts(countsCompleted, dates) setData( dates.map((date) => ({ date, dateTs: new Date(date + 'T00:00:00.000Z').getTime(), profilesCreations: cumAll[date] || 0, profilesCompletedCreations: cumCompleted[date] || 0, })), ) setLoading(false) } void load() }, []) // Colors from palette const AMBER = 'rgb(193 127 62)' // primary-500 const SAGE = 'rgb(107 143 113)' // green-500 return (
{/* Loading shimmer */} {loading && (
Loading chart…
)} {!loading && ( {/* Gradient fills */} (v >= 1000 ? `${(v / 1000).toFixed(1)}K` : v)} width={40} /> } cursor={{stroke: 'rgb(193 127 62)', strokeWidth: 1, strokeDasharray: '4 2'}} /> } /> {/* Completed (sage, behind) */} {/* Total (amber, on top) */} )}
) }