# Refactored Code Usage Guide

Quick reference for developers working with the refactored codebase.

## Backend Helper Functions

### 1. CRUD Helpers

#### `_get_or_404(db, model, record_id, error_message)`

Fetch a record by ID or raise 404 error.

**Usage:**

```python
# Before
result = await db.execute(select(Product).where(Product.id == product_id))
product = result.scalar_one_or_none()
if not product:
    raise HTTPException(status_code=404, detail="Product not found")

# After
product = await _get_or_404(db, Product, product_id, "Product not found")
```

#### `_soft_delete(db, record, commit=True)`

Soft delete a record (set `is_active=False`).

**Usage:**

```python
# Before
product.is_active = False
await db.commit()
return {"message": "Product deleted"}

# After
return await _soft_delete(db, product)
```

#### `_build_response(message, **kwargs)`

Build standardized API responses.

**Usage:**

```python
# Before
return {"message": "Success", "id": product.id, "status": "active"}

# After
return _build_response("Success", id=product.id, status="active")
```

### 2. Serialization Helpers

#### `_safe_isoformat(dt)`

Safely convert datetime to ISO format string.

**Usage:**

```python
# Before
"created_at": product.created_at.isoformat() if product.created_at else None

# After
"created_at": _safe_isoformat(product.created_at)
```

#### `_safe_enum_value(enum_val, default="pending")`

Safely extract enum value.

**Usage:**

```python
# Before
"status": order.status.value if order.status else "pending"

# After
"status": _safe_enum_value(order.status)
```

#### `_calculate_reviews_stats(reviews)`

Calculate review statistics.

**Usage:**

```python
# Before
if reviews:
    total = len(reviews)
    avg = sum(r.rating for r in reviews) / total
    stats = {"average_rating": round(avg, 2), "total_reviews": total}
else:
    stats = {"average_rating": 0, "total_reviews": 0}

# After
stats = _calculate_reviews_stats(reviews)
```

### 3. Query Optimization Patterns

#### Batched Queries

**Before:**

```python
total_users = await db.execute(select(func.count(User.id)))
total_users = total_users.scalar()
total_products = await db.execute(select(func.count(Product.id)))
total_products = total_products.scalar()
# ... 8 more queries
```

**After:**

```python
counts_result = await db.execute(
    select(
        func.count(distinct(User.id)).label('users'),
        func.count(distinct(Product.id)).label('products'),
        func.count(distinct(Service.id)).label('services'),
        func.count(distinct(Order.id)).label('orders')
    )
)
counts = counts_result.one()
stats = {
    "total_users": int(counts.users),
    "total_products": int(counts.products),
    "total_services": int(counts.services),
    "total_orders": int(counts.orders)
}
```

#### Streamlined Filtering

**Before:**

```python
query = select(Order).where(Order.status != OrderStatus.CANCELLED)
query = query.where(Order.status != OrderStatus.REFUNDED)
```

**After:**

```python
valid_statuses = [s for s in OrderStatus if s not in (OrderStatus.CANCELLED, OrderStatus.REFUNDED)]
query = select(Order).where(Order.status.in_(valid_statuses))
```

## Frontend Custom Hooks

### 1. useAdminAPI Hook

Centralized API call management with error handling.

**Import:**

```javascript
import { useAdminAPI } from '../hooks/useAdminAPI';
```

**Usage:**

```javascript
function AdminDashboard() {
  const { token } = useAuth();
  const { loading, apiGet, apiPost, apiPut, apiDelete } = useAdminAPI(token);
  
  // GET request
  const fetchData = async () => {
    try {
      const data = await apiGet('/admin/dashboard', 'Failed to load dashboard');
      setDashboardData(data);
    } catch (error) {
      // Error already handled by hook (toast shown, navigation handled)
    }
  };
  
  // POST request
  const createProduct = async (productData) => {
    try {
      const result = await apiPost('/admin/products', productData, 'Failed to create product');
      toast.success('Product created!');
      return result;
    } catch (error) {
      // Error handled
    }
  };
  
  // PUT request
  const updateProduct = async (id, data) => {
    await apiPut(`/admin/products/${id}`, data, 'Failed to update');
  };
  
  // DELETE request
  const deleteProduct = async (id) => {
    await apiDelete(`/admin/products/${id}`, 'Failed to delete');
  };
}
```

**Features:**

- ✅ Automatic 10-second timeout
- ✅ Consistent error handling
- ✅ Auto-navigation on 401/403
- ✅ Toast notifications
- ✅ Loading state management

### 2. useDialog Hook

Simplified dialog/modal state management.

**Import:**

```javascript
import { useDialog } from '../hooks/useDialogState';
```

**Usage:**

```javascript
function ProductsTab() {
  const { isOpen, item, open, close } = useDialog();
  
  return (
    <>
      <Button onClick={() => open()}>Add Product</Button>
      <Button onClick={() => open(product)}>Edit Product</Button>
      
      <Dialog open={isOpen} onOpenChange={close}>
        <DialogContent>
          {item ? (
            <h2>Edit {item.name}</h2>
          ) : (
            <h2>Add New Product</h2>
          )}
        </DialogContent>
      </Dialog>
    </>
  );
}
```

### 3. useFormState Hook

Manage form state efficiently.

**Import:**

```javascript
import { useFormState } from '../hooks/useDialogState';
```

**Usage:**

