# Hooks Library

Reusable React hooks for common patterns in the Mawidi application.

## Available Hooks

### `useApiRequest`

Generic hook for API requests with built-in loading state, error handling, CSRF token management, and automatic retry logic.

#### Features

- Automatic CSRF token fetching and caching
- Loading and error state management
- Type-safe response handling
- Optional retry on network failure
- Callback hooks for request lifecycle
- Convenience wrappers for common HTTP methods

#### Basic Usage

```typescript
import { useApiRequest } from '@/lib/hooks/useApiRequest';

function MyComponent() {
  const { execute, loading, error, data } = useApiRequest<{ userId: string }>();

  const handleSubmit = async () => {
    const result = await execute('/api/user/update', {
      method: 'PUT',
      body: JSON.stringify({ name: 'John' }),
    });

    if (result) {
      console.log('User ID:', result.userId);
    }
  };

  return (
    <div>
      <button onClick={handleSubmit} disabled={loading}>
        {loading ? 'Saving...' : 'Save'}
      </button>
      {error && <p className="text-red-500">{error}</p>}
    </div>
  );
}
```

#### Advanced Usage with Retry

```typescript
const { execute, loading, error } = useApiRequest<PreferencesData>();

const savePreferences = async () => {
  await execute('/api/user/preferences', {
    method: 'PUT',
    body: JSON.stringify(preferences),
    enableRetry: true,
    maxRetries: 3,
    retryDelay: 1000, // 1 second between retries
    onSuccess: (data) => {
      toast.success('Preferences saved!');
    },
    onError: (err) => {
      toast.error(err.message);
    },
  });
};
```

#### CSRF Token Handling

CSRF tokens are automatically included for PUT, POST, DELETE, and PATCH requests. The token is cached for 5 minutes to reduce server requests.

```typescript
// CSRF token automatically added to headers
const result = await execute('/api/user/preferences', {
  method: 'PUT',
  body: JSON.stringify(data),
});

// Disable CSRF for specific requests (not recommended)
const result = await execute('/api/public/data', {
  method: 'POST',
  includeCsrfToken: false,
});
```

#### Convenience Hooks

##### `useApiGet`

```typescript
import { useApiGet } from '@/lib/hooks/useApiRequest';

function UsersList() {
  const { data, loading, error, refetch } = useApiGet<User[]>('/api/users');

  useEffect(() => {
    refetch();
  }, []);

  if (loading) return <Spinner />;
  if (error) return <Error message={error} />;

  return (
    <ul>
      {data?.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}
```

##### `useApiPost`

```typescript
import { useApiPost } from '@/lib/hooks/useApiRequest';

function CreateBooking() {
  const { submit, loading, error } = useApiPost<{ id: string }>('/api/bookings');

  const handleCreate = async (formData: BookingData) => {
    const result = await submit(formData);
    if (result) {
      router.push(`/bookings/${result.id}`);
    }
  };

  return (
    <form onSubmit={handleCreate}>
      {/* form fields */}
      <button type="submit" disabled={loading}>Create</button>
      {error && <p>{error}</p>}
    </form>
  );
}
```

##### `useApiPut`

```typescript
import { useApiPut } from '@/lib/hooks/useApiRequest';

function PreferencesForm() {
  const { update, loading } = useApiPut<Preferences>('/api/user/preferences');

  const handleSave = async () => {
    await update(preferences, {
      onSuccess: () => toast.success('Saved!'),
    });
  };

  return (
    <button onClick={handleSave} disabled={loading}>
      {loading ? 'Saving...' : 'Save Changes'}
    </button>
  );
}
```

##### `useApiDelete`

```typescript
import { useApiDelete } from '@/lib/hooks/useApiRequest';

function DeleteButton({ bookingId }: { bookingId: string }) {
  const { remove, loading } = useApiDelete();

  const handleDelete = async () => {
    if (confirm('Are you sure?')) {
      await remove(`/api/bookings/${bookingId}`, {
        onSuccess: () => {
          toast.success('Booking deleted');
          router.refresh();
        },
      });
    }
  };

  return (
    <button onClick={handleDelete} disabled={loading}>
      {loading ? 'Deleting...' : 'Delete'}
    </button>
  );
}
```

