# Quick Start Guide - Missio Customer API

## For Frontend Developers

### Prerequisites
1. Get your company hash from the backend team
2. Import the Postman collection: `postman/Missio-Shop-API.postman_collection.json`
3. Set up environment variables in Postman

### Setup in Postman

1. **Import Collection:**
   - File → Import → Select `Missio-Shop-API.postman_collection.json`

2. **Set Variables:**
   - Click on the collection → Variables tab
   - Set `base_url`: Your API URL (e.g., `http://portal.missio.local.io`)
   - Set `c_hash`: Your company hash from the database
   - `token` will auto-populate after login/signup

3. **Test the Flow:**
   - Run `Signup` or `Login` - token auto-captures
   - Try `Get Profile` to verify authentication works
   - Test other endpoints

---

## Quick Integration Examples

### React/JavaScript

```javascript
// config.js
export const API_CONFIG = {
  baseURL: 'https://your-api.com/api',
  companyHash: 'your-company-hash-here'
};

// api.js
import { API_CONFIG } from './config';

class CustomerAPI {
  constructor() {
    this.baseURL = API_CONFIG.baseURL;
    this.companyHash = API_CONFIG.companyHash;
  }

  async signup(userData) {
    const response = await fetch(`${this.baseURL}/auth/signup`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Company-Hash': this.companyHash
      },
      body: JSON.stringify(userData)
    });
    
    const data = await response.json();
    
    if (data.status === 'success') {
      localStorage.setItem('token', data.access_token);
      return data;
    }
    throw new Error(data.message || 'Signup failed');
  }

  async login(credentials) {
    const response = await fetch(`${this.baseURL}/auth/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Company-Hash': this.companyHash
      },
      body: JSON.stringify(credentials)
    });
    
    const data = await response.json();
    
    if (data.status === 'success') {
      localStorage.setItem('token', data.access_token);
      return data;
    }
    throw new Error(data.message || 'Login failed');
  }

  async getProfile() {
    const token = localStorage.getItem('token');
    
    const response = await fetch(`${this.baseURL}/me`, {
      headers: {
        'Authorization': `Bearer ${token}`,
        'X-Company-Hash': this.companyHash
      }
    });
    
    const data = await response.json();
    
    if (data.status === 'success') {
      return data.customer;
    }
    throw new Error(data.message || 'Failed to get profile');
  }

  async updateProfile(updates) {
    const token = localStorage.getItem('token');
    
    const response = await fetch(`${this.baseURL}/me`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
        'X-Company-Hash': this.companyHash
      },
      body: JSON.stringify(updates)
    });
    
    const data = await response.json();
    
    if (data.status === 'success') {
      return data.customer;
    }
    throw new Error(data.message || 'Failed to update profile');
  }

  async logout() {
    const token = localStorage.getItem('token');
    
    await fetch(`${this.baseURL}/auth/logout`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'X-Company-Hash': this.companyHash
      }
    });
    
    localStorage.removeItem('token');
  }
}

export default new CustomerAPI();

// Usage in components
import api from './api';

// Signup
try {
  const result = await api.signup({
    fname: 'John',
    lname: 'Doe',
    email: 'john@example.com',
    password: 'secret123'
  });
  console.log('Signed up:', result.customer);
} catch (error) {
  console.error('Signup error:', error.message);
}

// Login
try {
  const result = await api.login({
    email: 'john@example.com',
    password: 'secret123'
  });
  console.log('Logged in:', result.customer);
} catch (error) {
  console.error('Login error:', error.message);
}
```

### React Native

```javascript
// api/customer.js
import AsyncStorage from '@react-native-async-storage/async-storage';

const API_BASE = 'https://your-api.com/api';
const COMPANY_HASH = 'your-company-hash';

