From 3283b11947477371d15b87fadd97d666703a1e4a Mon Sep 17 00:00:00 2001 From: Karl Kwon Date: Sat, 12 Apr 2025 14:53:44 -0400 Subject: [PATCH] WIP - date picker --- package-lock.json | 85 +++++++++++++++++++++++++++++++++++ package.json | 1 + src/App.tsx | 112 ++++++++++++++++++++++++++++------------------ 3 files changed, 155 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 28727a2..07b736c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,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", @@ -1071,6 +1072,59 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.7.tgz", + "integrity": "sha512-5V9pwFeiv+95Jlowq/7oiGISSrdXMTs2jfoSy8k+WM6oI/Skm1WWjPdJWeporN2O4UGcsaCJdirKffKayMoPgw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.9", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -3387,6 +3441,16 @@ "node": ">= 12" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -6437,6 +6501,21 @@ "node": ">=0.10.0" } }, + "node_modules/react-datepicker": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-8.3.0.tgz", + "integrity": "sha512-DhfrIJnTPJTUVRtXU7c7zooug40rD6q+Fc8UTCt19dYEotLpDQgTN98MfocY6Rc4S99oOFFEoxyanOM/TKauuw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.3", + "clsx": "^2.1.1", + "date-fns": "^4.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/react-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -7240,6 +7319,12 @@ "node": ">=8" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.2.0.tgz", diff --git a/package.json b/package.json index 362ec4e..1ae162c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/App.tsx b/src/App.tsx index 145e0d1..706d05e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -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"; @@ -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
Loading...
; } - // 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: "" } ); @@ -79,52 +87,70 @@ function App() {
- {/* Title for KPI Section */}

US Layoff Data Overview (2020 - Present)

Data from 2020 to the present showing the number of layoffs across various companies.

- {/* KPI Cards */} -
- - + +
+ +
+ setStartDate(date)} + selectsStart + startDate={startDate} + endDate={endDate} + className="border border-gray-300 rounded-md px-4 py-2" /> - setEndDate(date)} + selectsEnd + startDate={startDate} + endDate={endDate} + className="border border-gray-300 rounded-md px-4 py-2 ml-4" /> +
+ +
+ + + - + />
- +
-
- Loading Time Series...
}> - - -
-
- Loading Bar Chart...
}> - {/* */} - - + Loading Bar Chart...
}> + + + +
+ Loading Time Series...
}> + +
- - Change your password here. - } />