#### API Reference

##### `UseApiRequestReturn<T>`

| Property | Type | Description |
|----------|------|-------------|
| `execute` | `(url: string, options?: ApiRequestOptions) => Promise<T \| null>` | Execute API request |
| `loading` | `boolean` | Loading state |
| `error` | `string \| null` | Error message if request failed |
| `data` | `T \| null` | Response data if successful |
| `clearError` | `() => void` | Clear error state |
| `reset` | `() => void` | Reset all state to initial values |

##### `ApiRequestOptions`

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `includeCsrfToken` | `boolean` | `true` for PUT/POST/DELETE | Include CSRF token in headers |
| `enableRetry` | `boolean` | `false` | Enable automatic retry on failure |
| `maxRetries` | `number` | `2` | Maximum retry attempts |
| `retryDelay` | `number` | `1000` | Delay between retries (ms) |
| `onRequest` | `() => void` | - | Callback before request |
| `onSuccess` | `(data: any) => void` | - | Callback on success |
| `onError` | `(error: Error) => void` | - | Callback on error |

## Best Practices

1. **Type Safety**: Always provide type parameters for better IDE support
   ```typescript
   const { data } = useApiRequest<UserPreferences>();
   ```

2. **Error Handling**: Display errors to users
   ```typescript
   {error && (
     <div className="text-red-500 text-sm mt-2">
       {error}
     </div>
   )}
   ```

3. **Loading States**: Disable buttons during requests
   ```typescript
   <button disabled={loading}>
     {loading ? 'Saving...' : 'Save'}
   </button>
   ```

4. **Cleanup**: Use `reset()` when component unmounts or form is cleared
   ```typescript
   useEffect(() => {
     return () => reset();
   }, []);
   ```

5. **Retry Logic**: Use for network requests that might fail temporarily
   ```typescript
   execute(url, { enableRetry: true, maxRetries: 3 });
   ```

## Common Patterns

### Form Submission with Validation

```typescript
function PreferencesForm() {
  const { execute, loading, error } = useApiRequest<Preferences>();
  const [formData, setFormData] = useState<Preferences>(initialData);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const result = await execute('/api/user/preferences', {
      method: 'PUT',
      body: JSON.stringify(formData),
      onSuccess: () => {
        toast.success('Preferences saved');
      },
      onError: (err) => {
        toast.error(err.message);
      },
    });

    if (result) {
      setFormData(result); // Update with server response
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* form fields */}
      <button type="submit" disabled={loading}>
        {loading ? 'Saving...' : 'Save Changes'}
      </button>
      {error && <ErrorMessage message={error} />}
    </form>
  );
}
```

### Polling with Auto-Refresh

```typescript
function StatusMonitor() {
  const { refetch, data, loading } = useApiGet<Status>('/api/status');

  useEffect(() => {
    const interval = setInterval(() => {
      refetch();
    }, 5000); // Poll every 5 seconds

    return () => clearInterval(interval);
  }, [refetch]);

  return <StatusDisplay status={data} loading={loading} />;
}
```

### Optimistic Updates

```typescript
function ToggleSwitch({ id, initialValue }: Props) {
  const [value, setValue] = useState(initialValue);
  const { execute } = useApiRequest();

  const handleToggle = async () => {
    const newValue = !value;
    setValue(newValue); // Optimistic update

    const result = await execute(`/api/items/${id}`, {
      method: 'PUT',
      body: JSON.stringify({ enabled: newValue }),
      onError: () => {
        setValue(value); // Revert on error
        toast.error('Failed to update');
      },
    });
  };

  return <Switch checked={value} onChange={handleToggle} />;
}
```
