npm package: @mossistudio/hostmails-service
Description: A TypeScript service for handling contact form submissions with validation and API integration
Author: Bonito Fotso
Latest version: 1.0.0

# Contact Service

A TypeScript service for handling contact form submissions with built-in validation and API integration.

## Features

- 📝 Form data validation
- 🔐 Secure API key authentication
- ⚡ Promise-based async/await interface
- 🎯 TypeScript support with full type definitions
- 🛡️ Error handling and detailed error messages
- 📧 Email format validation
- ☎️ Phone number validation

## Installation

```bash
npm install @mossistudio/hostmails-service
```

or

```bash
yarn add @mossistudio/hostmails-service
```

## Usage

### Basic Usage

```typescript
import ContactService from '@mossistudio/hostmails-service';

// Initialize the service
const contactService = new ContactService({
  apiBaseUrl: 'https://mails.f2mb.xyz/api',
  apiKey: 'your-api-key-here',
  timeout: 10000, // optional, default: 10000ms
});

// Prepare form data
const formData = {
  name: 'John Doe',
  email: 'john.doe@example.com',
  subject: 'General Inquiry',
  message: 'Hello, I would like to know more about your services.',
  phone: '+1234567890', // optional
  company: 'Acme Corp', // optional
};

// Validate form data
const validation = contactService.validateFormData(formData);

if (!validation.valid) {
  console.error('Validation errors:', validation.errors);
  return;
}

// Submit the form
try {
  const response = await contactService.submitContactForm(formData);
  console.log('Success:', response.message);
} catch (error) {
  console.error('Error:', error.message);
}
```

### Using with Environment Variables

```typescript
import ContactService from '@mossistudio/hostmails-service';

const contactService = new ContactService({
  apiBaseUrl: process.env.VITE_API_URL,
  apiKey: process.env.VITE_CONTACT_API_KEY,
});
```

### Dynamic Configuration

```typescript
const contactService = new ContactService();

// Set API key later
contactService.setApiKey('your-api-key');

// Update API URL
contactService.setApiBaseUrl('https://api.example.com');
```

### React Example

```typescript
import { useState } from 'react';
import ContactService, { ContactFormData } from '@mossistudio/hostmails-service';

const contactService = new ContactService({
  apiKey: import.meta.env.VITE_CONTACT_API_KEY,
});

function ContactForm() {
  const [formData, setFormData] = useState<ContactFormData>({
    name: '',
    email: '',
    subject: '',
    message: '',
  });
  const [errors, setErrors] = useState<string[]>([]);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    // Validate
    const validation = contactService.validateFormData(formData);
    if (!validation.valid) {
      setErrors(validation.errors);
      return;
    }
    
    // Submit
    setLoading(true);
    try {
      const response = await contactService.submitContactForm(formData);
      alert(response.message);
      // Reset form
      setFormData({ name: '', email: '', subject: '', message: '' });
      setErrors([]);
    } catch (error: any) {
      setErrors([error.message]);
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields here */}
      {errors.length > 0 && (
        <div className="errors">
          {errors.map((error, i) => (
            <p key={i}>{error}</p>
          ))}
        </div>
      )}
      <button type="submit" disabled={loading}>
        {loading ? 'Sending...' : 'Send'}
      </button>
    </form>
  );
}
```

## API

### `ContactService(config?)`

Creates a new instance of ContactService.

**Parameters:**
- `config` (optional): Configuration object
  - `apiBaseUrl` (string): Base URL of the API (default: 'https://mails.f2mb.xyz/api')
  - `apiKey` (string): API key for authentication
  - `timeout` (number): Request timeout in milliseconds (default: 10000)

### `submitContactForm(data: ContactFormData): Promise<ApiResponse>`

Submits contact form data to the API.

**Parameters:**
- `data`: Contact form data object
  - `name` (string, required): Contact's name
  - `email` (string, required): Contact's email
  - `subject` (string, required): Message subject
  - `message` (string, required): Message content
  - `phone` (string, optional): Contact's phone number
  - `company` (string, optional): Contact's company

**Returns:** Promise resolving to ApiResponse

### `validateFormData(data: ContactFormData): ValidationResult`

Validates contact form data before submission.

**Parameters:**
- `data`: Contact form data object

**Returns:** ValidationResult object containing:
- `valid` (boolean): Whether the data is valid
- `errors` (string[]): Array of validation error messages

### `setApiKey(apiKey: string): void`

Updates the API key.

### `setApiBaseUrl(url: string): void`

Updates the API base URL.

## TypeScript Types

```typescript
interface ContactFormData {
  name: string;
  email: string;
  subject: string;
  message: string;
  phone?: string;
  company?: string;
}

interface ApiResponse {
  success: boolean;
  message: string;
  data?: any;
}

interface ApiError {
  message: string;
  status?: number;
  details?: any;
}

interface ValidationResult {
  valid: boolean;
  errors: string[];
}
```

## Error Handling

The service throws detailed error objects that include:
- `message`: Human-readable error message
- `status`: HTTP status code (if applicable)
- `details`: Additional error details from the API

Example error handling:

```typescript
try {
  await contactService.submitContactForm(formData);
} catch (error: any) {
  if (error.status === 0) {
    console.error('Network error:', error.message);
  } else if (error.status === 401) {
    console.error('Authentication error:', error.message);
  } else {
    console.error('Error:', error.message);
  }
}
```

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

For issues and questions, please open an issue on GitHub.