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