# Quick Reference - Reusable Utilities

Quick copy-paste examples for common patterns.

## API Request Hook

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

const { execute, loading, error } = useApiRequest<ResponseType>();

// In handler
await execute('/api/endpoint', {
  method: 'PUT',
  body: JSON.stringify(data),
});
```

### With Callbacks
```typescript
await execute('/api/endpoint', {
  method: 'POST',
  body: JSON.stringify(data),
  onSuccess: () => toast.success('Success!'),
  onError: (err) => toast.error(err.message),
});
```

### With Retry
```typescript
await execute('/api/endpoint', {
  method: 'GET',
  enableRetry: true,
  maxRetries: 3,
});
```

### Convenience Hooks
```typescript
// GET
const { data, loading, refetch } = useApiGet<User[]>('/api/users');

// POST
const { submit, loading } = useApiPost<{ id: string }>('/api/users');
await submit({ name: 'John' });

// PUT
const { update } = useApiPut<User>('/api/users/123');
await update({ name: 'Jane' });

// DELETE
const { remove } = useApiDelete();
await remove('/api/users/123');
```

---

## API Response Builders

### Import
```typescript
import { APIResponse, HTTP_STATUS } from '@/lib/utils/api-response.util';
```

### Success Responses
```typescript
// Basic success (200)
return APIResponse.success(data);

// With message
return APIResponse.success(data, 'Operation successful');

// Created (201)
return APIResponse.created({ id: '123' }, 'Resource created');

// No content (204)
return APIResponse.noContent();
```

### Error Responses
```typescript
// Bad request (400)
return APIResponse.error('Invalid input');

// Unauthorized (401)
return APIResponse.unauthorized();

// Forbidden (403)
return APIResponse.forbidden('Insufficient permissions');

// Not found (404)
return APIResponse.notFound('User');

// Conflict (409)
return APIResponse.conflict('Email already exists');

// Internal error (500)
return APIResponse.internalError();
```

### Validation Errors
```typescript
// Single field error
return APIResponse.validationError('Invalid email', 'email');

// Multiple field errors
return APIResponse.validationErrors({
  email: 'Invalid format',
  password: 'Too short',
  name: 'Required',
});
```

### Convenience Functions
```typescript
// Quick success
return successResponse(data, 'Success');

// Quick error
return errorResponse('Error message', 400);

// Quick validation error
return validationErrorResponse('Invalid email', 'email');
// OR
return validationErrorResponse({
  email: 'Invalid',
  password: 'Too short',
});
```

### Error Handling Wrapper
```typescript
export async function GET(request: NextRequest) {
  return withErrorHandling(async () => {
    const data = await fetchData();
    return APIResponse.success(data);
  });
}
```

### Paginated Response
```typescript
const users = await prisma.users.findMany({
  skip: (page - 1) * pageSize,
  take: pageSize,
});
const total = await prisma.users.count();

return paginatedResponse(users, page, pageSize, total);
```

---

## Preferences Configuration

### Import
```typescript
import {
  NOTIFICATION_TYPES,
  TIMEZONE_OPTIONS,
  EMAIL_FREQUENCY_OPTIONS,
  DEFAULT_PREFERENCES,
  isValidTimezone,
  isValidLanguage,
} from '@/lib/config/preferences.config';
```

### Render Timezones
```typescript
<select value={timezone} onChange={e => setTimezone(e.target.value)}>
  {TIMEZONE_OPTIONS.map(tz => (
    <option key={tz.value} value={tz.value}>
      {lang === 'ar' ? tz.labelAr : tz.labelEn} ({tz.offset})
    </option>
  ))}
</select>
```

### Render Notification Types
```typescript
{NOTIFICATION_TYPES.map(type => (
  <label key={type.key}>
    <input
      type="checkbox"
      checked={notifications[type.key]}
      onChange={e => handleChange(type.key, e.target.checked)}
    />
    {lang === 'ar' ? type.labelAr : type.labelEn}
  </label>
))}
```

### Render Email Frequency
```typescript
<select value={frequency} onChange={e => setFrequency(e.target.value)}>
  {EMAIL_FREQUENCY_OPTIONS.map(opt => (
    <option key={opt.value} value={opt.value}>
      {lang === 'ar' ? opt.labelAr : opt.labelEn}
    </option>
  ))}
</select>
```

### Create Default Preferences
```typescript
import { DEFAULT_PREFERENCES } from '@/lib/config/preferences.config';

const preferences = await prisma.user_preferences.create({
  data: {
    id: createId(),
    userId: user.id,
    ...DEFAULT_PREFERENCES,
  },
});
```

### Validate Input
```typescript
import {
  isValidTimezone,
  isValidLanguage,
  isValidEmailFrequency,
} from '@/lib/config/preferences.config';

if (!isValidLanguage(language)) {
  return APIResponse.validationError('Invalid language', 'language');
}

if (!isValidTimezone(timezone)) {
  return APIResponse.validationError('Invalid timezone', 'timezone');
}

if (!isValidEmailFrequency(frequency)) {
  return APIResponse.validationError('Invalid email frequency', 'emailFrequency');
}
```

### Get Configuration
```typescript
import {
  getNotificationTypeConfig,
  getTimezoneConfig,
} from '@/lib/config/preferences.config';

const notifConfig = getNotificationTypeConfig('bookings');
console.log(notifConfig?.labelEn); // "New bookings"

const tzConfig = getTimezoneConfig('Asia/Qatar');
console.log(tzConfig?.offset); // "GMT+3"
```

---

## Complete Form Example

```typescript
'use client';

