From 3f9d28bf1b12c190ce09202e4fd581799059c12f Mon Sep 17 00:00:00 2001 From: g Date: Mon, 12 Jan 2026 08:59:04 +0000 Subject: [PATCH] Improve browser detection and table UX for Firefox Standardizes browser detection logic across admin and storefront pages to more accurately identify Firefox. Updates table rendering logic to provide better compatibility and fallback for Firefox, including conditional use of AnimatePresence and improved loading/empty states. Refines table UI styles for consistency and accessibility. --- app/dashboard/admin/users/page.tsx | 137 ++++++------ app/dashboard/admin/vendors/page.tsx | 217 ++++++++++++++++++-- app/dashboard/storefront/customers/page.tsx | 3 +- components/tables/order-table.tsx | 28 +-- components/tables/product-table.tsx | 42 +++- components/tables/shipping-table.tsx | 83 +++++++- public/git-info.json | 4 +- 7 files changed, 400 insertions(+), 114 deletions(-) diff --git a/app/dashboard/admin/users/page.tsx b/app/dashboard/admin/users/page.tsx index 9b6ab95..30446ba 100644 --- a/app/dashboard/admin/users/page.tsx +++ b/app/dashboard/admin/users/page.tsx @@ -50,6 +50,14 @@ export default function AdminUsersPage() { const { toast } = useToast(); const [loading, setLoading] = useState(true); const [users, setUsers] = useState([]); + // State for browser detection + // Browser detection + const [isFirefox, setIsFirefox] = useState(false); + + useEffect(() => { + const ua = navigator.userAgent.toLowerCase(); + setIsFirefox(ua.includes("firefox") && !ua.includes("chrome")); + }, []); const [searchQuery, setSearchQuery] = useState(""); const [page, setPage] = useState(1); const [pagination, setPagination] = useState(null); @@ -198,20 +206,14 @@ export default function AdminUsersPage() { {loading ? ( - -
- -

Loading users...

+ +
+ + Loading users...
- ) : users.length === 0 ? ( - - - {searchQuery ? "No users found matching your search" : "No users found"} - - - ) : ( + ) : users.length > 0 ? ( users.map((user, index) => ( - -
{user.telegramUserId}
-
- -
- {user.telegramUsername !== "Unknown" ? ( - <> - @ - {user.telegramUsername} - - ) : ( - Unknown - )} -
-
+ {user.telegramUserId}
- {user.totalOrders} - {user.completedOrders > 0 && ( - - {user.completedOrders} done - + @{user.telegramUsername || "Unknown"} + {user.isBlocked && ( + Blocked )}
+ {user.totalOrders} + {formatCurrency(user.totalSpent)} - {formatCurrency(user.totalSpent)} +
+ {user.completedOrders} Completed + {user.paidOrders - user.completedOrders} Pending +
- - {user.isBlocked ? ( - - - - - - Blocked - - - {user.blockedReason && ( - -

{user.blockedReason}

-
- )} -
-
- ) : user.totalOrders > 0 ? ( - Active - ) : ( - No Orders - )} + + {user.firstOrderDate ? new Date(user.firstOrderDate).toLocaleDateString() : "-"} - - {user.firstOrderDate - ? new Date(user.firstOrderDate).toLocaleDateString() - : '-'} - - - {user.lastOrderDate - ? new Date(user.lastOrderDate).toLocaleDateString() - : '-'} + + {user.lastOrderDate ? new Date(user.lastOrderDate).toLocaleDateString() : "-"} -
- {!user.isBlocked ? ( - +
+ {user.isBlocked ? ( + + + + + + +

Unblock this user

+
+
+
) : ( - + + + + + + +

Block access to the store

+
+
+
)}
)) + ) : ( + + +
+ +

No users found

+
+
+
)} diff --git a/app/dashboard/admin/vendors/page.tsx b/app/dashboard/admin/vendors/page.tsx index 48bff9e..e57d400 100644 --- a/app/dashboard/admin/vendors/page.tsx +++ b/app/dashboard/admin/vendors/page.tsx @@ -12,6 +12,14 @@ import { Label } from "@/components/ui/label"; import { fetchClient } from "@/lib/api-client"; import { useToast } from "@/hooks/use-toast"; import { motion, AnimatePresence } from "framer-motion"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; interface Vendor { _id: string; @@ -40,6 +48,13 @@ export default function AdminVendorsPage() { const { toast } = useToast(); const [loading, setLoading] = useState(true); const [vendors, setVendors] = useState([]); + // State for browser detection + const [isFirefox, setIsFirefox] = useState(false); + + useEffect(() => { + const ua = navigator.userAgent.toLowerCase(); + setIsFirefox(ua.includes("firefox") && !ua.includes("chrome")); + }, []); const [page, setPage] = useState(1); const [pagination, setPagination] = useState(null); const [searchQuery, setSearchQuery] = useState(""); @@ -48,6 +63,26 @@ export default function AdminVendorsPage() { const [newStoreId, setNewStoreId] = useState(""); const [updating, setUpdating] = useState(false); + const handleToggleStatus = async (vendor: Vendor) => { + try { + await fetchClient(`/admin/vendors/${vendor._id}/status`, { + method: 'PATCH', + body: { isActive: !vendor.isActive } + }); + toast({ + title: "Success", + description: `Vendor ${vendor.isActive ? 'suspended' : 'activated'} successfully`, + }); + fetchVendors(); + } catch (error: any) { + toast({ + title: "Error", + description: error.message || "Failed to update vendor status", + variant: "destructive", + }); + } + }; + const handleEditStore = (vendor: Vendor) => { setEditingVendor(vendor); setNewStoreId(vendor.storeId || ""); @@ -212,8 +247,8 @@ export default function AdminVendorsPage() { - - {loading ? ( + {isFirefox ? ( + loading ? (
@@ -234,7 +269,6 @@ export default function AdminVendorsPage() { key={vendor._id} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} - exit={{ opacity: 0 }} transition={{ duration: 0.2, delay: index * 0.03 }} className="group hover:bg-muted/40 border-b border-border/50 transition-colors" > @@ -302,22 +336,173 @@ export default function AdminVendorsPage() {
-
- - - -
+ + + + + + Actions + navigator.clipboard.writeText(vendor._id)} + > + Copy Vendor ID + + + handleToggleStatus(vendor)} + > + {vendor.isActive ? ( + <> + + Suspend Vendor + + ) : ( + <> + + Activate Vendor + + )} + + +
)) - )} -
+ ) + ) : ( + + {loading ? ( + + +
+ +

Loading vendors...

+
+
+
+ ) : filteredVendors.length === 0 ? ( + + + {searchQuery.trim() ? "No vendors found matching your search" : "No vendors found"} + + + ) : ( + filteredVendors.map((vendor, index) => ( + + +
+
+ {vendor.username.substring(0, 2).toUpperCase()} +
+ {vendor.username} +
+
+ + {vendor.storeId ? ( +
+ {vendor.storeId} + +
+ ) : ( +
+ No store + +
+ )} +
+ +
+ + {vendor.isActive ? "Active" : "Suspended"} + + {vendor.isAdmin && ( + + + Admin + + )} +
+
+ +
+ + {vendor.createdAt ? new Date(vendor.createdAt).toLocaleDateString() : 'N/A'} +
+
+ +
+ + {vendor.lastLogin ? new Date(vendor.lastLogin).toLocaleDateString() : 'Never'} +
+
+ + + + + + + Actions + navigator.clipboard.writeText(vendor._id)} + > + Copy Vendor ID + + + handleToggleStatus(vendor)} + > + {vendor.isActive ? ( + <> + + Suspend Vendor + + ) : ( + <> + + Activate Vendor + + )} + + + + +
+ )) + )} +
+ )}
diff --git a/app/dashboard/storefront/customers/page.tsx b/app/dashboard/storefront/customers/page.tsx index f5713d0..3d8126f 100644 --- a/app/dashboard/storefront/customers/page.tsx +++ b/app/dashboard/storefront/customers/page.tsx @@ -66,7 +66,8 @@ export default function CustomerManagementPage() { const [isFirefox, setIsFirefox] = useState(false); useEffect(() => { - setIsFirefox(navigator.userAgent.toLowerCase().indexOf("firefox") > -1); + const ua = navigator.userAgent.toLowerCase(); + setIsFirefox(ua.includes("firefox") && !ua.includes("chrome")); }, []); const [filteredCustomers, setFilteredCustomers] = useState([]); const [searchQuery, setSearchQuery] = useState(""); diff --git a/components/tables/order-table.tsx b/components/tables/order-table.tsx index 6fb7ee0..c707436 100644 --- a/components/tables/order-table.tsx +++ b/components/tables/order-table.tsx @@ -158,10 +158,12 @@ export default function OrderTable() { // Fetch orders with server-side pagination // State for browser detection + // Browser detection const [isFirefox, setIsFirefox] = useState(false); useEffect(() => { - setIsFirefox(navigator.userAgent.toLowerCase().indexOf("firefox") > -1); + const ua = navigator.userAgent.toLowerCase(); + setIsFirefox(ua.includes("firefox") && !ua.includes("chrome")); }, []); const fetchOrders = useCallback(async () => { @@ -401,9 +403,9 @@ export default function OrderTable() { return (
- + {/* Filters header */} -
+
{exporting ? ( <> @@ -443,7 +445,7 @@ export default function OrderTable() {
- + +
+ + + )) + ) : ( + + +
+ +

No shipping methods found

+
+
+
+ )} + + )}
diff --git a/public/git-info.json b/public/git-info.json index cc477c8..170c1e6 100644 --- a/public/git-info.json +++ b/public/git-info.json @@ -1,4 +1,4 @@ { - "commitHash": "7b95589", - "buildTime": "2026-01-12T06:32:31.897Z" + "commitHash": "064cd7a", + "buildTime": "2026-01-12T08:43:31.133Z" } \ No newline at end of file