# Frontend Utility Hooks & Components Guide

Complete TypeScript/TSX utilities that mirror the backend helpers and make frontend development much easier.

## Table of Contents

1. [Hooks](#hooks)
   - [usePaginatedData](#usepaginateddata)
   - [useApiMutation](#useapimutation)
   - [useFormValidation](#useformvalidation)
   - [useQueryBuilder](#usequerybuilder)
   - [useToast](#usetoast)
   - [useBatchSelection](#usebatchselection)
2. [Components](#components)
   - [DataTable](#datatable)
   - [ToastContainer](#toastcontainer)
3. [Utilities](#utilities)
   - [Export Functions](#export-functions)
4. [Complete Example](#complete-example)

---

## Hooks

### usePaginatedData

**Purpose:** Fetch paginated data with search, sort, and filters in one line.

**Features:**
- Automatic pagination management
- Search functionality
- Sorting
- Filtering
- Loading and error states
- Works seamlessly with backend QueryParser

```tsx
import { usePaginatedData } from '../hooks/usePaginatedData';

interface Article {
  id: number;
  title: string;
  published: boolean;
}

function ArticleList() {
  const {
    data: articles,
    meta,
    loading,
    error,
    setPage,
    setSearch,
    setSort,
    setFilters,
    refresh,
  } = usePaginatedData<Article>('/articles', {
    page_size: 20,
  });

  return (
    <div>
      <input 
        type="text" 
        onChange={(e) => setSearch(e.target.value)} 
        placeholder="Search..." 
      />
      
      <select onChange={(e) => setFilters({ published: e.target.value })}>
        <option value="">All</option>
        <option value="true">Published</option>
        <option value="false">Draft</option>
      </select>

      {loading && <p>Loading...</p>}
      {error && <p>Error: {error}</p>}
      
      <ul>
        {articles.map(article => (
          <li key={article.id}>{article.title}</li>
        ))}
      </ul>

      {meta && (
        <button 
          onClick={() => setPage(meta.page + 1)} 
          disabled={!meta.has_next}
        >
          Next Page
        </button>
      )}
    </div>
  );
}
```

### useApiMutation

**Purpose:** Handle POST, PUT, PATCH, DELETE requests with loading states.

**Features:**
- Automatic loading states
- Error handling
- Success tracking
- TypeScript support

```tsx
import { useApiPost, useApiDelete } from '../hooks/useApiMutation';

function ArticleForm() {
  // Create article
  const { mutate: createArticle, loading, error, success } = useApiPost<Article>('/articles');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const article = await createArticle({
      title: 'New Article',
      content: 'Content here...',
    });
    
    if (article) {
      console.log('Created:', article);
    }
  };

  // Delete article
  const deleteArticle = useApiDelete((data: { id: number }) => `/articles/${data.id}`);

  const handleDelete = async (id: number) => {
    await deleteArticle.mutate({ id });
  };

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit" disabled={loading}>
        {loading ? 'Creating...' : 'Create Article'}
      </button>
      {error && <p className="error">{error}</p>}
      {success && <p className="success">Article created!</p>}
    </form>
  );
}
```

### useFormValidation

**Purpose:** Form validation with built-in rules and error messages.

**Features:**
- Required, min/max length, pattern, email, URL validators
- Custom validators
- Automatic error messages
- Touch tracking
- Easy integration with forms

```tsx
import { useFormValidation } from '../hooks/useFormValidation';

interface ArticleForm {
  title: string;
  content: string;
  email: string;
  url: string;
}

function CreateArticleForm() {
  const {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
  } = useFormValidation<ArticleForm>(
    {
      title: '',
      content: '',
      email: '',
      url: '',
    },
    {
      title: { required: true, min: 3, max: 200 },
      content: { required: true, min: 10 },
      email: { required: true, email: true },
      url: { url: true },
    }
  );

  const onSubmit = async (data: ArticleForm) => {
    console.log('Valid data:', data);
    // Call API here
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <input
          type="text"
          name="title"
          value={values.title}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder="Title"
        />
        {touched.title && errors.title && (
          <span className="error">{errors.title}</span>
        )}
      </div>

      <div>
        <textarea
          name="content"
          value={values.content}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder="Content"
        />
        {touched.content && errors.content && (
          <span className="error">{errors.content}</span>
        )}
      </div>

      <button type="submit">Create Article</button>
    </form>
  );
}
```

### useQueryBuilder

**Purpose:** Build query strings for API calls with filters, search, and sort.

**Features:**
- Filter management
- Search management
- Sort management
- Pagination
- URL-friendly query string generation

```tsx
import { useQueryBuilder } from '../hooks/useQueryBuilder';

function ArticleFilters() {
  const query = useQueryBuilder(20);

  return (
    <div>
      <input
        type="text"
        placeholder="Search..."
        onChange={(e) => query.setSearch(e.target.value)}
      />

      <select onChange={(e) => query.setFilter('published', e.target.value)}>
        <option value="">All</option>
        <option value="true">Published</option>
        <option value="false">Draft</option>
      </select>

      <button onClick={() => query.setSort('created_at', 'desc')}>
        Sort by Date
      </button>

      <p>Query: {query.queryString}</p>
      {/* Use in API call: `/articles?${query.queryString}` */}
    </div>
  );
}
```

### useToast

**Purpose:** Display toast notifications for user feedback.

**Features:**
- Success, error, warning, info types
- Auto-dismiss
- Manual dismiss
- Queue management

```tsx
import { useToast } from '../hooks/useToast';
import { ToastContainer } from '../components/common/ToastContainer';

function App() {
  const toast = useToast();

  const handleSave = async () => {
    try {
      // Save logic
      toast.success('Article saved successfully!');
    } catch (error) {
      toast.error('Failed to save article');
    }
  };

  return (
    <div>
      <ToastContainer toasts={toast.toasts} onDismiss={toast.dismiss} />
      
      <button onClick={handleSave}>Save</button>
      <button onClick={() => toast.info('This is info')}>Show Info</button>
      <button onClick={() => toast.warning('Warning!')}>Show Warning</button>
    </div>
  );
}
```

### useBatchSelection

**Purpose:** Manage selection of multiple items in tables/lists.

**Features:**
- Select/deselect individual items
- Select all / deselect all
- Track selected items
- Get selected IDs or full items

```tsx
import { useBatchSelection } from '../hooks/useBatchSelection';

function ArticleTable() {
  const articles = [
    { id: 1, title: 'Article 1' },
    { id: 2, title: 'Article 2' },
    { id: 3, title: 'Article 3' },
  ];

  const selection = useBatchSelection(articles, 'id');

  const handleBatchDelete = () => {
    const ids = selection.getSelectedIds();
    console.log('Delete articles:', ids);
    // Call batch delete API
  };

  return (
    <div>
      <div>
        <input
          type="checkbox"
          checked={selection.isAllSelected}
          onChange={selection.toggleAll}
        />
        <label>Select All</label>
      </div>

      {articles.map((article) => (
        <div key={article.id}>
          <input
            type="checkbox"
            checked={selection.isSelected(article.id)}
            onChange={() => selection.toggle(article.id)}
          />
          <span>{article.title}</span>
        </div>
      ))}

      {selection.selectedIds.size > 0 && (
        <button onClick={handleBatchDelete}>
          Delete {selection.selectedIds.size} selected
        </button>
      )}
    </div>
  );
}
```

---

## Components

### DataTable

**Purpose:** Feature-rich data table with sorting, selection, and custom rendering.

**Features:**
- Sortable columns
- Row selection (single or multiple)
- Custom cell rendering
- Actions column
- Loading and empty states
- Responsive design

```tsx
import { DataTable, Column } from '../components/common/DataTable';

interface Article {
  id: number;
  title: string;
  published: boolean;
  created_at: string;
}

function ArticleTable() {
  const articles: Article[] = [/* ... */];
  const selection = useBatchSelection(articles, 'id');

  const columns: Column<Article>[] = [
    {
      key: 'id',
      label: 'ID',
      sortable: true,
      width: '80px',
    },
    {
      key: 'title',
      label: 'Title',
      sortable: true,
      render: (article) => (
        <strong>{article.title}</strong>
      ),
    },
    {
      key: 'published',
      label: 'Status',
      render: (article) => (
        <span className={article.published ? 'published' : 'draft'}>
          {article.published ? 'Published' : 'Draft'}
        </span>
      ),
    },
    {
      key: 'created_at',
      label: 'Created',
      sortable: true,
      render: (article) => new Date(article.created_at).toLocaleDateString(),
    },
  ];

  return (
    <DataTable
      data={articles}
      columns={columns}
      selectable
      selectedIds={selection.selectedIds}
      onToggleSelect={selection.toggle}
      onToggleSelectAll={selection.toggleAll}
      isAllSelected={selection.isAllSelected}
      isSomeSelected={selection.isSomeSelected}
      onSort={(field) => console.log('Sort by:', field)}
      actions={(article) => (
        <div>
          <button onClick={() => console.log('Edit', article.id)}>Edit</button>
          <button onClick={() => console.log('Delete', article.id)}>Delete</button>
        </div>
      )}
    />
  );
}
```

### ToastContainer

**Purpose:** Display toast notifications from useToast hook.

```tsx
import { useToast } from '../hooks/useToast';
import { ToastContainer } from '../components/common/ToastContainer';

function App() {
  const toast = useToast();

  return (
    <div>
      <ToastContainer toasts={toast.toasts} onDismiss={toast.dismiss} />
      {/* Your app content */}
    </div>
  );
}
```

---

## Utilities

### Export Functions

**Purpose:** Export data to CSV/JSON files.

```tsx
import {
  exportToCSV,
  exportToJSON,
  exportFromAPI,
  getExportFilename,
  copyToClipboard,
} from '../utils/export';

function ExportButtons() {
  const articles = [
    { id: 1, title: 'Article 1', published: true },
    { id: 2, title: 'Article 2', published: false },
  ];

  // Export to CSV
  const handleExportCSV = () => {
    const filename = getExportFilename('articles', 'csv');
    exportToCSV(articles, filename);
  };

  // Export to JSON
  const handleExportJSON = () => {
    const filename = getExportFilename('articles', 'json');
    exportToJSON(articles, filename);
  };

  // Export from API endpoint
  const handleExportFromAPI = async () => {
    try {
      await exportFromAPI('/articles/export', 'articles.csv', 'csv');
    } catch (error) {
      console.error('Export failed');
    }
  };

  // Copy to clipboard
  const handleCopy = async () => {
    const success = await copyToClipboard(JSON.stringify(articles, null, 2));
    if (success) {
      alert('Copied to clipboard!');
    }
  };

  return (
    <div>
      <button onClick={handleExportCSV}>Export CSV</button>
      <button onClick={handleExportJSON}>Export JSON</button>
      <button onClick={handleExportFromAPI}>Export from API</button>
      <button onClick={handleCopy}>Copy to Clipboard</button>
    </div>
  );
}
```

---

## Complete Example

See `ArticleListExample.tsx` for a complete implementation using all utilities.

**Key Features Demonstrated:**
- ✅ Paginated data fetching with search and filters
- ✅ Batch selection
- ✅ Toast notifications
- ✅ Data table with sorting
- ✅ Export to CSV
- ✅ Delete operations
- ✅ Loading and error states

---

## Benefits

### Before (Without Utilities)

```tsx
// 100+ lines of boilerplate for a list page
function ArticleList() {
  const [articles, setArticles] = useState([]);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [selected, setSelected] = useState([]);
  const [search, setSearch] = useState('');
  
  useEffect(() => {
    setLoading(true);
    fetch(`/api/articles?page=${page}&search=${search}`)
      .then(res => res.json())
      .then(data => {
        setArticles(data.data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [page, search]);

  // More boilerplate...
}
```

### After (With Utilities)

```tsx
// 30 lines with full functionality
function ArticleList() {
  const { data, meta, loading, error, setSearch, setPage } = 
    usePaginatedData('/articles');
  const selection = useBatchSelection(data, 'id');
  const toast = useToast();

  return (
    <div>
      <ToastContainer toasts={toast.toasts} onDismiss={toast.dismiss} />
      <DataTable
        data={data}
        columns={columns}
        loading={loading}
        selectable
        {...selection}
      />
    </div>
  );
}
```

**Result:** 70% less code, more features, better UX!

---

## Files Created

**Hooks:**
1. ✅ `hooks/usePaginatedData.ts` - Paginated data fetching
2. ✅ `hooks/useApiMutation.ts` - API mutations (POST, PUT, DELETE)
3. ✅ `hooks/useFormValidation.ts` - Form validation
4. ✅ `hooks/useQueryBuilder.ts` - Query string builder
5. ✅ `hooks/useToast.ts` - Toast notifications
6. ✅ `hooks/useBatchSelection.ts` - Batch selection

**Components:**
7. ✅ `components/common/DataTable.tsx` - Data table component
8. ✅ `components/common/DataTable.css` - Table styles
9. ✅ `components/common/ToastContainer.tsx` - Toast container
10. ✅ `components/common/ToastContainer.css` - Toast styles

**Utilities:**
11. ✅ `utils/export.ts` - Export functions

**Examples:**
12. ✅ `components/examples/ArticleListExample.tsx` - Complete example
13. ✅ `components/examples/ArticleListExample.css` - Example styles

**Documentation:**
14. ✅ `FRONTEND_UTILITIES_GUIDE.md` - This guide

---

## Quick Reference

```tsx
// Fetch paginated data
const { data, meta, loading, setSearch, setPage } = 
  usePaginatedData<T>('/endpoint');

// API mutations
const { mutate, loading, error } = useApiPost<T>('/endpoint');

// Form validation
const { values, errors, handleChange, handleSubmit } = 
  useFormValidation(initialValues, rules);

// Query builder
const { queryString, setFilter, setSearch, setSort } = useQueryBuilder();

// Toast notifications
const toast = useToast();
toast.success('Success!');
toast.error('Error!');

// Batch selection
const selection = useBatchSelection(items, 'id');
selection.toggle(id);
selection.selectAll();

// Export
exportToCSV(data, 'export.csv');
exportToJSON(data, 'export.json');
```

---

## Integration with Backend

All frontend utilities are designed to work seamlessly with the backend helpers:

| Frontend | Backend | Purpose |
|----------|---------|---------|
| `usePaginatedData` | `Paginator` | Pagination |
| `useQueryBuilder` | `QueryParser` | Filtering/Sorting |
| `useFormValidation` | `Validator` | Validation |
| `useToast` | `Respond` | User Feedback |
| `useBatchSelection` | `BatchOps` | Batch Operations |
| `exportToCSV` | `Exporter` | Data Export |

---

## Best Practices

1. **Always use error boundaries** with data fetching hooks
2. **Debounce search inputs** to avoid excessive API calls
3. **Show loading states** for better UX
4. **Use toast notifications** for user feedback
5. **Implement batch operations** for efficiency
6. **Export functionality** for reporting needs
7. **TypeScript types** for type safety

---

## Next Steps

1. Review the complete example: `ArticleListExample.tsx`
2. Copy patterns for your own components
3. Customize styles to match your design
4. Add more custom validators as needed
5. Extend utilities with project-specific features

**Your frontend development is now easier, faster, and better!** 🚀
