Spaces:
Running
Running
| import React, { Suspense, lazy, useState } from "react"; | |
| import ErrorBoundary from "./components/boundaries/ErrorBoundary"; | |
| import "./App.css"; | |
| import LoadingState from "./components/common/LoadingState"; | |
| import StatusBanner from "./components/common/StatusBanner"; | |
| import AppHeader from "./components/layout/AppHeader"; | |
| import DatasetMetaPanel from "./components/layout/DatasetMetaPanel"; | |
| import KpiOverview from "./components/overview/KpiOverview"; | |
| import StackOverflowKpiOverview from "./components/overview/StackOverflowKpiOverview"; | |
| import { useMarketplaceDataset } from "./hooks/useMarketplaceDataset"; | |
| import { useProductHuntDataset } from "./hooks/useProductHuntDataset"; | |
| import { DATASET_PATH } from "./config/appConfig"; | |
| /* ================= CHART IMPORTS ================= */ | |
| // Demographics | |
| const DevelopersByCountryBar = lazy(() => | |
| import("./charts/DevelopersByCountryBar") | |
| ); | |
| const AgeDistributionHistogram = lazy(() => | |
| import("./charts/AgeDistributionHistogram") | |
| ); | |
| const GenderDistributionDonut = lazy(() => | |
| import("./charts/GenderDistributionDonut") | |
| ); | |
| // Experience & Career | |
| const CodingExperienceHistogram = lazy(() => | |
| import("./charts/CodingExperienceHistogram") | |
| ); | |
| const DeveloperRolesChart = lazy(() => import("./charts/DeveloperRolesChart")); | |
| const SalaryByRoleChart = lazy(() => import("./charts/SalaryByRoleChart")); | |
| const RemoteWorkVsSalaryBoxPlot = lazy(() => | |
| import("./charts/RemoteWorkVsSalaryBoxPlot") | |
| ); | |
| // Education & Work Style | |
| const EducationLevelBarChart = lazy(() => | |
| import("./charts/EducationLevelBarChart") | |
| ); | |
| const RemoteWorkPreferencePieChart = lazy(() => | |
| import("./charts/RemoteWorkPreferencePieChart") | |
| ); | |
| const OrgSizeVsRemoteWorkChart = lazy(() => | |
| import("./charts/OrgSizeVsRemoteWorkChart") | |
| ); | |
| // Technology Usage | |
| const MostUsedLanguagesChart = lazy(() => | |
| import("./charts/MostUsedLanguagesChart") | |
| ); | |
| const LanguagesUsedVsAdmiredChart = lazy(() => | |
| import("./charts/LanguagesUsedVsAdmiredChart") | |
| ); | |
| const MostUsedDatabasesChart = lazy(() => | |
| import("./charts/MostUsedDatabasesChart") | |
| ); | |
| const DatabasesHaveVsWantChart = lazy(() => | |
| import("./charts/DatabasesHaveVsWantChart") | |
| ); | |
| const PlatformsDevelopersWorkWithChart = lazy(() => | |
| import("./charts/PlatformsDevelopersWorkWithChart") | |
| ); | |
| const PlatformsHaveVsWantChart = lazy(() => | |
| import("./charts/PlatformsHaveVsWantChart") | |
| ); | |
| // AI & Community | |
| const ExperienceVsAIUsageChart = lazy(() => | |
| import("./charts/ExperienceVsAIUsageChart") | |
| ); | |
| const StackOverflowChart = lazy(() => import("./charts/StackOverflowChart")); | |
| export default function App() { | |
| const [showFields, setShowFields] = useState(false); | |
| const { metadata, status, error, hasData, refresh } = | |
| useMarketplaceDataset(DATASET_PATH); | |
| const productHuntData = useProductHuntDataset(DATASET_PATH); | |
| const initialLoading = status === "loading" && !hasData; | |
| const initialError = status === "error" && !hasData; | |
| return ( | |
| <div className="app-container"> | |
| {/* ================= HEADER ================= */} | |
| <AppHeader | |
| metadata={metadata} | |
| showColumns={showFields} | |
| onToggleColumns={() => setShowFields((p) => !p)} | |
| isLoadingMetadata={status === "loading"} | |
| onRefresh={refresh} | |
| isRefreshing={status === "loading"} | |
| /> | |
| {/* ================= DATASET META ================= */} | |
| <DatasetMetaPanel metadata={metadata} visible={showFields} /> | |
| {/* ================= WARNING ================= */} | |
| {error && hasData && ( | |
| <StatusBanner | |
| variant="warning" | |
| title="Showing cached data" | |
| message="Latest refresh failed. Using last successful dataset." | |
| actionLabel="Retry" | |
| onAction={refresh} | |
| /> | |
| )} | |
| {/* ================= INITIAL LOADING / ERROR ================= */} | |
| {initialLoading && ( | |
| <LoadingState | |
| label="Loading dataset" | |
| description="Fetching Stack Overflow survey data…" | |
| /> | |
| )} | |
| {initialError && ( | |
| <StatusBanner | |
| variant="error" | |
| title="Dataset load failed" | |
| message={error ? String(error) : "Unknown error"} | |
| actionLabel="Retry" | |
| onAction={refresh} | |
| /> | |
| )} | |
| {/* ================= CONTENT ================= */} | |
| <ErrorBoundary> | |
| {/* ================= STACK OVERFLOW KPI OVERVIEW ================= */} | |
| <div className="row card"> | |
| <Suspense | |
| fallback={<LoadingState label="Loading Stack Overflow KPI…" />} | |
| > | |
| <StackOverflowKpiOverview rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| {/* <h2 className="section-heading">Developer Demographics</h2> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <DevelopersByCountryBar rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <AgeDistributionHistogram rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <h2 className="section-heading">Experience & Career Insights</h2> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <CodingExperienceHistogram rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <DeveloperRolesChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <SalaryByRoleChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <RemoteWorkVsSalaryBoxPlot rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <h2 className="section-heading">Education & Work Style</h2> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <EducationLevelBarChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <RemoteWorkPreferencePieChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <OrgSizeVsRemoteWorkChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <h2 className="section-heading">Technology Trends</h2> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <MostUsedLanguagesChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <LanguagesUsedVsAdmiredChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <MostUsedDatabasesChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <DatabasesHaveVsWantChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <PlatformsDevelopersWorkWithChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <PlatformsHaveVsWantChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <h2 className="section-heading">AI & Community Usage</h2> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <ExperienceVsAIUsageChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> | |
| <div className="row card"> | |
| <Suspense fallback={<LoadingState label="Loading chart…" />}> | |
| <StackOverflowChart rows={productHuntData.rows} /> | |
| </Suspense> | |
| </div> */} | |
| </ErrorBoundary> | |
| </div> | |
| ); | |
| } | |