Overview
The Don Palito Jr admin panel is a separate web application for administrators to manage the e-commerce platform. It provides interfaces for product management, order processing, customer administration, and coupon creation.
Technology Stack
React 19.2 Latest React with improved performance
Vite 7.2 Next-generation build tool
Tailwind CSS 4.1 Modern utility-first CSS
DaisyUI 5.5 Component library for Tailwind
Key Dependencies
Authentication : Clerk React (@clerk/clerk-react)
State Management : Zustand
Data Fetching : TanStack Query (@tanstack/react-query)
HTTP Client : Axios
Routing : React Router v7
Icons : Lucide React
Monitoring : Sentry React
Setup and Development
Install Dependencies
cd source/admin
npm install
Configure Environment
Create a .env file: VITE_CLERK_PUBLISHABLE_KEY = your_clerk_key
VITE_API_URL = http://localhost:3000/api
VITE_SENTRY_DSN = your_sentry_dsn
Start Development Server
Admin panel runs on http://localhost:5173
Admin Role Protection
The admin panel uses Clerk’s public metadata to verify admin access:
// src/App.jsx
function App () {
const { isSignedIn , isLoaded } = useAuth ();
const { user , isLoaded : userLoaded } = useUser ();
if ( ! isLoaded || ! userLoaded ) {
return < PageLoader /> ;
}
const isAdmin = user ?. publicMetadata ?. role === 'admin' ;
return (
< Routes >
< Route
path = "/login"
element = {
isSignedIn
? ( isAdmin ? < Navigate to = "/dashboard" /> : < Navigate to = "/unauthorized" /> )
: < LoginPage />
}
/>
< Route path = "/unauthorized" element = { < UnauthorizedPage /> } />
< Route
path = "/"
element = {
! isSignedIn ? (
< Navigate to = "/login" />
) : ! isAdmin ? (
< Navigate to = "/unauthorized" replace />
) : (
< DashboardLayout />
)
}
>
< Route index element = { < Navigate to = "dashboard" /> } />
< Route path = "dashboard" element = { < DashboardPage /> } />
< Route path = "products" element = { < ProductsPage /> } />
< Route path = "orders" element = { < OrdersPage /> } />
< Route path = "customers" element = { < CustomersPage /> } />
< Route path = "coupons" element = { < CouponsPage /> } />
</ Route >
</ Routes >
);
}
Only users with role: 'admin' in Clerk’s publicMetadata can access the admin panel. All other users are redirected to the unauthorized page.
Project Structure
src/
├── components/
│ ├── AuthProvider.jsx # Clerk authentication wrapper
│ ├── Navbar.jsx # Top navigation bar
│ ├── Sidebar.jsx # Side navigation menu
│ └── PageLoader.jsx # Loading spinner
├── layouts/
│ └── DashboardLayout.jsx # Main admin layout
├── lib/
│ ├── api.js # API client functions
│ └── utils.js # Utility functions
├── pages/
│ ├── DashboardPage.jsx # Analytics overview
│ ├── ProductsPage.jsx # Product management
│ ├── OrdersPage.jsx # Order processing
│ ├── CustomersPage.jsx # Customer administration
│ ├── CouponsPage.jsx # Coupon management
│ ├── LoginPage.jsx # Admin login
│ └── UnauthorizedPage.jsx # Access denied page
├── App.jsx
└── main.jsx
Admin Features
Product Management
The products page allows admins to create, update, and delete products with image uploads:
function ProductsPage () {
const [ showModal , setShowModal ] = useState ( false );
const [ editingProduct , setEditingProduct ] = useState ( null );
const [ formData , setFormData ] = useState ({
name: "" ,
category: "" ,
price: "" ,
stock: "" ,
description: "" ,
});
const [ images , setImages ] = useState ([]);
const queryClient = useQueryClient ();
// Fetch products
const { data : products = [] } = useQuery ({
queryKey: [ "products" ],
queryFn: productApi . getAll ,
});
// Create product mutation
const createProductMutation = useMutation ({
mutationFn: productApi . create ,
onSuccess : () => {
closeModal ();
queryClient . invalidateQueries ({ queryKey: [ "products" ] });
},
});
const handleSubmit = ( e ) => {
e . preventDefault ();
const formDataToSend = new FormData ();
formDataToSend . append ( "name" , formData . name );
formDataToSend . append ( "description" , formData . description );
formDataToSend . append ( "price" , formData . price );
formDataToSend . append ( "stock" , formData . stock );
formDataToSend . append ( "category" , formData . category );
if ( images . length > 0 ) {
images . forEach (( image ) => formDataToSend . append ( "images" , image ));
}
createProductMutation . mutate ( formDataToSend );
};
}
Product Categories
The admin panel supports the following product categories:
Palitos Premium - High-quality traditional sticks
Palitos Cocteleros - Cocktail-style sticks
Dulces - Sweet treats
Especiales - Special edition items
Nuevos - New arrivals
Order Management
Admins can view and update order statuses:
View Orders
Display all orders with customer information, items, and current status
Update Status
Change order status between:
Pending
Processing
Shipped
Delivered
Cancelled
View Details
Access detailed order information including shipping address and payment details
Customer Administration
Manage customer accounts:
View customer profiles and order history
Activate/deactivate accounts
View customer addresses and preferences
Monitor customer activity
Coupon Management
Create and manage promotional coupons:
Set discount percentage or fixed amount
Configure expiration dates
Set usage limits
Track coupon redemptions
State Management with Zustand
The admin panel uses Zustand for lightweight global state:
import create from 'zustand' ;
const useAdminStore = create (( set ) => ({
sidebarOpen: true ,
toggleSidebar : () => set (( state ) => ({ sidebarOpen: ! state . sidebarOpen })),
}));
Data Fetching Configuration
React Query is configured with optimized defaults:
const queryClient = new QueryClient ({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000 , // 5 minutes
gcTime: 10 * 60 * 1000 , // 10 minutes
retry: 1 ,
refetchOnWindowFocus: false ,
refetchOnMount: true ,
refetchOnReconnect: true ,
networkMode: 'online' ,
},
mutations: {
retry: 0 ,
networkMode: 'online' ,
},
},
})
Error Monitoring with Sentry
Sentry is integrated for error tracking and performance monitoring:
import * as Sentry from "@sentry/react" ;
Sentry . init ({
dsn: import . meta . env . VITE_SENTRY_DSN ,
sendDefaultPii: true ,
enableLogs: true ,
integrations: [ Sentry . replayIntegration ()],
replaysSessionSampleRate: 1.0 ,
replaysOnErrorSampleRate: 1.0 ,
});
Available Scripts
Development
Build
Preview
Lint
Best Practices
Always verify admin role before rendering sensitive components
Use React Query mutations for all data modifications
Invalidate queries after successful mutations to refresh data
Handle loading and error states in all components
Use DaisyUI components for consistent UI
The admin panel is a separate deployment from the customer-facing web app. They share the same API but have different access controls.
Security Considerations
Role-Based Access : Only users with admin role can access the panel
Token Validation : All API requests include JWT tokens from Clerk
Protected Routes : Unauthorized users are redirected to /unauthorized
Secure Endpoints : Backend validates admin permissions on every request
Never expose admin credentials in client-side code. All admin verification happens server-side.