export const customerAPI = {
  async signup(userData) {
    try {
      const response = await fetch(`${API_BASE}/auth/signup`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Company-Hash': COMPANY_HASH
        },
        body: JSON.stringify(userData)
      });
      
      const data = await response.json();
      
      if (data.status === 'success') {
        await AsyncStorage.setItem('token', data.access_token);
        await AsyncStorage.setItem('customer', JSON.stringify(data.customer));
        return data;
      }
      throw new Error(data.message);
    } catch (error) {
      console.error('Signup error:', error);
      throw error;
    }
  },

  async login(email, password) {
    try {
      const response = await fetch(`${API_BASE}/auth/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Company-Hash': COMPANY_HASH
        },
        body: JSON.stringify({ email, password })
      });
      
      const data = await response.json();
      
      if (data.status === 'success') {
        await AsyncStorage.setItem('token', data.access_token);
        await AsyncStorage.setItem('customer', JSON.stringify(data.customer));
        return data;
      }
      throw new Error(data.message);
    } catch (error) {
      console.error('Login error:', error);
      throw error;
    }
  },

  async getProfile() {
    try {
      const token = await AsyncStorage.getItem('token');
      
      const response = await fetch(`${API_BASE}/me`, {
        headers: {
          'Authorization': `Bearer ${token}`,
          'X-Company-Hash': COMPANY_HASH
        }
      });
      
      const data = await response.json();
      
      if (data.status === 'success') {
        await AsyncStorage.setItem('customer', JSON.stringify(data.customer));
        return data.customer;
      }
      throw new Error(data.message);
    } catch (error) {
      console.error('Get profile error:', error);
      throw error;
    }
  },

  async logout() {
    try {
      const token = await AsyncStorage.getItem('token');
      
      await fetch(`${API_BASE}/auth/logout`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'X-Company-Hash': COMPANY_HASH
        }
      });
      
      await AsyncStorage.multiRemove(['token', 'customer']);
    } catch (error) {
      console.error('Logout error:', error);
      // Clear local data even if API call fails
      await AsyncStorage.multiRemove(['token', 'customer']);
    }
  }
};
```

### Flutter/Dart

```dart
// api/customer_api.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';

class CustomerAPI {
  static const String baseURL = 'https://your-api.com/api';
  static const String companyHash = 'your-company-hash';

  Future<Map<String, dynamic>> signup(Map<String, dynamic> userData) async {
    final response = await http.post(
      Uri.parse('$baseURL/auth/signup'),
      headers: {
        'Content-Type': 'application/json',
        'X-Company-Hash': companyHash,
      },
      body: jsonEncode(userData),
    );

    final data = jsonDecode(response.body);

    if (data['status'] == 'success') {
      final prefs = await SharedPreferences.getInstance();
      await prefs.setString('token', data['access_token']);
      await prefs.setString('customer', jsonEncode(data['customer']));
      return data;
    }

    throw Exception(data['message'] ?? 'Signup failed');
  }

  Future<Map<String, dynamic>> login(String email, String password) async {
    final response = await http.post(
      Uri.parse('$baseURL/auth/login'),
      headers: {
        'Content-Type': 'application/json',
        'X-Company-Hash': companyHash,
      },
      body: jsonEncode({
        'email': email,
        'password': password,
      }),
    );

    final data = jsonDecode(response.body);

    if (data['status'] == 'success') {
      final prefs = await SharedPreferences.getInstance();
      await prefs.setString('token', data['access_token']);
      await prefs.setString('customer', jsonEncode(data['customer']));
      return data;
    }

    throw Exception(data['message'] ?? 'Login failed');
  }

  Future<Map<String, dynamic>> getProfile() async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString('token');

    final response = await http.get(
      Uri.parse('$baseURL/me'),
      headers: {
        'Authorization': 'Bearer $token',
        'X-Company-Hash': companyHash,
      },
    );

    final data = jsonDecode(response.body);

    if (data['status'] == 'success') {
      await prefs.setString('customer', jsonEncode(data['customer']));
      return data['customer'];
    }

    throw Exception(data['message'] ?? 'Failed to get profile');
  }

  Future<void> logout() async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString('token');

    await http.post(
      Uri.parse('$baseURL/auth/logout'),
      headers: {
        'Authorization': 'Bearer $token',
        'X-Company-Hash': companyHash,
      },
    );

    await prefs.remove('token');
    await prefs.remove('customer');
  }
}
```

---

## Important Notes

### 1. Required Headers
**Every request MUST include:**
```
X-Company-Hash: your-company-hash
```

**Authenticated requests also need:**
```
Authorization: Bearer your-token-here
```

### 2. Error Handling

Always check the `status` field in responses:

```javascript
const data = await response.json();

if (data.status === 'success') {
  // Handle success
  console.log(data.message);
} else {
  // Handle error
  console.error(data.message);
  
  // Check for validation errors
  if (data.errors) {
    Object.keys(data.errors).forEach(field => {
      console.log(`${field}: ${data.errors[field].join(', ')}`);
    });
  }
}
```

### 3. HTTP Status Codes

| Code | Meaning | Action |
|------|---------|--------|
| 200 | Success | Process the response data |
| 401 | Unauthorized | Redirect to login, clear token |
| 403 | Forbidden | Show "account inactive" message |
| 422 | Validation Error | Display validation errors to user |
| 500 | Server Error | Show generic error, retry later |

### 4. Customer Status

Check `customer.status`:
- `"1"` = Active (can use app)
- `"0"` = Inactive (login returns 403)

### 5. Token Management

**Security Best Practices:**
- **Web:** Use httpOnly cookies or secure storage (not localStorage for production)
- **Mobile:** Use secure storage (AsyncStorage for React Native, SharedPreferences for Flutter)
- **Always** send token in Authorization header
- Clear token on logout or 401 errors
- Implement token refresh if needed

### 6. Testing Checklist

- [ ] Signup with valid data
- [ ] Signup with duplicate email (should fail)
- [ ] Login with correct credentials
- [ ] Login with wrong password (should fail)
- [ ] Get profile with valid token
- [ ] Get profile without token (should fail)
- [ ] Update profile
- [ ] Update addresses
- [ ] Refresh token
- [ ] Logout

---

## Common Issues & Solutions

### Issue: "Missing or invalid X-Company-Hash header"
**Solution:** Ensure `X-Company-Hash` header is included in every request.

### Issue: 401 Unauthorized
**Solution:** 
- Check if token is valid
- Verify token is sent in `Authorization: Bearer {token}` format
- Token may have been revoked, login again

### Issue: Validation errors
**Solution:** Check the `errors` object in response and display to user.

### Issue: CORS errors (web only)
**Solution:** Backend needs to configure CORS headers. Contact backend team.

---

## Support

- **Full Documentation:** `docs/API_DOCUMENTATION.md`
- **Postman Collection:** `postman/Missio-Shop-API.postman_collection.json`
- **Environments:** `postman/` folder contains Local, Staging, and Prod environments

For issues or questions, contact the backend development team.
