Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"lucide-react": "^0.487.0",
"papaparse": "^5.5.2",
"react": "^19.0.0",
"react-datepicker": "^8.3.0",
"react-dom": "^19.0.0",
"react-infinite-scroll-component": "^6.1.0",
"react-leaflet": "^5.0.0",
Expand Down
112 changes: 69 additions & 43 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { Suspense } from "react";
import React, { Suspense, useState } from "react";
import LayoffTable from "./components/LayoffTable";
import { useLayoffData } from "./hooks/useLayoffData";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { BrowserRouter as Router, Route, Routes, Link } from "react-router-dom";
import About from "./components/About";
import KpiCard from "./components/KpiCard";
import ReactDatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";

import LayoffTop10PieChart from "./components/LayoffTop10PieChart";

Expand All @@ -17,28 +19,34 @@ const LayoffMonthlyTimeSeries = React.lazy(

function App() {
const data = useLayoffData();
const [searchKeyword, setSearchKeyword] = useState("");
const [dateFilter, setDateFilter] = useState("YTD");
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());

if (data.length === 0) {
return <div>Loading...</div>;
}

// Calculate KPIs
const totalLayoffs = data.reduce((sum, item) => sum + item.laidOff, 0);
const totalCompanies = data.length;
const averageLayoffsPerCompany = Math.round(totalLayoffs / totalCompanies);
const largestLayoff = Math.max(...data.map((item) => item.laidOff));
const topIndustry = data.reduce((acc, item) => {
acc[item.industry] = (acc[item.industry] || 0) + item.laidOff;
return acc;
}, {});
const topIndustryName = Object.keys(topIndustry).reduce((a, b) =>
topIndustry[a] > topIndustry[b] ? a : b
);
const retainedEmployees = data.reduce(
(sum, item) => sum + (item.totalEmployees - item.laidOff),
0
const filteredData = data.filter((item) => {
const matchesKeyword = item.company
.toLowerCase()
.includes(searchKeyword.toLowerCase());

const matchesDate = (() => {
const itemDate = new Date(item.date);
return itemDate >= startDate && itemDate <= endDate;
})();

return matchesKeyword && matchesDate;
});

const totalLayoffs = filteredData.reduce((sum, item) => sum + item.laidOff, 0);
const totalCompanies = filteredData.length;
const averageLayoffsPerCompany = Math.round(
totalLayoffs / (totalCompanies || 1)
);
const largestLayoffEvent = data.reduce(
const largestLayoffEvent = filteredData.reduce(
(max, item) => (item.laidOff > max.laidOff ? item : max),
{ company: "", laidOff: 0, date: "" }
);
Expand Down Expand Up @@ -79,52 +87,70 @@ function App() {
</TabsList>
<TabsContent value="layoff">
<div className="p-8 text-center">
{/* Title for KPI Section */}
<h2 className="text-2xl mb-2">US Layoff Data Overview (2020 - Present)</h2>
<p className="text-gray-600 mb-6">Data from 2020 to the present showing the number of layoffs across various companies.</p>

{/* KPI Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<KpiCard title="Total Laid Off" value={totalLayoffs} />
<KpiCard
title="Total Companies with Layoffs"
value={totalCompanies}
<div className="flex justify-center mb-6">
<select
value={dateFilter}
onChange={(e) => setDateFilter(e.target.value)}
className="border border-gray-300 rounded-md px-4 py-2"
>
<option value="YTD">Year to Date (YTD)</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
<option value="All">All Years</option>
</select>
</div>

<div className="flex justify-center mb-6">
<ReactDatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
selectsStart
startDate={startDate}
endDate={endDate}
className="border border-gray-300 rounded-md px-4 py-2"
/>
<KpiCard
title="Average Layoffs per Company"
value={averageLayoffsPerCompany}
<ReactDatePicker
selected={endDate}
onChange={(date) => setEndDate(date)}
selectsEnd
startDate={startDate}
endDate={endDate}
className="border border-gray-300 rounded-md px-4 py-2 ml-4"
/>
</div>

<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<KpiCard title="Total Laid Off" value={totalLayoffs} />
<KpiCard title="Total Companies with Layoffs" value={totalCompanies} />
<KpiCard title="Average Layoffs per Company" value={averageLayoffsPerCompany} />
<KpiCard
title="Largest Layoff Event"
value={largestLayoffEvent.laidOff}
note={`${largestLayoffEvent.company} on ${new Date(largestLayoffEvent.date).toLocaleDateString()}`}
>
</KpiCard>
/>
</div>

<div className="w-5/5 mx-auto">
<LayoffTable />
<LayoffTable data={filteredData} />
</div>

<div className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-8">
<div className="col-span-3">
<Suspense fallback={<div>Loading Time Series...</div>}>
<LayoffMonthlyTimeSeries rawData={data} />
</Suspense>
</div>

<div className="col-span-3 mt-8">
<Suspense fallback={<div>Loading Bar Chart...</div>}>
{/* <LayoffTop10Chart data={data} /> */}
<LayoffTop10PieChart data={data} />
</Suspense>
<Suspense fallback={<div>Loading Bar Chart...</div>}>
<LayoffTop10PieChart data={filteredData} />
</Suspense>
</div>
<div className="col-span-3">
<Suspense fallback={<div>Loading Time Series...</div>}>
<LayoffMonthlyTimeSeries rawData={filteredData} />
</Suspense>
</div>
</div>
</div>
</TabsContent>
<TabsContent value="password">
Change your password here.
</TabsContent>
</Tabs>
}
/>
Expand Down