feat: Complete toolbar standardization - add refresh button and fix reset filters

**Issue:**
- Orders: Missing refresh button (Products had it)
- Orders: Reset button had red background style
- Products: Reset button had text link style
- Inconsistent UX between modules

**Solution:**
1. Updated PROJECT_SOP.md with complete toolbar standards
2. Added refresh button to Orders (now mandatory for all CRUD)
3. Standardized reset filters button style (text link)

**Changes to PROJECT_SOP.md:**
- Added "Refresh (Required)" button type
- Added "Reset Filters" button type (text link style)
- Updated rules: 11 mandatory rules (was 8)
- Rule 2: Refresh button MUST exist in all CRUD lists
- Rule 3: Reset filters use text link (NOT button with background)
- Updated toolbar layout example with complete structure

**Changes to Orders/index.tsx:**
- Added refresh button (always visible)
- Reset button: bg-red-500/10 text-red-600 → text-muted-foreground hover:text-foreground underline
- Reset button text: "Reset" → "Clear filters"
- Removed loading indicator (q.isFetching)

**Result:**
 Both modules now have refresh button
 Consistent reset filters style (text link)
 Consistent button placement and behavior
 Complete toolbar standardization

**Standards Now Include:**
1. Delete button (red, conditional)
2. Refresh button (always visible, REQUIRED)
3. Reset filters (text link, conditional)
4. Export/secondary actions (light, optional)

Ready for Coupons and Customers CRUD implementation! 🎉
This commit is contained in:
dwindown
2025-11-20 10:27:57 +07:00
parent a36094f6df
commit dfbd992a22
2 changed files with 52 additions and 24 deletions

View File

@@ -269,8 +269,9 @@ All CRUD list pages MUST use consistent button styling in the toolbar:
| Button Type | Classes | Use Case | | Button Type | Classes | Use Case |
|-------------|---------|----------| |-------------|---------|----------|
| **Delete (Destructive)** | `border rounded-md px-3 py-2 text-sm bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 inline-flex items-center gap-2` | Bulk delete action | | **Delete (Destructive)** | `border rounded-md px-3 py-2 text-sm bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 inline-flex items-center gap-2` | Bulk delete action |
| **Refresh** | `border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2` | Refresh data | | **Refresh (Required)** | `border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2` | Refresh data (MUST exist in all CRUD lists) |
| **Export/Secondary** | `border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2` | Secondary actions | | **Reset Filters** | `text-sm text-muted-foreground hover:text-foreground underline` | Clear all active filters |
| **Export/Secondary** | `border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2` | Other secondary actions |
**Button Structure:** **Button Structure:**
```tsx ```tsx
@@ -286,30 +287,49 @@ All CRUD list pages MUST use consistent button styling in the toolbar:
**Rules:** **Rules:**
1. ✅ **Delete button** - Always use `bg-red-600` (NOT `bg-black`) 1. ✅ **Delete button** - Always use `bg-red-600` (NOT `bg-black`)
2. ✅ **Icon placement** - Use `inline-flex items-center gap-2` (NOT `inline mr-2`) 2. ✅ **Refresh button** - MUST exist in all CRUD list pages (mandatory)
3. ✅ **Destructive actions** - Only show when items selected (conditional render) 3. ✅ **Reset filters** - Use text link style (NOT button with background)
4. ✅ **Non-destructive actions** - Can be always visible (use `disabled` state) 4. ✅ **Icon placement** - Use `inline-flex items-center gap-2` (NOT `inline mr-2`)
5. ✅ **Consistent spacing** - Use `gap-2` between icon and text 5. ✅ **Destructive actions** - Only show when items selected (conditional render)
6. ✅ **Hover states** - Destructive: `hover:bg-red-700`, Secondary: `hover:bg-accent` 6. ✅ **Non-destructive actions** - Can be always visible (use `disabled` state)
7. **Never use `bg-black`** for delete buttons 7. **Consistent spacing** - Use `gap-2` between icon and text
8. **Never use `inline mr-2`** - use `inline-flex gap-2` instead 8. **Hover states** - Destructive: `hover:bg-red-700`, Secondary: `hover:bg-accent`
9. ❌ **Never use `bg-black`** for delete buttons
10. ❌ **Never use `inline mr-2`** - use `inline-flex gap-2` instead
11. ❌ **Never use button style** for reset filters - use text link
**Toolbar Layout:** **Toolbar Layout:**
```tsx ```tsx
<div className="flex gap-3"> <div className="flex flex-col lg:flex-row lg:justify-between lg:items-center gap-3">
{/* Bulk Actions - Show only when items selected */} {/* Left: Bulk Actions */}
{selectedIds.length > 0 && ( <div className="flex gap-3">
<button className="...bg-red-600..."> {/* Delete - Show only when items selected */}
<Trash2 className="w-4 h-4" /> {selectedIds.length > 0 && (
{__('Delete')} ({selectedIds.length}) <button className="border rounded-md px-3 py-2 text-sm bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 inline-flex items-center gap-2">
<Trash2 className="w-4 h-4" />
{__('Delete')} ({selectedIds.length})
</button>
)}
{/* Refresh - Always visible (REQUIRED) */}
<button className="border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2">
<RefreshCw className="w-4 h-4" />
{__('Refresh')}
</button> </button>
)} </div>
{/* Always-visible actions */} {/* Right: Filters */}
<button className="...hover:bg-accent..."> <div className="flex gap-3 flex-wrap items-center">
<RefreshCw className="w-4 h-4" /> <Select>...</Select>
{__('Refresh')} <Select>...</Select>
</button>
{/* Reset Filters - Text link style */}
{activeFiltersCount > 0 && (
<button className="text-sm text-muted-foreground hover:text-foreground underline">
{__('Clear filters')}
</button>
)}
</div>
</div> </div>
``` ```

View File

@@ -255,6 +255,15 @@ export default function Orders() {
{__('Delete')} ({selectedIds.length}) {__('Delete')} ({selectedIds.length})
</button> </button>
)} )}
<button
className="border rounded-md px-3 py-2 text-sm hover:bg-accent disabled:opacity-50 inline-flex items-center gap-2"
onClick={handleRefresh}
disabled={q.isLoading || isRefreshing}
>
<RefreshCw className={`w-4 h-4 ${isRefreshing ? 'animate-spin' : ''}`} />
{__('Refresh')}
</button>
</div> </div>
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
@@ -299,13 +308,12 @@ export default function Orders() {
{activeFiltersCount > 0 && ( {activeFiltersCount > 0 && (
<button <button
className="rounded-md px-3 py-2 text-sm bg-red-500/10 text-red-600" className="text-sm text-muted-foreground hover:text-foreground underline"
onClick={handleResetFilters} onClick={handleResetFilters}
> >
{__('Reset')} {__('Clear filters')}
</button> </button>
)} )}
{q.isFetching && <span className="text-sm opacity-70">{__('Loading…')}</span>}
</div> </div>
</div> </div>
</div> </div>