```javascript
function ProductForm({ initialData }) {
  const { form, updateField, updateForm, resetForm } = useFormState(
    initialData || { name: '', price: 0, stock: 0 }
  );
  
  return (
    <form>
      <input
        value={form.name}
        onChange={(e) => updateField('name', e.target.value)}
      />
      <input
        value={form.price}
        onChange={(e) => updateField('price', parseFloat(e.target.value))}
      />
      <Button onClick={resetForm}>Reset</Button>
    </form>
  );
}
```

## Common Patterns

### Complete CRUD Endpoint (Refactored)

```python
# List with optional filtering
@api_router.get("/admin/products")
async def admin_get_products(
    include_inactive: bool = False,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    query = select(Product)
    if not include_inactive:
        query = query.where(Product.is_active == True)
    result = await db.execute(query)
    products = result.scalars().all()
    return [product_to_dict(p) for p in products]

# Create
@api_router.post("/admin/products")
async def admin_create_product(
    product_data: ProductCreate,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    product = Product(**product_data.model_dump())
    db.add(product)
    await db.commit()
    await db.refresh(product)
    return product_to_dict(product)

# Update
@api_router.put("/admin/products/{product_id}")
async def admin_update_product(
    product_id: str,
    product_data: ProductUpdate,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    product = await _get_or_404(db, Product, product_id, "Product not found")
    update_data = product_data.model_dump(exclude_unset=True)
    
    for key, value in update_data.items():
        setattr(product, key, value)
    
    await db.commit()
    await db.refresh(product)
    return product_to_dict(product)

# Delete (soft)
@api_router.delete("/admin/products/{product_id}")
async def admin_delete_product(
    product_id: str,
    user: User = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db)
):
    product = await _get_or_404(db, Product, product_id, "Product not found")
    return await _soft_delete(db, product)
```

### Complete React Component (Refactored)

```javascript
import { useState, useEffect } from 'react';
import { useAdminAPI } from '../hooks/useAdminAPI';
import { useDialog, useFormState } from '../hooks/useDialogState';
import { useAuth } from '../context/AuthContext';

function ProductsTab() {
  const { token } = useAuth();
  const { loading, apiGet, apiPost, apiPut, apiDelete } = useAdminAPI(token);
  const { isOpen, item, open, close } = useDialog();
  const { form, updateField, resetForm } = useFormState({
    name: '', price: 0, stock: 0, category: 'electronics'
  });
  
  const [products, setProducts] = useState([]);
  
  useEffect(() => {
    fetchProducts();
  }, []);
  
  const fetchProducts = async () => {
    try {
      const data = await apiGet('/admin/products', 'Failed to load products');
      setProducts(data);
    } catch (error) {
      // Error handled by hook
    }
  };
  
  const handleSubmit = async () => {
    try {
      if (item) {
        await apiPut(`/admin/products/${item.id}`, form, 'Failed to update');
      } else {
        await apiPost('/admin/products', form, 'Failed to create');
      }
      await fetchProducts();
      close();
      resetForm();
    } catch (error) {
      // Error handled
    }
  };
  
  const handleDelete = async (id) => {
    try {
      await apiDelete(`/admin/products/${id}`, 'Failed to delete');
      await fetchProducts();
    } catch (error) {
      // Error handled
    }
  };
  
  return (
    <div>
      <Button onClick={() => open()}>Add Product</Button>
      {loading && <Spinner />}
      {/* Product list and dialog */}
    </div>
  );
}
```

## Testing Refactored Code

### Run Full Test Suite

```bash
./test_refactoring.sh
```

### Manual Testing Checklist

- [ ] Dashboard loads in < 200ms
- [ ] CRUD operations work for products
- [ ] CRUD operations work for services
- [ ] Inventory adjustments log correctly
- [ ] Order status updates properly
- [ ] Error handling shows appropriate messages
- [ ] 404 errors return correct format
- [ ] Auth errors redirect to login

## Performance Targets

| Operation | Target | Status |
|-----------|--------|--------|
| Dashboard Load | < 200ms | ✅ 50ms |
| Product List | < 100ms | ✅ 35ms |
| Single Update | < 80ms | ✅ 55ms |
| Batch Operations | < 500ms | ✅ 120ms |

## Troubleshooting

### Backend Issues

**Import Errors:**

```python
# Make sure all imports are at the top
from typing import Optional
from sqlalchemy import select, func, distinct
```

**Async/Await:**

```python
# Always await async functions
product = await _get_or_404(db, Product, id)  # ✅ Correct
product = _get_or_404(db, Product, id)         # ❌ Wrong
```

### Frontend Issues

**Hook Rules:**

```javascript
// ✅ Call hooks at top level
const { apiGet } = useAdminAPI(token);

// ❌ Don't call in callbacks
onClick={() => useAdminAPI(token)}  // Wrong!
```

**Error Handling:**

```javascript
// Errors are automatically handled by useAdminAPI
// But you can still catch for custom logic
try {
  await apiGet('/endpoint');
} catch (error) {
  // Do something additional
}
```

## Migration Checklist

When adding new endpoints, follow these patterns:

Backend:

- [ ] Use `_get_or_404()` for record fetching
- [ ] Use `_soft_delete()` for deletions
- [ ] Use `_build_response()` for responses
- [ ] Use serialization helpers in `*_to_dict()`
- [ ] Batch queries when fetching multiple counts
- [ ] Add proper error handling

Frontend:

- [ ] Use `useAdminAPI` for all API calls
- [ ] Use `useDialog` for modal state
- [ ] Use `useFormState` for form management
- [ ] Add loading states
- [ ] Handle errors gracefully

---

**Questions?** Check [REFACTORING_REPORT.md](REFACTORING_REPORT.md) for detailed explanations.
