diff --git a/frontend/src/landing_page/landing_page_armor/ImpactDashboard.js b/frontend/src/landing_page/landing_page_armor/ImpactDashboard.js
index fc5dc8b..43b23fa 100644
--- a/frontend/src/landing_page/landing_page_armor/ImpactDashboard.js
+++ b/frontend/src/landing_page/landing_page_armor/ImpactDashboard.js
@@ -3,19 +3,22 @@ import React, { useEffect, useRef, useState } from "react";
const ACCENT_YELLOW = "#defe47";
const ACCENT_BLUE = "#28b2fb";
-const stats = [
- { label: "Community Members", value: 2000, suffix: "+" },
- { label: "Cities Represented", value: 30, suffix: "+" },
- { label: "Events Hosted", value: 50, suffix: "+" },
- { label: "AI Agents in Gallery", value: 50, suffix: "+" },
- { label: "Academy Lectures", value: 10, suffix: "+" },
- { label: "AI Courses Available", value: 20, suffix: "+" },
+const API_KEY = "AIzaSyCjxXVDGAolugKgrTXpJ0HmAjL0lLxLN1E";
+const MEMBERS_SHEET_ID = "1IREd2vCxo7rDGOoDUYtzoywVGLqqUFCsu3qGsA0HsMc";
+const MEMBERS_SHEET_NAME = "Sheet-1";
+const CALENDAR_ID = "e88890e803003d95935e56c48dc68aedfd5311e3204360f781830c06287f4f24@group.calendar.google.com";
+
+const STATIC_STATS = [
+ { key: "cities", label: "Cities Represented", value: 30, suffix: "+" },
+ { key: "agents", label: "AI Agents in Gallery", value: 50, suffix: "+" },
+ { key: "lectures", label: "Academy Lectures", value: 10, suffix: "+" },
+ { key: "courses", label: "AI Courses Available", value: 20, suffix: "+" },
];
function useCountUp(target, duration, start) {
const [count, setCount] = useState(0);
useEffect(() => {
- if (!start) return;
+ if (!start || !target) return;
let startTime = null;
const step = (timestamp) => {
if (!startTime) startTime = timestamp;
@@ -39,8 +42,7 @@ function StatCard({ label, value, suffix, animate }) {
}}
>
- {animate ? count : 0}
- {suffix}
+ {animate ? count : 0}{suffix}
{label}
@@ -50,34 +52,91 @@ function StatCard({ label, value, suffix, animate }) {
export default function ImpactDashboard() {
const ref = useRef(null);
const [animate, setAnimate] = useState(false);
+ const [memberCount, setMemberCount] = useState(2000);
+ const [eventCount, setEventCount] = useState(50);
+ // Live member count from Google Sheets
+ useEffect(() => {
+ const url = `https://sheets.googleapis.com/v4/spreadsheets/${MEMBERS_SHEET_ID}/values/${encodeURIComponent(MEMBERS_SHEET_NAME)}?key=${API_KEY}`;
+ fetch(url)
+ .then((r) => r.json())
+ .then((data) => {
+ if (data.values && data.values.length > 1) {
+ setMemberCount(data.values.length - 1); // subtract header row
+ }
+ })
+ .catch(() => {});
+ }, []);
+
+ // Live event count from Google Calendar
+ useEffect(() => {
+ const url =
+ `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(CALENDAR_ID)}/events` +
+ `?key=${API_KEY}&singleEvents=true&maxResults=250`;
+ fetch(url)
+ .then((r) => r.json())
+ .then((data) => {
+ if (data.items && data.items.length > 0) {
+ setEventCount(data.items.length);
+ }
+ })
+ .catch(() => {});
+ }, []);
+
+ // Trigger count-up animation on scroll into view
useEffect(() => {
const observer = new IntersectionObserver(
- ([entry]) => {
- if (entry.isIntersecting) setAnimate(true);
- },
+ ([entry]) => { if (entry.isIntersecting) setAnimate(true); },
{ threshold: 0.2 }
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, []);
+ const allStats = [
+ { key: "members", label: "Community Members", value: memberCount, suffix: "+" },
+ { key: "events", label: "Events Hosted", value: eventCount, suffix: "+" },
+ ...STATIC_STATS,
+ ];
+
+ const shareText = `Join ${memberCount}+ AI builders at the Anote AI Community — ${eventCount}+ events hosted across 30+ cities. community.anote.ai`;
+
return (
-
-
- Community Impact
-
-
- Growing together across the U.S.
-
+
+
+
+ Community Impact
+
+
+ Growing together across the U.S.
+
+
+
- {stats.map((s) => (
-
+ {allStats.map((s) => (
+
))}