Forms, Tables & UI Patterns
Reusable UI architecture for forms, data tables, bulk selection, modal dialogs, and feedback states.
Forms, Tables & UI Patterns
IMPLEMENTED
The Sheba ISP ERP frontend employs consistent design patterns across all 28 pages to ensure predictability and high developer velocity.
1. Form Architecture & Lifecycle
All entity creation and modification actions (such as adding a customer, updating a router, or generating invoices) are implemented as modal forms using the Dialog primitive:
Controlled Input Example:
// Pattern used across customer and package modals
const [formData, setFormData] = useState({
full_name: "",
mobile: "",
package: "",
billing_type: "Prepaid",
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!formData.full_name || !formData.mobile) {
toast.error("Please provide both name and mobile number");
return;
}
setSaving(true);
try {
await ApiClient.createCustomer(formData);
toast.success("Customer created successfully");
setIsModalOpen(false);
reloadCustomers();
} catch (err) {
toast.error("Failed to create customer");
} finally {
setSaving(false);
}
};2. Table Architecture & Filtering Pattern
Tables in the application follow a standardized 4-part structure:
- Header & Actions Bar: Page title, total record count, primary creation button (e.g.
Plusicon), and export trigger. - Filter Toolbar:
- Search Input: Full-text search on names, usernames, phone numbers, or IPs.
- Status Tabs: Fast status toggling (
All,Active,Expired,Suspended). - Context Dropdowns: Zone, Package, or Reseller filters.
- Data Grid:
- Built using
@/components/ui/table:Table,TableHeader,TableRow,TableCell. - Zebra striping or subtle hover highlighting (
hover:bg-muted/50). - Compact density to fit large ISP operational datasets on standard laptop screens.
- Built using
- Action Menu: Each row features a
MoreHorizontaldropdown containing contextual operations (View, Edit, Recharge, Suspend, Delete).
3. Bulk Selection & Batch Actions
For mass operations (such as bulk subscriber recharge, sending notification blasts, or extending grace days), tables implement multi-select state:
// Bulk selection state pattern (src/app/customers/page.tsx)
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const handleSelectAll = (checked: boolean) => {
if (checked) {
setSelectedIds(customers.map((c) => c.id));
} else {
setSelectedIds([]);
}
};
const handleToggleRow = (id: string) => {
setSelectedIds((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
);
};When selectedIds.length > 0, an animated floating Bulk Action Toolbar appears, displaying the selected count and actions like:
- Bulk Recharge (specify days and payment method)
- Bulk Grace Extension (extend expiry without marking unpaid)
- Bulk Change Reseller
- Bulk SMS Broadcast
4. UI Feedback States
Loading States
- Individual buttons display a spinning indicator when executing asynchronous tasks (
<Button disabled={saving}>). - Full tables render an animated placeholder or skeleton rows while
loading === true.
Toast Notifications
All mutation outcomes trigger immediate visual confirmation using Sonner:
import { toast } from "sonner";
// On success
toast.success("Router configuration synchronized successfully");
// On failure
toast.error("Failed to reboot router: Device timed out");Platform, Portal & Control Plane Pages
Documentation for Customer Self-Service Portal, SaaS Multi-Tenant Control Plane, ISP Configuration, and Authentication.
Frontend Development Guides
Step-by-step developer guides for creating new pages, adding CRUD features, extending ApiClient, and protecting routes.