File size: 3,947 Bytes
78d0e31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"use client"

import type React from "react"

import { useEffect, useState } from "react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { UserCheck, HeartHandshake, DollarSign, Users } from "lucide-react"
import { Skeleton } from "@/components/ui/skeleton"

// Type for stats
type PulseStatsData = {
  verifiedCHWs: number
  activeGuardians: number
  totalSupport: number
  livesImpacted: number
  totalUsers: number
  lastUpdated: string
}

export function PulseStats() {
  const [stats, setStats] = useState<Partial<PulseStatsData>>({})
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const fetchStats = async () => {
      try {
        const response = await fetch("/api/stats")
        if (!response.ok) {
          throw new Error("Failed to fetch stats")
        }

        const data = await response.json()
        setStats(data)
      } catch (err) {
        setError("Failed to load statistics")
        console.error(err)
      } finally {
        setLoading(false)
      }
    }

    fetchStats()
  }, [])

  // Stat card component
  const StatCard = ({
    title,
    value,
    icon: Icon,
    isLoading,
    isError,
    colorClass,
  }: {
    title: string
    value: number | string
    icon: React.ElementType
    isLoading: boolean
    isError: boolean
    colorClass?: string
  }) => (
    <Card
      className={`bg-gradient-to-br ${colorClass ? `${colorClass}/20 to-${colorClass}/5 border border-${colorClass}/20` : "from-background to-muted border"} shadow-lg rounded-xl overflow-hidden relative group`}
    >
      {colorClass && (
        <div
          className={`absolute inset-0 bg-${colorClass}/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500`}
        ></div>
      )}
      <CardHeader className="flex flex-row items-center justify-between pb-2 relative z-10">
        <CardTitle className="text-sm font-medium text-muted-foreground">{title}</CardTitle>
        <Icon className={`h-5 w-5 ${colorClass ? `text-${colorClass}` : "text-primary"}`} />
      </CardHeader>
      <CardContent className="relative z-10">
        {isError ? (
          <div className="text-red-500 text-sm">Data unavailable</div>
        ) : isLoading ? (
          <Skeleton className="h-8 w-3/4 bg-muted-foreground/20" />
        ) : (
          <div className={`text-2xl font-bold ${colorClass ? `text-${colorClass}` : "text-foreground"}`}>{value}</div>
        )}
        <p className="text-xs text-muted-foreground/80 mt-1">
          {isLoading
            ? "Loading..."
            : error
              ? "Update failed"
              : stats.lastUpdated
                ? `Updated: ${new Date(stats.lastUpdated).toLocaleString()}`
                : "Live data"}
        </p>
      </CardContent>
    </Card>
  )

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
      <StatCard
        title="Verified CHWs"
        value={stats.verifiedCHWs?.toLocaleString() || "0"}
        icon={UserCheck}
        isLoading={loading}
        isError={!!error}
        colorClass="flame"
      />
      <StatCard
        title="Active Guardians"
        value={stats.activeGuardians?.toLocaleString() || "0"}
        icon={HeartHandshake}
        isLoading={loading}
        isError={!!error}
        colorClass="guardian"
      />
      <StatCard
        title="Total Support"
        value={`$${stats.totalSupport?.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) || "0.00"}`}
        icon={DollarSign}
        isLoading={loading}
        isError={!!error}
        colorClass="pulse"
      />
      <StatCard
        title="Lives Impacted"
        value={stats.livesImpacted?.toLocaleString() || "0"}
        icon={Users}
        isLoading={loading}
        isError={!!error}
        colorClass="neon"
      />
    </div>
  )
}