import { useState } from 'react';
import { useApiPut } from '@/lib/hooks/useApiRequest';
import { TIMEZONE_OPTIONS, NOTIFICATION_TYPES } from '@/lib/config/preferences.config';
import type { Lang } from '@/lib/config';

interface Props {
  lang: Lang;
}

export default function PreferencesForm({ lang }: Props) {
  const { update, loading, error } = useApiPut('/api/user/preferences');
  const [preferences, setPreferences] = useState({
    timezone: 'Asia/Qatar',
    emailNotifications: {
      bookings: true,
      reminders: true,
      payments: true,
      marketing: false,
      security: true,
      weeklyReport: false,
    },
  });

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

  const isAr = lang === 'ar';

  return (
    <form onSubmit={(e) => { e.preventDefault(); handleSave(); }}>
      {/* Timezone */}
      <select
        value={preferences.timezone}
        onChange={(e) => setPreferences({ ...preferences, timezone: e.target.value })}
      >
        {TIMEZONE_OPTIONS.map(tz => (
          <option key={tz.value} value={tz.value}>
            {isAr ? tz.labelAr : tz.labelEn} ({tz.offset})
          </option>
        ))}
      </select>

      {/* Notifications */}
      {NOTIFICATION_TYPES.map(type => (
        <label key={type.key}>
          <input
            type="checkbox"
            checked={preferences.emailNotifications[type.key]}
            onChange={(e) => setPreferences({
              ...preferences,
              emailNotifications: {
                ...preferences.emailNotifications,
                [type.key]: e.target.checked,
              },
            })}
          />
          {isAr ? type.labelAr : type.labelEn}
        </label>
      ))}

      {/* Error */}
      {error && <p className="text-red-500">{error}</p>}

      {/* Submit */}
      <button type="submit" disabled={loading}>
        {loading ? (isAr ? 'جاري الحفظ...' : 'Saving...') : (isAr ? 'حفظ' : 'Save')}
      </button>
    </form>
  );
}
```

---

## Complete API Route Example

```typescript
import { NextRequest } from 'next/server';
import { APIResponse, withErrorHandling } from '@/lib/utils/api-response.util';
import { isValidTimezone, DEFAULT_PREFERENCES } from '@/lib/config/preferences.config';
import { auth } from '@/lib/auth';
import { prisma } from '@/lib/db';
import { getAuthenticatedEmail } from '@/lib/utils/auth-helpers.util';

export async function PUT(request: NextRequest) {
  return withErrorHandling(async () => {
    const email = await getAuthenticatedEmail(request, auth);
    if (!email) {
      return APIResponse.unauthorized();
    }

    const body = await request.json();
    const { timezone, emailNotifications } = body;

    // Validate
    if (timezone && !isValidTimezone(timezone)) {
      return APIResponse.validationError('Invalid timezone', 'timezone');
    }

    // Update
    const preferences = await prisma.user_preferences.update({
      where: { email },
      data: {
        timezone,
        emailNotifications,
        updatedAt: new Date(),
      },
    });

    return APIResponse.success(preferences, 'Preferences updated');
  });
}

export async function GET(request: NextRequest) {
  return withErrorHandling(async () => {
    const email = await getAuthenticatedEmail(request, auth);
    if (!email) {
      return APIResponse.unauthorized();
    }

    const user = await prisma.users.findUnique({
      where: { email },
      include: { user_preferences: true },
    });

    if (!user) {
      return APIResponse.notFound('User');
    }

    // Create defaults if not exists
    if (!user.user_preferences) {
      const prefs = await prisma.user_preferences.create({
        data: {
          userId: user.id,
          ...DEFAULT_PREFERENCES,
        },
      });
      return APIResponse.created(prefs);
    }

    return APIResponse.success(user.user_preferences);
  });
}
```

---

## Testing Examples

### Component Test
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import PreferencesForm from './PreferencesForm';

// Mock the hook
jest.mock('@/lib/hooks/useApiRequest', () => ({
  useApiPut: () => ({
    update: jest.fn().mockResolvedValue({ success: true }),
    loading: false,
    error: null,
  }),
}));

test('saves preferences', async () => {
  render(<PreferencesForm lang="en" />);

  const saveButton = screen.getByText('Save');
  fireEvent.click(saveButton);

  await waitFor(() => {
    expect(screen.getByText('Saved!')).toBeInTheDocument();
  });
});
```

### API Route Test
```typescript
import { GET, PUT } from './route';
import { NextRequest } from 'next/server';

describe('Preferences API', () => {
  it('returns 401 if not authenticated', async () => {
    const request = new NextRequest('http://localhost:3000/api/user/preferences');
    const response = await GET(request);
    expect(response.status).toBe(401);
  });

  it('validates timezone', async () => {
    const request = new NextRequest('http://localhost:3000/api/user/preferences', {
      method: 'PUT',
      body: JSON.stringify({ timezone: 'Invalid/Timezone' }),
    });
    const response = await PUT(request);
    expect(response.status).toBe(400);
  });
});
```

---

## Common Patterns

### Loading State
```typescript
{loading && <Spinner />}
{!loading && <Content />}
```

### Error Display
```typescript
{error && (
  <div className="bg-red-50 border border-red-200 p-3 rounded">
    <p className="text-red-700 text-sm">{error}</p>
  </div>
)}
```

### Success Message
```typescript
{success && (
  <div className="bg-green-50 border border-green-200 p-3 rounded">
    <p className="text-green-700 text-sm">Saved successfully!</p>
  </div>
)}
```

### Disabled Button
```typescript
<button
  disabled={loading || !hasChanges}
  className="disabled:opacity-50 disabled:cursor-not-allowed"
>
  {loading ? 'Saving...' : 'Save'}
</button>
```
