diff --git a/src/components/KitchenandInventory/KIInventory/KIInventory.jsx b/src/components/KitchenandInventory/KIInventory/KIInventory.jsx
new file mode 100644
index 0000000000..395586d968
--- /dev/null
+++ b/src/components/KitchenandInventory/KIInventory/KIInventory.jsx
@@ -0,0 +1,274 @@
+import { useState, useEffect } from 'react';
+import { useSelector } from 'react-redux';
+import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
+import styles from './KIInventory.module.css';
+import MetricCard from '../MetricCards/MetricCard';
+import classnames from 'classnames';
+// Icons
+import { TbToolsKitchen2 } from 'react-icons/tb';
+import { LiaSeedlingSolid } from 'react-icons/lia';
+import { GiMasonJar } from 'react-icons/gi';
+import { PiBarcode } from 'react-icons/pi';
+import {
+ FiSearch,
+ FiPackage,
+ FiAlertCircle,
+ FiAlertTriangle,
+ FiShoppingCart,
+ FiArchive,
+} from 'react-icons/fi';
+import { RiLeafLine } from 'react-icons/ri';
+import KIItemCard from './KIItemCard';
+import {
+ ingredients,
+ preservedItems,
+ lowStock,
+ totalItems,
+ criticalStock,
+ onsiteGrown,
+ equipmentAndSupplies,
+ seeds,
+ canningSupplies,
+ animalSupplies,
+} from './KIInventorySampleItems.js';
+
+const KIInventory = () => {
+ const darkMode = useSelector(state => state.theme.darkMode);
+ const tabs = [
+ 'ingredients',
+ 'equipment & supplies',
+ 'seeds',
+ 'canning supplies',
+ 'animal supplies',
+ ];
+ const [activeTab, setActiveTab] = useState(tabs[0]);
+ const [searchTerm, setSearchTerm] = useState('');
+ const toggleTab = tab => {
+ if (activeTab !== tabs[tab]) setActiveTab(tabs[tab]);
+ };
+ useEffect(() => {
+ // This is where you would fetch real data from an API or database
+ // For this example, we're using static sample data from KIInventorySampleItems.js
+ }, []);
+ let preservedDesc = [];
+ if (preservedItems.length > 0) {
+ preservedDesc = preservedItems.map(
+ item => `${item.presentQuantity} ${item.unit} of ${item.name}`,
+ );
+ }
+ return (
+
+
+
+
Inventory Management
+
Track ingredients, equipment, and supplies across all kitchen operations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setSearchTerm(e.target.value);
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+ {preservedItems.length > 0 && (
+
+
+
+
+ Preserved Stock Available
+
+
+ Extended shelf life items for year-round use
+
+
+
+
{preservedDesc.join(', ')}
+
+
+
+
+
+ )}
+
+ {ingredients.map(item => (
+
+
+
+ ))}
+
+
+
+
+
+
+ {equipmentAndSupplies.map(item => (
+
+
+
+ ))}
+
+
+
+
+
+
+ {seeds.map(item => (
+
+
+
+ ))}
+
+
+
+
+
+
+ {canningSupplies.map(item => (
+
+
+
+ ))}
+
+
+
+
+
+
+ {animalSupplies.map(item => (
+
+
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default KIInventory;
diff --git a/src/components/KitchenandInventory/KIInventory/KIInventory.module.css b/src/components/KitchenandInventory/KIInventory/KIInventory.module.css
new file mode 100644
index 0000000000..4ccd36f568
--- /dev/null
+++ b/src/components/KitchenandInventory/KIInventory/KIInventory.module.css
@@ -0,0 +1,269 @@
+.inventoryContainer {
+ display: flex;
+ flex-direction: column;
+ background-color: #ffffff;
+ padding: 20px 20px;
+ margin:0;
+ line-height: 1.6;
+ letter-spacing: 0.2px;
+ width: 100%;
+}
+.inventoryText {
+ color: black;
+}
+.inventoryPageHeader {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: space-between;
+ margin: 0px 0px 10px 0px;
+ width: 100%;
+ padding: 10px 10px;
+ border-radius: 8px;
+ background-color: rgb(249, 245, 245);
+}
+.inventoryMetricCards {
+ width: 100%;
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ gap: 15px;
+ border-radius: 16px;
+ margin-right: 40px;
+}
+.inventoryNavBar {
+ margin-top: 30px;
+ width: auto;
+ border: 1px solid #e0e0e0;
+ border-radius: 30px;
+ background-color: #e7eef6;
+}
+.inventoryNavBarLink {
+ padding-bottom: 8px;
+ font-weight: 500;
+ color: #404040;
+ cursor: pointer;
+}
+.inventoryNavBarLink:hover {
+ background-color: #d2d5d5;
+ border-radius: 30px;
+ color: black;
+}
+.inventoryNavBarIcon {
+ font-size: 1.2rem;
+ margin-right: 8px;
+ vertical-align: middle;
+}
+.inventoryInteraction {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+.inventorySearchBar {
+ display: flex;
+ width: auto;
+ align-items: center;
+ border: 1px solid #ccc;
+ border-radius: 10px;
+ padding: 0px 8px;
+ background-color: #f2f4f7;
+}
+.otherIcons {
+ margin-bottom: 3px;
+ margin-right: 3px;
+}
+.searchBarInput{
+ width: 300px;
+ border: none;
+ outline: none;
+ padding: 4px;
+ font-size: 16px;
+ border-radius: 8px;
+ background-color: #f2f4f7;
+}
+.button {
+ margin: 0px 20px;
+ padding: 4px 12px;
+ border-radius: 10px;
+ box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.3);
+ color: white;
+}
+.button:hover {
+ opacity: 0.7;
+}
+.button:active {
+ transition: 0.2s all;
+ box-shadow: inset 0 1px #666;
+}
+.clearSearch {
+ border: none;
+ color: rgb(82, 82, 90);
+ font-weight: bold;
+ font-size: 12px;
+ border-radius: 100%;
+ padding: 0px 4px;
+ cursor: pointer;
+}
+.clearSearch:hover {
+ background-color: rgb(230, 225, 225);
+}
+.addItemButton {
+ background-color: rgb(3, 128, 3);
+}
+.scanBarcodeButton {
+ background-color: rgb(0, 120, 215);
+}
+.inventoryTabContent {
+ background-color: #ffffff;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);
+}
+.darkContainer {
+ background-color: #1b2a41;
+}
+.darkHeader {
+ background-color: #14253b;
+}
+.darkNavBar {
+ background-color: #3A506B;
+ border: none;
+}
+.darkSearchBar {
+ background-color: #1e293b;
+ border: none;
+}
+.darkSearchInput {
+ background-color: #151515 !important;
+ border: none !important;
+}
+.darkTabContent {
+ background-color: #2c3e50;
+ color: white;
+ border: none;
+}
+/* Ingredient tab styles */
+.tabContainer {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+.notificationContainer {
+ margin: 10px;
+ background-color: rgb(248, 239, 211);
+ border: 1px solid rgb(245, 162, 61);
+ border-radius: 8px;
+ padding: 10px;
+}
+.ingredientsContainer {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 10px;
+ padding: 10px;
+ justify-items: center;
+}
+.notificationHeader {
+ display: flex;
+ flex-direction: column;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+.notificationHeader p {
+ color: rgb(245, 162, 61);
+}
+.notificationBody {
+ display: flex;
+ gap: 5px;
+ justify-content: space-between;
+}
+.viewAllButton {
+ padding: 3px 6px;
+ align-self: flex-end;
+ background-color: rgb(243, 241, 236);
+ color: rgb(245, 162, 61);
+ font-weight: bold;
+ cursor: pointer;
+ border-radius: 6px;
+ border: 1px solid rgb(245, 162, 61);
+}
+.viewAllButton:active {
+ box-shadow: inset 0 1px 2px #666;
+}
+.darkModeNotification {
+ background-color: transparent;
+ border: 3px solid rgb(245, 162, 61);
+}
+@media screen and (max-width: 480px){
+ .inventoryContainer {
+ padding: 5px 5px;
+ }
+ .inventoryPageHeader {
+ font-size: 0.8rem;
+ padding: 2px;
+ margin-top: 0px;
+ }
+ .inventoryMetricCards {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 5px;
+ justify-content: center;
+ align-items: center;
+ margin-right: 0px;
+ }
+ .inventoryNavBar {
+ width: 100%;
+ margin-top: 10px;
+ }
+ .inventoryNavBarLink {
+ padding: 0px 0px;
+ }
+ .inventoryInteraction {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ margin: 10px 0px;
+ }
+ .inventorySearchBar {
+ font-size: 0.8rem;
+ max-height: 30px;
+ width: 100%;
+ }
+ .inventorySearchBar input {
+ font-size: 0.8rem;
+ height: 28px;
+ width: 100%;
+ }
+ .button {
+ margin: 0px 2px;
+ padding: 3px 4px;
+ font-size: 0.8rem;
+ }
+}
+@media screen and (max-width: 768px){
+ .inventoryContainer {
+ padding: 5px 5px;
+ }
+ .inventoryMetricCards {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 5px;
+ justify-content: center;
+ align-items: center;
+ margin-right: 0px;
+ }
+ .inventoryInteraction {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ margin: 10px 0px;
+ }
+ .button {
+ margin: 0px 4px;
+ }
+ .notificationBody {
+ flex-direction: column;
+ }
+}
\ No newline at end of file
diff --git a/src/components/KitchenandInventory/KIInventory/KIInventorySampleItems.js b/src/components/KitchenandInventory/KIInventory/KIInventorySampleItems.js
new file mode 100644
index 0000000000..79667c0453
--- /dev/null
+++ b/src/components/KitchenandInventory/KIInventory/KIInventorySampleItems.js
@@ -0,0 +1,353 @@
+const ingredients = [
+ {
+ _id: '6971bd95b82f6dd968770bb7',
+ onsite: true,
+ name: 'Dummy Canned Tomatos',
+ storedQuantity: 105,
+ presentQuantity: 85,
+ unit: 'jars',
+ type: 'Preserved Foods',
+ monthlyUsage: 25,
+ category: 'INGREDIENT',
+ expiryDate: '2027-01-25T06:00:00.000Z',
+ reorderAt: 20,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Pantry Shelf 2',
+ },
+ {
+ _id: '6971b51fbf34b40da4b3b088',
+ onsite: true,
+ name: 'Dummy Carrots',
+ storedQuantity: 25,
+ presentQuantity: 5,
+ unit: 'lbs',
+ type: 'Vegetables',
+ monthlyUsage: 10,
+ category: 'INGREDIENT',
+ expiryDate: '2026-01-24T06:00:00.000Z',
+ reorderAt: 10,
+ lastHarvestDate: '2025-12-31T06:00:00.000Z',
+ nextHarvestDate: '2026-03-31T06:00:00.000Z',
+ createdAt: '2026-01-22T05:26:55.421Z',
+ updatedAt: '2026-01-22T05:26:55.421Z',
+ nextHarvestQuantity: 30,
+ location: 'Garden Bed 2',
+ },
+ {
+ _id: '6971b1997d9134e35c5468e6',
+ onsite: true,
+ name: 'Dummy Tomatos',
+ storedQuantity: 60,
+ presentQuantity: 25,
+ unit: 'lbs',
+ type: 'Vegetables',
+ monthlyUsage: 25,
+ category: 'INGREDIENT',
+ expiryDate: '2026-02-13T06:00:00.000Z',
+ reorderAt: 30,
+ createdAt: '2026-01-22T05:11:53.811Z',
+ updatedAt: '2026-01-24T22:33:57.652Z',
+ nextHarvestDate: '2026-04-14T06:00:00.000Z',
+ nextHarvestQuantity: 30,
+ location: 'Garden Bed 1',
+ },
+ {
+ _id: '6971bd95b82f6dd968770bb7',
+ onsite: false,
+ name: 'Dummy Pickles',
+ storedQuantity: 95,
+ presentQuantity: 65,
+ unit: 'jars',
+ type: 'Preserved Foods',
+ monthlyUsage: 25,
+ category: 'INGREDIENT',
+ expiryDate: '2027-03-03T06:00:00.000Z',
+ reorderAt: 20,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Pantry Shelf 2',
+ },
+];
+const preservedItems = [
+ {
+ _id: '6971bd95b82f6dd968770bb7',
+ onsite: true,
+ name: 'Dummy Canned Tomatos',
+ storedQuantity: 105,
+ presentQuantity: 85,
+ unit: 'jars',
+ type: 'Preserved Foods',
+ monthlyUsage: 25,
+ category: 'INGREDIENT',
+ expiryDate: '2027-01-25T06:00:00.000Z',
+ reorderAt: 20,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ },
+ {
+ _id: '6971bd95b82f6dd968770bb7',
+ onsite: false,
+ name: 'Dummy Pickles',
+ storedQuantity: 95,
+ presentQuantity: 65,
+ unit: 'jars',
+ type: 'Preserved Foods',
+ monthlyUsage: 25,
+ category: 'INGREDIENT',
+ expiryDate: '2027-03-03T06:00:00.000Z',
+ reorderAt: 20,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Pantry Shelf 2',
+ },
+];
+const equipmentAndSupplies = [
+ {
+ _id: 'equipandsupplies1',
+ onsite: false,
+ name: 'Dummy Dinner Plates',
+ storedQuantity: 90,
+ presentQuantity: 48,
+ unit: 'pieces',
+ type: 'Dinnerware',
+ category: 'EQUIPEMENTANDSUPPLIES',
+ reorderAt: 20,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Dish Storage',
+ },
+ {
+ _id: 'equipandsupplies2',
+ onsite: false,
+ name: 'Dummy Drinking Glasses',
+ storedQuantity: 90,
+ presentQuantity: 52,
+ unit: 'pieces',
+ type: 'Glassware',
+ category: 'EQUIPEMENTANDSUPPLIES',
+ reorderAt: 45,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Dish Storage',
+ },
+ {
+ _id: 'equipandsupplies3',
+ onsite: false,
+ name: 'Dummy Forks',
+ storedQuantity: 84,
+ presentQuantity: 38,
+ unit: 'pieces',
+ type: 'Utensils',
+ category: 'EQUIPEMENTANDSUPPLIES',
+ reorderAt: 40,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Utensil Drawer',
+ },
+ {
+ _id: 'equipandsupplies4',
+ onsite: false,
+ name: 'Dummy Large Mixing Bowls',
+ storedQuantity: 15,
+ presentQuantity: 12,
+ unit: 'pieces',
+ type: 'Cookware',
+ category: 'EQUIPEMENTANDSUPPLIES',
+ reorderAt: 8,
+ createdAt: '2026-01-22T06:03:01.655Z',
+ updatedAt: '2026-01-24T21:57:10.164Z',
+ location: 'Kitchen Storage',
+ },
+];
+const seeds = [
+ {
+ _id: 'seeds1',
+ onsite: false,
+ name: 'Dummy Tomato Seeds',
+ storedQuantity: 200,
+ presentQuantity: 200,
+ unit: 'seeds',
+ type: 'Seeds',
+ monthlyUsage: 50,
+ category: 'SEEDS',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 100,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Seed Storage Room',
+ },
+ {
+ _id: 'seeds2',
+ onsite: false,
+ name: 'Dummy Lettuce Seeds',
+ storedQuantity: 200,
+ presentQuantity: 150,
+ unit: 'seeds',
+ type: 'Seeds',
+ monthlyUsage: 40,
+ category: 'SEEDS',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 100,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Seed Storage Room',
+ },
+ {
+ _id: 'seeds3',
+ onsite: false,
+ name: 'Dummy carrot Seeds',
+ storedQuantity: 180,
+ presentQuantity: 80,
+ unit: 'seeds',
+ type: 'Seeds',
+ monthlyUsage: 30,
+ category: 'SEEDS',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 100,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Seed Storage Room',
+ },
+ {
+ _id: 'seeds4',
+ onsite: false,
+ name: 'Dummy Strawberry Seeds',
+ storedQuantity: 100,
+ presentQuantity: 45,
+ unit: 'seeds',
+ type: 'Seeds',
+ monthlyUsage: 20,
+ category: 'SEEDS',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 50,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Seed Storage Room',
+ },
+];
+const canningSupplies = [
+ {
+ _id: 'canningsupplies1',
+ onsite: false,
+ name: 'Dummy Mason Jars',
+ storedQuantity: 120,
+ presentQuantity: 120,
+ unit: 'jars',
+ type: 'Canning',
+ monthlyUsage: 40,
+ category: 'CANNINGSUPPLIES',
+ reorderAt: 50,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Canning Supply Storage',
+ },
+ {
+ _id: 'canningsupplies2',
+ onsite: false,
+ name: 'Dummy Canning Lids',
+ storedQuantity: 180,
+ presentQuantity: 85,
+ unit: 'pieces',
+ type: 'Canning',
+ monthlyUsage: 50,
+ category: 'CANNINGSUPPLIES',
+ reorderAt: 100,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Canning Supply Storage',
+ },
+ {
+ _id: 'canningsupplies3',
+ onsite: false,
+ name: 'Dummy Vacuum Sealer Bags(Gallon)',
+ storedQuantity: 200,
+ presentQuantity: 200,
+ unit: 'bags',
+ type: 'Storage',
+ monthlyUsage: 60,
+ category: 'CANNINGSUPPLIES',
+ reorderAt: 100,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Storage supplies',
+ },
+];
+const animalSupplies = [
+ {
+ _id: 'animalsupplies1',
+ onsite: false,
+ name: 'Dummy Chicken Feed',
+ storedQuantity: 400,
+ presentQuantity: 250,
+ unit: 'lbs',
+ type: 'Animal Feed',
+ monthlyUsage: 180,
+ category: 'ANIMALSUPPLIES',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 200,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Animal Feed Storage',
+ },
+ {
+ _id: 'animalsupplies2',
+ onsite: false,
+ name: 'Dummy Cattle Feed',
+ storedQuantity: 1000,
+ presentQuantity: 800,
+ unit: 'lbs',
+ type: 'Animal Feed',
+ monthlyUsage: 600,
+ category: 'ANIMALSUPPLIES',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 500,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Animal Feed Storage',
+ },
+ {
+ _id: 'animalsupplies3',
+ onsite: false,
+ name: 'Dummy Mineral Supplements',
+ storedQuantity: 45,
+ presentQuantity: 15,
+ unit: 'lbs',
+ type: 'Animal Supplements',
+ monthlyUsage: 12,
+ category: 'ANIMALSUPPLIES',
+ expiryDate: '2026-12-30T06:00:00.000Z',
+ reorderAt: 20,
+ createdAt: '2026-01-24T22:39:35.498Z',
+ updatedAt: '2026-01-24T22:39:35.498Z',
+ location: 'Veterinary Supplies Storage',
+ },
+];
+
+const combinedInventory = [
+ ...ingredients,
+ ...equipmentAndSupplies,
+ ...seeds,
+ ...canningSupplies,
+ ...animalSupplies,
+];
+const totalItems = combinedInventory.length;
+const lowStock = combinedInventory.filter(
+ item => item.presentQuantity <= item.reorderAt && item.presentQuantity >= item.reorderAt * 0.75,
+).length;
+const criticalStock = combinedInventory.filter(item => item.presentQuantity < item.reorderAt * 0.75)
+ .length;
+const onsiteGrown = combinedInventory.filter(item => item.onsite).length;
+
+export {
+ ingredients,
+ preservedItems,
+ totalItems,
+ lowStock,
+ criticalStock,
+ onsiteGrown,
+ equipmentAndSupplies,
+ seeds,
+ canningSupplies,
+ animalSupplies,
+};
diff --git a/src/components/KitchenandInventory/KIInventory/KIItemCard.jsx b/src/components/KitchenandInventory/KIInventory/KIItemCard.jsx
new file mode 100644
index 0000000000..ec4f4e09ce
--- /dev/null
+++ b/src/components/KitchenandInventory/KIInventory/KIItemCard.jsx
@@ -0,0 +1,192 @@
+import { RiLeafLine } from 'react-icons/ri';
+import { TbCircleCheck } from 'react-icons/tb';
+import { FiAlertCircle, FiAlertTriangle, FiCalendar, FiShoppingCart } from 'react-icons/fi';
+import { useSelector } from 'react-redux';
+import styles from './KIItemCard.module.css';
+
+function KIItemCard(props) {
+ const item = props.item;
+ const healthyStock = item.presentQuantity > item.reorderAt;
+ const lowStock =
+ item.presentQuantity <= item.reorderAt && item.presentQuantity >= item.reorderAt * 0.75;
+ const supplyRatio = item.presentQuantity / item.monthlyUsage;
+ const healthySupply = supplyRatio >= 1;
+ const lowSupply = supplyRatio < 1 && supplyRatio >= 0.6;
+ const darkMode = useSelector(state => state.theme.darkMode);
+ return (
+
+ {/* Card Header */}
+
+
+
+ {item.name}
+
+ {' '}
+ {item.onsite && (
+
+ )}
+
+
+
{item.type}
+
+
+ {healthyStock ? (
+
+ ) : lowStock ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Card Body */}
+
+ {/* Stock Quantity Bars */}
+
+
+
+
Current Stock
+
+ {item.presentQuantity} {item.unit}
+
+
+
+
+ Reorder at {item.reorderAt} {item.unit}
+
+
+ {item.monthlyUsage && (
+
+
+
Monthly Supply
+
+ {Math.round((item.presentQuantity / item.monthlyUsage) * 10) / 10} months
+
+
+
+
+ {`Target: 1 month minimum (${item.monthlyUsage} ${item.unit}/month)`}
+
+
+ )}
+
+
+
+
Location
+
{item.location}
+
+
+
Source
+
+ {item.onsite ? (
+ Onsite
+ ) : (
+
+ Purchased
+
+ )}
+
+
+
+
+ {item.expiryDate && (
+
+
+
+ Expires: {new Date(item.expiryDate).toLocaleDateString()}
+
+
+ )}
+ {item.lastHarvestDate && (
+
+
+
+ Last harvest: {new Date(item.lastHarvestDate).toLocaleDateString()}
+
+
+ )}
+ {item.nextHarvestDate && (
+
+
+
+ Next harvest:{' '}
+ {`${item.nextHarvestQuantity} ${item.unit} on ${new Date(
+ item.nextHarvestDate,
+ ).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`}
+
+
+ )}
+
+
+
+
+
+
+
+ );
+}
+
+export default KIItemCard;
diff --git a/src/components/KitchenandInventory/KIInventory/KIItemCard.module.css b/src/components/KitchenandInventory/KIInventory/KIItemCard.module.css
new file mode 100644
index 0000000000..dda1c4998b
--- /dev/null
+++ b/src/components/KitchenandInventory/KIInventory/KIItemCard.module.css
@@ -0,0 +1,109 @@
+.cardContainer {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ padding: 15px;
+ margin: 10px 0;
+ background-color: #fff;
+ width: 300px;
+ height: auto;
+ box-shadow: -4px 2px 4px #e3e2e2;
+}
+.cardHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid #b7b6b6;
+ padding-bottom: 10px;
+}
+.smallerText {
+ opacity: 0.8;
+ font-size: smaller;
+ padding: 0;
+ margin: 0px;
+}
+.stockandSupplyContainer {
+ display: flex;
+ flex-direction: column;
+ border-bottom: 1px solid #b7b6b6;
+}
+.quantityDetails {
+ margin-bottom: 10px;
+}
+.currentStockDetails {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 5px 0px 5px 0px;
+}
+.statusBar {
+ height: 6px;
+ border-radius: 10px;
+ margin-top: 5px;
+ background-color: #e8ebe8;
+}
+.stockBarProgress {
+ height: 100%;
+ background-color: var(--status-color);
+ border-radius: 10px;
+}
+.supplyBarProgress {
+ height: 100%;
+ background-color: var(--status-color);
+ border-radius: 10px;
+}
+.locationSourceContainer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 5px;
+}
+.sourceType {
+ padding: 4px;
+ background-color: black;
+ color: white;
+ border-radius: 6px;
+ font-size: 0.8rem;
+ font-weight: bold;
+}
+.datesContainer {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 10px;
+}
+.dates {
+ display: flex;
+ gap: 5px;
+ border-radius: 4px;
+ padding: 2px 4px;
+ align-items: center;
+}
+.dates p {
+ color: inherit;
+}
+.cardButtonContainer {
+ display: flex;
+ justify-content: space-around;
+ gap: 10px;
+ margin-top: 10px;
+}
+.cardButton {
+ padding: 2px 8px;
+ border: none;
+ border-radius: 4px;
+ font-size: smaller;
+ background-color: #d0d2d3;
+ color: black;
+ cursor: pointer;
+ box-shadow: 0 1px #999;
+}
+.cardButton:active {
+ box-shadow: inset 0 1px 2px #666;
+}
+.darkCardContainer {
+ background-color: #225163;
+ border: 1px solid #444;
+ box-shadow: -4px 2px 4px #252424;
+}
\ No newline at end of file
diff --git a/src/components/KitchenandInventory/MetricCards/MetricCard.jsx b/src/components/KitchenandInventory/MetricCards/MetricCard.jsx
new file mode 100644
index 0000000000..34fe792ede
--- /dev/null
+++ b/src/components/KitchenandInventory/MetricCards/MetricCard.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import styles from './MetricCard.module.css';
+import { useSelector } from 'react-redux';
+
+function MetricCard(props) {
+ const darkMode = useSelector(state => state.theme.darkMode);
+ const { metricname, metricvalue, iconcolor, children: Icon } = props;
+ return (
+
+
{metricname}
+
+
{metricvalue}
+
+ {Icon}
+
+
+
+ );
+}
+
+export default MetricCard;
diff --git a/src/components/KitchenandInventory/MetricCards/MetricCard.module.css b/src/components/KitchenandInventory/MetricCards/MetricCard.module.css
new file mode 100644
index 0000000000..435fe82301
--- /dev/null
+++ b/src/components/KitchenandInventory/MetricCards/MetricCard.module.css
@@ -0,0 +1,75 @@
+.metricCard {
+ width: 100%;
+ border-radius: 8px;
+ box-shadow: 4px 0px 10px rgba(54, 54, 54, 0.1), -4px 0px 10px rgba(0, 0, 0, 0.1);
+ padding: 16px;
+ background-color: rgb(251, 252, 254);
+}
+.metricCardHeader {
+ font-size: 1rem;
+ font-weight: bold;
+ margin-bottom: 12px;
+ margin-left: 10px;
+}
+.metricCardBody {
+ margin-left: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 2rem;
+}
+.metricCardIcon {
+ margin: 0;
+ font-size: 2rem;
+ font-weight: bold;
+ margin-bottom: 20px;
+ margin-right: 20px;
+ color: var(--icon-color)
+}
+.darkModeCard {
+ background-color: #032c50;
+ box-shadow: 4px 0px 10px rgba(0, 0, 0, 0.2), -4px 0px 10px rgba(0, 0, 0, 0.2);
+}
+.darkModeIcon svg{
+ fill: var(--icon-color);
+}
+
+@media screen and (max-width:480px) {
+ .metricCard {
+ max-height: 90px;
+ padding: 4px;
+ }
+ .metricCardBody {
+ font-size: 1.5rem;
+ justify-content: space-between;
+ }
+ .metricCardIcon{
+ font-size: 1.2rem;
+ }
+}
+@media screen and (max-width: 735px){
+ .metricCard {
+ max-height: 90px;
+ padding: 4px;
+ }
+ .metricCardBody {
+ font-size: 1.5rem;
+ justify-content: space-between;
+ }
+ .metricCardIcon{
+ font-size: 1.2rem;
+ }
+}
+@media screen and (max-width: 1024px) and (min-width: 736px){
+ .metricCard {
+ max-height: 100px;
+ padding: 8px;
+ }
+ .metricCardBody {
+ font-size: 1.8rem;
+ justify-content: space-between;
+ }
+ .metricCardIcon{
+ font-size: 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/src/routes.jsx b/src/routes.jsx
index 74ad1caa97..2dbea3b98f 100644
--- a/src/routes.jsx
+++ b/src/routes.jsx
@@ -157,6 +157,8 @@ import CommunityCalendar from './components/CommunityPortal/Calendar/CommunityCa
import KitchenandInventoryLogin from './components/KitchenandInventory/Login';
import KIProtectedRoute from './components/common/KitchenandInventory/KIProtectedRoute';
import KIDashboard from './components/KitchenandInventory/KIDashboard/KIDashboard';
+import KIINVENTORY from './components/KitchenandInventory/KIInventory/KIInventory';
+
// Education Portal
import EPProtectedRoute from './components/common/EPDashboard/EPProtectedRoute';
import EPLogin from './components/EductionPortal/Login';
@@ -838,6 +840,7 @@ export default (
{/* ----- END BM Dashboard Routing ----- */}
{/* ----- Kitchen and Inventory Portal Routes ----- */}
+
{/* ----- End of Kitchen and Inventory Portal Routes ----- */}
diff --git a/yarn.lock b/yarn.lock
index 2d07b6c40a..f842fc2896 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -46,9 +46,9 @@
"@ant-design/fast-color" "^2.0.6"
"@ant-design/colors@^8.0.0":
- version "8.0.1"
- resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-8.0.1.tgz"
- integrity sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==
+ version "8.0.0"
+ resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-8.0.0.tgz"
+ integrity sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==
dependencies:
"@ant-design/fast-color" "^3.0.0"
@@ -250,9 +250,9 @@
"@antv/vendor" "^1.0.10"
"@antv/g2@^5.1.8", "@antv/g2@^5.2.7":
- version "5.4.8"
- resolved "https://registry.npmjs.org/@antv/g2/-/g2-5.4.8.tgz"
- integrity sha512-IvgIpwmT4M5/QAd3Mn2WiHIDeBqFJ4WA2gcZhRRSZuZ2KmgCqZWZwwIT0hc+kIGxwYeDoCQqf//t6FMVu3ryBg==
+ version "5.4.7"
+ resolved "https://registry.npmjs.org/@antv/g2/-/g2-5.4.7.tgz"
+ integrity sha512-pYXOZ4Am+xgQbPshbHlbAsH6+DTPZ2iF8b63Vtfp19CoRuq6oO3cNZl+yweBs2WxLLSxVzjDkwBmB1kZBXOpFg==
dependencies:
"@antv/component" "^2.1.9"
"@antv/coord" "^0.4.7"
@@ -1601,13 +1601,25 @@
resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz"
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
-"@emotion/is-prop-valid@1.4.0", "@emotion/is-prop-valid@^1.3.0":
- version "1.4.0"
- resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz"
- integrity sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==
+"@emotion/is-prop-valid@1.2.2":
+ version "1.2.2"
+ resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz"
+ integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==
+ dependencies:
+ "@emotion/memoize" "^0.8.1"
+
+"@emotion/is-prop-valid@^1.3.0":
+ version "1.3.1"
+ resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz"
+ integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==
dependencies:
"@emotion/memoize" "^0.9.0"
+"@emotion/memoize@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz"
+ integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
+
"@emotion/memoize@^0.9.0":
version "0.9.0"
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz"
@@ -1655,7 +1667,12 @@
"@emotion/use-insertion-effect-with-fallbacks" "^1.2.0"
"@emotion/utils" "^1.4.2"
-"@emotion/unitless@0.10.0", "@emotion/unitless@^0.10.0":
+"@emotion/unitless@0.8.1":
+ version "0.8.1"
+ resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz"
+ integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
+
+"@emotion/unitless@^0.10.0":
version "0.10.0"
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz"
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
@@ -1778,7 +1795,7 @@
"@esbuild/darwin-arm64@0.25.9":
version "0.25.9"
- resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz#f1513eaf9ec8fa15dcaf4c341b0f005d3e8b47ae"
integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==
"@esbuild/darwin-x64@0.25.9":
@@ -1883,7 +1900,7 @@
"@esbuild/win32-x64@0.25.9":
version "0.25.9"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f"
+ resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz"
integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.7.0":
@@ -2187,7 +2204,7 @@
"@jest/environment-jsdom-abstract@30.2.0":
version "30.2.0"
- resolved "https://registry.yarnpkg.com/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.2.0.tgz#1313f9b3b509c31298c241203161b36622865181"
+ resolved "https://registry.npmjs.org/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.2.0.tgz"
integrity sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ==
dependencies:
"@jest/environment" "30.2.0"
@@ -2727,7 +2744,7 @@
"@parcel/watcher-darwin-arm64@2.5.1":
version "2.5.1"
- resolved "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67"
integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==
"@parcel/watcher-darwin-x64@2.5.1":
@@ -2782,7 +2799,7 @@
"@parcel/watcher-win32-x64@2.5.1":
version "2.5.1"
- resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947"
+ resolved "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz"
integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==
"@parcel/watcher@^2.4.1":
@@ -2830,9 +2847,9 @@
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
"@rc-component/async-validator@^5.0.3":
- version "5.1.0"
- resolved "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.1.0.tgz"
- integrity sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==
+ version "5.0.4"
+ resolved "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz"
+ integrity sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==
dependencies:
"@babel/runtime" "^7.24.4"
@@ -2963,7 +2980,7 @@
"@rollup/rollup-darwin-arm64@4.49.0":
version "4.49.0"
- resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz#788fad425b4129875639e0c14b6441c5f3b69d46"
integrity sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw==
"@rollup/rollup-darwin-arm64@^4.54.0":
@@ -3053,7 +3070,7 @@
"@rollup/rollup-win32-x64-msvc@4.49.0":
version "4.49.0"
- resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz#c2a0e3b81262a7e9dd12ce18b350a97558dd50bc"
+ resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz"
integrity sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg==
"@rtsao/scc@^1.1.0":
@@ -3607,10 +3624,10 @@
resolved "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz"
integrity sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==
-"@types/stylis@4.2.7":
- version "4.2.7"
- resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.7.tgz"
- integrity sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==
+"@types/stylis@4.2.5":
+ version "4.2.5"
+ resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz"
+ integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==
"@types/testing-library__jest-dom@^5.9.1":
version "5.14.9"
@@ -3781,7 +3798,7 @@
"@unrs/resolver-binding-darwin-arm64@1.11.1":
version "1.11.1"
- resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz"
+ resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf"
integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==
"@unrs/resolver-binding-darwin-x64@1.11.1":
@@ -3863,7 +3880,7 @@
"@unrs/resolver-binding-win32-x64-msvc@1.11.1":
version "1.11.1"
- resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777"
+ resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz"
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
"@vitejs/plugin-react@^4.5.0":
@@ -5373,10 +5390,10 @@ cssstyle@^4.2.1:
"@asamuzakjp/css-color" "^3.2.0"
rrweb-cssom "^0.8.0"
-csstype@3.2.3, csstype@^3.0.2, csstype@^3.0.8, csstype@^3.1.3:
- version "3.2.3"
- resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz"
- integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
+csstype@3.1.3, csstype@^3.0.2, csstype@^3.0.8, csstype@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
"d3-array@1 - 3", "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.1.6, d3-array@^3.2.0, d3-array@^3.2.4:
version "3.2.4"
@@ -5943,6 +5960,10 @@ dompurify@^2.5.4:
resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz"
integrity sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==
+dompurify@^3.2.5, dompurify@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz"
+ integrity sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==
dompurify@^3.2.5:
version "3.2.6"
resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz"
@@ -6842,7 +6863,7 @@ fs.realpath@^1.0.0:
fsevents@^2.3.2, fsevents@^2.3.3, fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
- resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
@@ -7870,7 +7891,7 @@ jest-each@30.2.0:
jest-environment-jsdom@^30.0.5:
version "30.2.0"
- resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-30.2.0.tgz#e95e0921ed22be974f1d8a324766d12b1844cb2c"
+ resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-30.2.0.tgz"
integrity sha512-zbBTiqr2Vl78pKp/laGBREYzbZx9ZtqPjOK4++lL4BNDhxRnahg51HtoDrk9/VjIy9IthNEWdKVd7H5bqBhiWQ==
dependencies:
"@jest/environment" "30.2.0"
@@ -8431,6 +8452,9 @@ jspdf@^2.5.1:
dompurify "^2.5.4"
html2canvas "^1.0.0-rc.5"
+jspdf@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/jspdf/-/jspdf-4.1.0.tgz"
jspdf@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-4.1.0.tgz#4fb476251c8751c996175cfaac02d30fdf8c7b7a"
@@ -11265,19 +11289,19 @@ style-to-object@0.3.0:
inline-style-parser "0.1.1"
styled-components@^6.1.15:
- version "6.3.8"
- resolved "https://registry.npmjs.org/styled-components/-/styled-components-6.3.8.tgz"
- integrity sha512-Kq/W41AKQloOqKM39zfaMdJ4BcYDw/N5CIq4/GTI0YjU6pKcZ1KKhk6b4du0a+6RA9pIfOP/eu94Ge7cu+PDCA==
+ version "6.1.19"
+ resolved "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz"
+ integrity sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==
dependencies:
- "@emotion/is-prop-valid" "1.4.0"
- "@emotion/unitless" "0.10.0"
- "@types/stylis" "4.2.7"
+ "@emotion/is-prop-valid" "1.2.2"
+ "@emotion/unitless" "0.8.1"
+ "@types/stylis" "4.2.5"
css-to-react-native "3.2.0"
- csstype "3.2.3"
+ csstype "3.1.3"
postcss "8.4.49"
shallowequal "1.1.0"
- stylis "4.3.6"
- tslib "2.8.1"
+ stylis "4.3.2"
+ tslib "2.6.2"
stylelint-config-recommended@^17.0.0:
version "17.0.0"
@@ -11340,7 +11364,12 @@ stylis@4.2.0:
resolved "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz"
integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
-stylis@4.3.6, stylis@^4.3.4:
+stylis@4.3.2:
+ version "4.3.2"
+ resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz"
+ integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==
+
+stylis@^4.3.4:
version "4.3.6"
resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz"
integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==
@@ -11628,7 +11657,12 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6"
strip-bom "^3.0.0"
-tslib@2.8.1, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.3:
+tslib@2.6.2:
+ version "2.6.2"
+ resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.3:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==