Add modular dashboard widgets and layout editor
Some checks failed
Build Frontend / build (push) Failing after 7s

Introduces a modular dashboard system with draggable, configurable widgets including revenue, low stock, recent customers, and pending chats. Adds a dashboard editor for layout customization, widget visibility, and settings. Refactors dashboard content to use the new widget system and improves UI consistency and interactivity.
This commit is contained in:
g
2026-01-12 10:39:50 +00:00
parent a6b7286b45
commit 318927cd0c
23 changed files with 2435 additions and 317 deletions

View File

@@ -3,6 +3,7 @@
import { useState, useEffect, useCallback } from "react";
import React from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useSearchParams } from "next/navigation";
import {
Table,
TableBody,
@@ -129,9 +130,12 @@ const PageSizeSelector = ({ currentSize, onChange, options }: { currentSize: num
export default function OrderTable() {
const searchParams = useSearchParams();
const initialStatus = searchParams?.get("status") || "all";
const [orders, setOrders] = useState<Order[]>([]);
const [loading, setLoading] = useState(true);
const [statusFilter, setStatusFilter] = useState("all");
const [statusFilter, setStatusFilter] = useState(initialStatus);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalOrders, setTotalOrders] = useState(0);
@@ -249,37 +253,56 @@ export default function OrderTable() {
return;
}
const orderIdsToShip = Array.from(selectedOrders);
// Store previous state for rollback
const previousOrders = [...orders];
// Optimistic update - immediately mark orders as shipped in UI
setOrders(prev =>
prev.map(order =>
selectedOrders.has(order._id)
? { ...order, status: "shipped" as const }
: order
)
);
setSelectedOrders(new Set());
// Show optimistic toast
toast.success(`Marking ${orderIdsToShip.length} order(s) as shipped...`, { id: "shipping-optimistic" });
try {
setIsShipping(true);
const response = await clientFetch("/orders/mark-shipped", {
method: "POST",
body: JSON.stringify({ orderIds: Array.from(selectedOrders) })
body: JSON.stringify({ orderIds: orderIdsToShip })
});
// Only update orders that were successfully marked as shipped
// Handle partial success/failure
if (response.success && response.success.orders) {
const successfulOrderIds = new Set(response.success.orders.map((o: any) => o.id));
setOrders(prev =>
prev.map(order =>
successfulOrderIds.has(order._id)
? { ...order, status: "shipped" }
: order
)
);
// If some orders failed, revert those specifically
if (response.failed && response.failed.count > 0) {
toast.warning(`${response.failed.count} orders could not be marked as shipped`);
}
if (response.success.count > 0) {
toast.success(`${response.success.count} orders marked as shipped`);
setOrders(prev =>
prev.map(order => {
if (orderIdsToShip.includes(order._id) && !successfulOrderIds.has(order._id)) {
// Find original status from previousOrders
const originalOrder = previousOrders.find(o => o._id === order._id);
return originalOrder || order;
}
return order;
})
);
toast.warning(`${response.failed.count} order(s) could not be marked as shipped`, { id: "shipping-optimistic" });
} else if (response.success.count > 0) {
toast.success(`${response.success.count} order(s) marked as shipped!`, { id: "shipping-optimistic" });
}
}
setSelectedOrders(new Set());
} catch (error) {
toast.error("Failed to update orders");
// Revert all changes on error
setOrders(previousOrders);
toast.error("Failed to update orders - changes reverted", { id: "shipping-optimistic" });
console.error("Shipping error:", error);
} finally {
setIsShipping(false);