🛒 Custom Development

Custom Admin Panel:
Shipping APIs, PO Templates, Dark Mode

The client's e-commerce operation had outgrown every off-the-shelf admin tool. Legacy float-based layouts were breaking product grids. The purchase order template was a 2005-era HTML table that printed badly. Shipping rates required manually visiting carrier websites. We replaced all of it from scratch.

3Carrier APIs
Real-TimeShipping Rates
CSS GridPO Templates
Dark ModeBuilt-In

The Challenge

The client was running a B2B e-commerce operation that had grown to hundreds of daily orders. Their admin interface was a collection of cobbled-together tools: legacy PHP pages with inline styles, Bootstrap 3 grids that broke when product names were longer than expected, and a purchase order template that had been designed around early 2000s HTML email table techniques.

Every time a rep needed to quote shipping, they opened three browser tabs — one for FedEx, one for UPS, one for USPS — manually entered the package details, and compared the numbers. On a busy day, that was 20+ minutes of wasted time just on shipping lookups.

The goal: A single, modern admin dashboard that works the way their team actually works. No off-the-shelf compromises, no legacy debt — built specifically for their product catalog, their carriers, and their workflow.

Real-Time Shipping Calculator

The shipping calculator was the most technically complex piece. Each of the three major carriers now uses OAuth 2.0-based REST APIs — not the old XML/SOAP interfaces most tutorials still document. We built an object-oriented carrier abstraction where each carrier is its own class implementing a common interface:

PHP — Carrier class architecture
// Common interface all carriers implement
interface ShippingCarrier {
  public function getOAuthToken(): string;
  public function getRates(ShipmentRequest $req): array;
  public function createShipment(ShipmentRequest $req): Label;
}

// Each carrier is its own class
class FedExCarrier implements ShippingCarrier { ... }
class UPSCarrier implements ShippingCarrier { ... }
class USPSCarrier implements ShippingCarrier { ... }

// Get rates from all carriers simultaneously
$rates = array_merge(
  $fedex->getRates($request),
  $ups->getRates($request),
  $usps->getRates($request)
);
usort($rates, fn($a,$b) => $a->price <=> $b->price);
FedEx
REST API v1
OAuth 2.0 Client Credentials
Ground, Express, 2Day
UPS
OAuth 2.0 REST API
Ground, 3-Day Select
Next Day Air Saver
USPS
Web Tools API
Priority Mail
First Class, Media Mail

OAuth tokens are cached in the database with expiry timestamps — no unnecessary re-authentication on every rate request. When a token is within 60 seconds of expiring, it's refreshed proactively in the background, so the user never sees an authentication delay.

Purchase Order Template Redesign

The existing PO template was built with nested HTML tables and inline font tags — a relic of the era before CSS was reliable. It printed inconsistently across browsers, the column widths shifted based on content, and it couldn't be styled without touching every cell individually.

The redesign used CSS Grid for the PO line-item table and modern print CSS for letter-size output:

Before — table-based layout
<table width="100%">
<tr><td width="50%">
 <font size="2">
  Item name here...
 </font>
</td>
<td align="right">
 <font size="2">$99.99</font>
</td></tr>
</table>
After — CSS Grid, print-ready
.po-lines {
 display: grid;
 grid-template-columns:
  1fr 80px 80px 100px;
}
@media print {
 @page { size: letter; }
 .po-lines { font-size: 11px; }
 .no-print { display: none; }
}

Fixing the Product Grid

The product listing used Bootstrap 3's float-based grid. When a product name was unusually long or an image failed to load, it would push subsequent tiles out of alignment — creating a "staircase" effect where every other column was offset. This is a fundamental limitation of float-based layouts.

The fix was converting the grid from floats to flexbox with a fixed tile height and align-items: stretch. Each tile is now a flex column with the image at top, name in the middle with flex-grow: 1 to absorb varying lengths, and the price/action buttons pinned to the bottom:

CSS — Flexbox product tile fix
/* Before: float-based Bootstrap 3 — tiles could "skip" */
.product-grid { overflow: hidden; }
.product-tile { float: left; width: 25%; }

/* After: flexbox — all tiles same height, no skipping */
.product-grid {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
}
.product-tile {
  display: flex;
  flex-direction: column;
  width: calc(25% - 16px);
}
.product-tile .name {
  flex-grow: 1; /* absorbs varying name lengths */
}

The admin panel serves multiple roles: account managers see customer data and orders, warehouse staff see inventory and shipping labels, admins see everything including configuration and user management. The sidebar nav renders dynamically based on the logged-in user's permission set — no navigation items appear that the user can't access, preventing both accidental misuse and role confusion.

Dark/Light Theme

The entire UI uses CSS custom properties for colors. Switching themes is a single class toggle on the <html> element — no page reload, no JavaScript framework required. Theme preference is persisted in localStorage and remembered across sessions.

CSS — Theme system with custom properties
/* Light theme (default) */
:root {
  --bg: #ffffff;
  --text: #0f172a;
  --border: #e2e8f0;
}

/* Dark theme — one selector, zero duplication */
html[data-theme="dark"] {
  --bg: #0f172a;
  --text: #f1f5f9;
  --border: #1e293b;
}

// JS — toggle with localStorage persistence
document.documentElement.dataset.theme =
  localStorage.getItem('theme') || 'light';

Feature Summary

📦 Shipping Calculator

FedEx, UPS, USPS rates side-by-side in real time. OAuth tokens cached with auto-refresh. Sorted cheapest-first.

📄 Purchase Orders

CSS Grid layout, letter-size print-ready, consistent column widths regardless of content length.

📷 Product Grid

Flexbox tiles — no "skipped" products. Uniform height. Name overflow handled gracefully.

🔒 Permission System

Role-based sidebar nav. Users only see sections they have access to. Admin, manager, and warehouse roles.

🌙 Dark/Light Mode

CSS custom properties + localStorage. Zero-reload theme switching. Persistent across sessions.

📱 Fully Responsive

Works on tablets for warehouse use. Mobile-first breakpoints. Collapsible sidebar on small screens.

Tech Stack

PHP 8.1 • MySQL 8.0 • FedEx REST API (OAuth 2.0) • UPS REST API (OAuth 2.0) • USPS Web Tools API • CSS Grid • CSS Custom Properties • Vanilla JavaScript • Print CSS

Need a Custom Admin Panel?

We build tools that fit your workflow exactly — not the other way around. Tell us what you need and we'll scope it out.

Discuss Your Project View All Case Studies