diff --git a/src/App.tsx b/src/App.tsx
index 4b18413..207fa47 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,29 +1,101 @@
-import { useState, useMemo } from "react";
+import { useState, useMemo, useDeferredValue, memo } from "react";
import "./App.css";
import { generateOrders, type Order } from "./generateOrderData";
+interface OrderTableProps {
+ orders: Order[];
+}
+
+const OrderTable = memo(function OrderTable({ orders }: OrderTableProps) {
+ const formatDate = (date: Date) => {
+ return date.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+ };
+
+ const formatCurrency = (amount: number, currency: string) => {
+ return `${currency} ${amount.toFixed(2)}`;
+ };
+ return (
+
+
+
+
+ | Order # |
+ Customer |
+ Email |
+ Date |
+ Status |
+ Total |
+ Items |
+ Payment |
+ Address |
+ City |
+ Country |
+ Tracking |
+ Est. Delivery |
+
+
+
+ {orders.map((order: Order) => (
+
+ | {order.orderNumber} |
+ {order.customerName} |
+ {order.customerEmail} |
+ {formatDate(order.orderDate)} |
+
+ {order.status}
+ |
+ {formatCurrency(order.totalAmount, order.currency)} |
+ {order.itemsCount} |
+ {order.paymentMethod.replace("_", " ")} |
+ {order.shippingAddress} |
+ {order.shippingCity} |
+ {order.shippingCountry} |
+ {order.trackingNumber} |
+ {formatDate(order.estimatedDelivery)} |
+
+ ))}
+
+
+
+ );
+});
+
function App() {
const [searchTerm, setSearchTerm] = useState("");
+ const deferredSearchTerm = useDeferredValue(searchTerm);
const [activeStatuses, setActiveStatuses] = useState>(
new Set(["pending", "processing", "shipped", "delivered", "cancelled"])
);
+ // orders could come from a server, in this example it does not matter.
const orders = useMemo(() => generateOrders(5000), []);
const filteredOrders = useMemo(() => {
return orders.filter((order) => {
const matchesSearch =
- searchTerm === "" ||
- order.orderNumber.toLowerCase().includes(searchTerm.toLowerCase()) ||
- order.customerName.toLowerCase().includes(searchTerm.toLowerCase()) ||
- order.customerEmail.toLowerCase().includes(searchTerm.toLowerCase()) ||
- order.trackingNumber.toLowerCase().includes(searchTerm.toLowerCase());
+ deferredSearchTerm === "" ||
+ order.orderNumber
+ .toLowerCase()
+ .includes(deferredSearchTerm.toLowerCase()) ||
+ order.customerName
+ .toLowerCase()
+ .includes(deferredSearchTerm.toLowerCase()) ||
+ order.customerEmail
+ .toLowerCase()
+ .includes(deferredSearchTerm.toLowerCase()) ||
+ order.trackingNumber
+ .toLowerCase()
+ .includes(deferredSearchTerm.toLowerCase());
const matchesStatus = activeStatuses.has(order.status);
return matchesSearch && matchesStatus;
});
- }, [orders, searchTerm, activeStatuses]);
+ }, [orders, deferredSearchTerm, activeStatuses]);
const toggleStatus = (status: Order["status"]) => {
setActiveStatuses((prev) => {
@@ -37,18 +109,6 @@ function App() {
});
};
- const formatDate = (date: Date) => {
- return date.toLocaleDateString("en-US", {
- year: "numeric",
- month: "short",
- day: "numeric",
- });
- };
-
- const formatCurrency = (amount: number, currency: string) => {
- return `${currency} ${amount.toFixed(2)}`;
- };
-
const statuses: Order["status"][] = [
"pending",
"processing",
@@ -63,6 +123,7 @@ function App() {
-
-
-
-
- | Order # |
- Customer |
- Email |
- Date |
- Status |
- Total |
- Items |
- Payment |
- Address |
- City |
- Country |
- Tracking |
- Est. Delivery |
-
-
-
- {filteredOrders.map((order: Order) => (
-
- | {order.orderNumber} |
- {order.customerName} |
- {order.customerEmail} |
- {formatDate(order.orderDate)} |
-
- {order.status}
- |
- {formatCurrency(order.totalAmount, order.currency)} |
- {order.itemsCount} |
- {order.paymentMethod.replace("_", " ")} |
- {order.shippingAddress} |
- {order.shippingCity} |
- {order.shippingCountry} |
- {order.trackingNumber} |
- {formatDate(order.estimatedDelivery)} |
-
- ))}
-
-
-
+
);
}
diff --git a/src/index.css b/src/index.css
index 08a3ac9..ffd860c 100644
--- a/src/index.css
+++ b/src/index.css
@@ -24,10 +24,6 @@ a:hover {
body {
margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
}
h1 {