+ {isAdminView ? (
+
+ ) : null}
+
+
{product.name}
Status:{" "}
@@ -129,17 +130,17 @@ const OrderCard: React.FC<{ orderWithProduct: OrderWithProduct }> = ({
Manage order
setIsEditAddressModalOpen(true)}
className="cursor-pointer"
>
@@ -147,7 +148,7 @@ const OrderCard: React.FC<{ orderWithProduct: OrderWithProduct }> = ({
setIsCancelOrderModalOpen(true)}
className="cursor-pointer"
>
diff --git a/frontend/src/components/pages/AdminDashboard.tsx b/frontend/src/components/pages/AdminDashboard.tsx
new file mode 100644
index 00000000..6b94a734
--- /dev/null
+++ b/frontend/src/components/pages/AdminDashboard.tsx
@@ -0,0 +1,109 @@
+import { useEffect, useState } from "react";
+import { useNavigate } from "react-router-dom";
+
+import OrderCard from "@/components/orders/OrderCard";
+import Spinner from "@/components/ui/Spinner";
+import { useAlertQueue } from "@/hooks/useAlertQueue";
+import { useAuthentication } from "@/hooks/useAuth";
+import { ApiError } from "@/lib/types/api";
+import type { OrderWithProduct } from "@/lib/types/orders";
+import ROUTES from "@/lib/types/routes";
+
+const AdminDashboard = () => {
+ const navigate = useNavigate();
+ const { api, currentUser, isAuthenticated, isLoading } = useAuthentication();
+ const [orders, setOrders] = useState([]);
+ const [loadingOrders, setLoadingOrders] = useState(true);
+ const { addErrorAlert } = useAlertQueue();
+
+ useEffect(() => {
+ const fetchOrders = async () => {
+ if (isAuthenticated && currentUser?.permissions?.includes("is_admin")) {
+ setLoadingOrders(true);
+ try {
+ const { data, error } = await api.client.GET("/orders/admin/all");
+
+ if (error) {
+ const apiError = error as ApiError;
+ addErrorAlert({
+ message: "Failed to fetch orders",
+ detail: apiError.message || "An unexpected error occurred",
+ });
+ setOrders([]);
+ } else {
+ setOrders(data.orders as OrderWithProduct[]);
+ }
+ } finally {
+ setLoadingOrders(false);
+ }
+ }
+ };
+
+ fetchOrders();
+ }, [api, currentUser, isAuthenticated]);
+
+ // Redirect non-admin users
+ useEffect(() => {
+ if (
+ !isLoading &&
+ (!isAuthenticated || !currentUser?.permissions?.includes("is_admin"))
+ ) {
+ navigate(ROUTES.HOME.path);
+ }
+ }, [isLoading, isAuthenticated, currentUser]);
+
+ if (isLoading || loadingOrders) {
+ return (
+
+
+
Admin Dashboard
+
+ View and manage all orders across the platform. Update order
+ statuses, process pre-orders, and cancel orders.
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
Admin Dashboard
+
+ View and manage all orders across the platform. Update order statuses,
+ process pre-orders, and cancel orders.
+
+
+
+
+
+ Viewing All Orders As Admin
+
+ {orders.length > 0 ? (
+
+ {orders.map((orderWithProduct) => (
+
+ ))}
+
+ ) : (
+
+
No orders found
+
+ There are no orders placed yet or no orders that match your query.
+
+
+ )}
+
+
+ );
+};
+
+export default AdminDashboard;
diff --git a/frontend/src/components/ui/Modal.tsx b/frontend/src/components/ui/Modal.tsx
index 83b18144..dbde01e3 100644
--- a/frontend/src/components/ui/Modal.tsx
+++ b/frontend/src/components/ui/Modal.tsx
@@ -4,9 +4,17 @@ interface ModalProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
+ className?: string;
+ size?: "sm" | "md" | "lg" | "xl";
}
-const Modal: React.FC = ({ isOpen, onClose, children }) => {
+const Modal: React.FC = ({
+ isOpen,
+ onClose,
+ children,
+ className,
+ size = "md",
+}) => {
if (!isOpen) return null;
return (
@@ -15,7 +23,9 @@ const Modal: React.FC = ({ isOpen, onClose, children }) => {
className="absolute inset-0 bg-gray-11 opacity-50"
onClick={onClose}
>
diff --git a/frontend/src/gen/api.ts b/frontend/src/gen/api.ts
index 6f229f96..35c37369 100644
--- a/frontend/src/gen/api.ts
+++ b/frontend/src/gen/api.ts
@@ -703,6 +703,43 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/orders/admin/all": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /**
+ * Get All Orders
+ * @description Get all orders (admin only).
+ */
+ get: operations["get_all_orders_orders_admin_all_get"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/orders/admin/status/{order_id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ /** Update Order Status */
+ put: operations["update_order_status_orders_admin_status__order_id__put"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/robots/create": {
parameters: {
query?: never;
@@ -979,7 +1016,7 @@ export interface paths {
patch?: never;
trace?: never;
};
- "/stripe/process-preorder/{order_id}": {
+ "/stripe/process/preorder/{order_id}": {
parameters: {
query?: never;
header?: never;
@@ -1226,6 +1263,11 @@ export interface paths {
export type webhooks = Record