import React, { useMemo, useState } from "react"; import "./overview.css"; /* ================= KPI CARD ================= */ function StackOverflowKpiCard({ icon, title, value, subtitle, accent, trend, progress, onClick, isActive, }) { const [isHovered, setIsHovered] = useState(false); return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} >
{icon} {title} {trend && ( 0 ? "positive" : "negative"}`}> {trend > 0 ? "↑" : "↓"} {Math.abs(trend)}% )}
{value}
{progress !== undefined && (
)}
{subtitle &&
{subtitle}
}
); } /* ================= FEATURED METRIC ================= */ function StackOverflowFeaturedMetric({ icon, title, value, subtitle, description, }) { return (
{icon}
{title}
{value}
{subtitle &&
{subtitle}
} {description && (
{description}
)}
); } /* ================= MAIN OVERVIEW ================= */ export default function StackOverflowKpiOverview({ rows = [] }) { const [selectedMetric, setSelectedMetric] = useState(null); const [viewMode, setViewMode] = useState("grid"); const metrics = useMemo(() => { if (!rows.length) return null; // Demographics const ageGroups = {}; const educationLevels = {}; const countries = {}; const employmentTypes = {}; const orgSizes = {}; const remoteWorkTypes = {}; // Experience const yearsCodeRanges = {}; const devTypes = new Set(); const icOrPM = {}; // Technology const languages = new Set(); const databases = new Set(); const platforms = new Set(); const aiTools = new Set(); // Salary & Satisfaction let totalSalary = 0; let salaryCount = 0; const jobSatLevels = {}; // AI Usage let aiUsers = 0; let aiSentiments = { positive: 0, negative: 0, neutral: 0 }; let aiThreats = { yes: 0, no: 0 }; rows.forEach((row) => { // Demographics if (row.Age) { ageGroups[row.Age] = (ageGroups[row.Age] || 0) + 1; } if (row.EdLevel) { educationLevels[row.EdLevel] = (educationLevels[row.EdLevel] || 0) + 1; } if (row.Country) { countries[row.Country] = (countries[row.Country] || 0) + 1; } if (row.Employment) { employmentTypes[row.Employment] = (employmentTypes[row.Employment] || 0) + 1; } if (row.OrgSize) { orgSizes[row.OrgSize] = (orgSizes[row.OrgSize] || 0) + 1; } if (row.RemoteWork) { remoteWorkTypes[row.RemoteWork] = (remoteWorkTypes[row.RemoteWork] || 0) + 1; } // Experience if (row.YearsCode) { yearsCodeRanges[row.YearsCode] = (yearsCodeRanges[row.YearsCode] || 0) + 1; } if (row.DevType) { row.DevType.split(";").forEach((type) => devTypes.add(type.trim())); } if (row.ICorPM) { icOrPM[row.ICorPM] = (icOrPM[row.ICorPM] || 0) + 1; } // Technology if (row.LanguageHaveWorkedWith) { row.LanguageHaveWorkedWith.split(";").forEach((lang) => languages.add(lang.trim()) ); } if (row.DatabaseHaveWorkedWith) { row.DatabaseHaveWorkedWith.split(";").forEach((db) => databases.add(db.trim()) ); } if (row.PlatformHaveWorkedWith) { row.PlatformHaveWorkedWith.split(";").forEach((platform) => platforms.add(platform.trim()) ); } if (row.AIModelsHaveWorkedWith) { row.AIModelsHaveWorkedWith.split(";").forEach((ai) => aiTools.add(ai.trim()) ); aiUsers++; } // Salary if (row.CompTotal && row.CompTotal !== "NA" && row.CompTotal !== "") { const salary = parseFloat(row.CompTotal.replace(/,/g, "")); if (!isNaN(salary)) { totalSalary += salary; salaryCount++; } } // Job Satisfaction if (row.JobSat) { jobSatLevels[row.JobSat] = (jobSatLevels[row.JobSat] || 0) + 1; } // AI Sentiment if (row.AISent) { if ( row.AISent.toLowerCase().includes("agree") || row.AISent.toLowerCase().includes("positive") ) { aiSentiments.positive++; } else if ( row.AISent.toLowerCase().includes("disagree") || row.AISent.toLowerCase().includes("negative") ) { aiSentiments.negative++; } else { aiSentiments.neutral++; } } // AI Threat Perception if (row.AIThreat) { if ( row.AIThreat.toLowerCase().includes("agree") || row.AIThreat.toLowerCase() === "yes" ) { aiThreats.yes++; } else { aiThreats.no++; } } }); const avgSalary = salaryCount > 0 ? totalSalary / salaryCount : 0; const aiAdoptionRate = (aiUsers / rows.length) * 100; const topCountry = Object.entries(countries).sort((a, b) => b[1] - a[1])[0]; const topLanguage = Array.from(languages).length; const topDevType = Array.from(devTypes).length; return { totalRespondents: rows.length, avgSalary, salaryCount, uniqueCountries: Object.keys(countries).length, uniqueLanguages: topLanguage, uniqueDevTypes: topDevType, aiAdoptionRate, aiUsers, aiSentiments, aiThreats, topCountry: topCountry ? topCountry[0] : "N/A", topCountryCount: topCountry ? topCountry[1] : 0, remoteWorkPercentage: (((remoteWorkTypes["Remote"] || 0) + (remoteWorkTypes["Hybrid"] || 0)) / rows.length) * 100, fullyRemotePercentage: ((remoteWorkTypes["Remote"] || 0) / rows.length) * 100, educationDiversity: Object.keys(educationLevels).length, avgYearsCode: calculateAverageYearsCode(yearsCodeRanges), jobSatisfaction: calculateJobSatisfaction(jobSatLevels), organizationSizes: Object.keys(orgSizes).length, }; }, [rows]); function calculateAverageYearsCode(yearsCodeRanges) { let totalYears = 0; let totalRespondents = 0; Object.entries(yearsCodeRanges).forEach(([range, count]) => { const avgYears = parseCodeRange(range); if (avgYears !== null) { totalYears += avgYears * count; totalRespondents += count; } }); return totalRespondents > 0 ? totalYears / totalRespondents : 0; } function parseCodeRange(range) { if (range.includes("More than 50")) return 55; if (range.includes("30-44")) return 37; if (range.includes("20-29")) return 25; if (range.includes("15-19")) return 17; if (range.includes("10-14")) return 12; if (range.includes("5-9")) return 7; if (range.includes("3-5")) return 4; if (range.includes("1-2")) return 1.5; if (range.includes("Less than 1")) return 0.5; return null; } function calculateJobSatisfaction(jobSatLevels) { const total = Object.values(jobSatLevels).reduce( (sum, count) => sum + count, 0 ); const satisfied = (jobSatLevels["Very satisfied"] || 0) + (jobSatLevels["Slightly satisfied"] || 0); return total > 0 ? (satisfied / total) * 100 : 0; } if (!metrics) return null; const kpiData = [ { icon: "👥", title: "Total Respondents", value: metrics.totalRespondents.toLocaleString(), subtitle: "Developer survey participants", accent: "accent-primary", trend: 15.2, progress: (metrics.totalRespondents / 100000) * 100, }, { icon: "🌍", title: "Global Reach", value: metrics.uniqueCountries, subtitle: `Top: ${metrics.topCountry} (${metrics.topCountryCount})`, accent: "accent-info", trend: 5.3, progress: (metrics.uniqueCountries / 200) * 100, }, { icon: "💻", title: "Languages Used", value: metrics.uniqueLanguages, subtitle: "Programming languages", accent: "accent-secondary", trend: 12.1, progress: (metrics.uniqueLanguages / 50) * 100, }, { icon: "🏢", title: "Developer Types", value: metrics.uniqueDevTypes, subtitle: "Professional roles", accent: "accent-warning", trend: 7.8, progress: (metrics.uniqueDevTypes / 30) * 100, }, { icon: "🏠", title: "Remote Work", value: `${metrics.remoteWorkPercentage.toFixed(1)}%`, subtitle: `${metrics.fullyRemotePercentage.toFixed(1)}% fully remote`, accent: "accent-success", trend: 18.5, progress: metrics.remoteWorkPercentage, }, { icon: "🎓", title: "Education Diversity", value: metrics.educationDiversity, subtitle: "Education levels", accent: "accent-info", trend: 3.2, progress: (metrics.educationDiversity / 10) * 100, }, // { // icon: "📊", // title: "Avg Experience", // value: `${metrics.avgYearsCode.toFixed(1)} yrs`, // subtitle: "Years coding", // accent: "accent-primary", // trend: 2.1, // progress: (metrics.avgYearsCode / 20) * 100, // }, ]; const insights = [ // { // type: "success", // icon: "🚀", // text: `AI adoption is booming with ${metrics.aiAdoptionRate.toFixed( // 1 // )}% of developers using AI tools, showing ${( // (metrics.aiSentiments.positive / (metrics.aiUsers || 1)) * // 100 // ).toFixed(1)}% positive sentiment`, // }, { type: "info", icon: "🌐", text: `Global developer community spans ${metrics.uniqueCountries} countries with ${metrics.uniqueLanguages} programming languages in use`, }, { type: "success", icon: "🏠", text: `Remote work revolution: ${metrics.remoteWorkPercentage.toFixed( 1 )}% work remotely with ${metrics.fullyRemotePercentage.toFixed( 1 )}% fully remote`, }, // { // type: "warning", // icon: "💰", // text: `Average salary of $${metrics.avgSalary.toLocaleString()} across ${ // metrics.salaryCount // } respondents, showing ${metrics.jobSatisfaction.toFixed( // 1 // )}% job satisfaction`, // }, ]; return (
{/* ================= HEADER ================= */}

Stack Overflow Developer Survey Insights

Live developer community analytics and trends
{/*
*/}
{/* ================= FEATURED METRICS ================= */}
{/* */}
{/* ================= KPI GRID ================= */}
{kpiData.map((kpi, index) => ( setSelectedMetric(selectedMetric === index ? null : index) } isActive={selectedMetric === index} /> ))}
{/* ================= DETAILED INSIGHTS ================= */}

🎯 Developer Insights

Key trends and observations from the developer community
{insights.map((insight, index) => (
{insight.icon}
{insight.text}
))}
{/* ================= SUMMARY STATS ================= */}
Community Growth
+15.2%
vs. last year
{/*
AI Adoption
{metrics.aiAdoptionRate.toFixed(1)}%
using AI tools
*/}
Remote Work
{metrics.remoteWorkPercentage.toFixed(1)}%
work remotely
{/*
Job Satisfaction
{metrics.jobSatisfaction.toFixed(1)}%
satisfied developers
*/}
); }