# Client Helper untuk Frontend

Folder ini berisi helper utilities yang dapat digunakan di frontend SAPPS untuk menangani ISP blocking dan connection issues.

## 📁 Files

### ResilientAPIClient.js

API Client yang robust dengan features:

- ✅ Automatic retry dengan exponential backoff
- ✅ Multiple endpoint fallback
- ✅ Connection quality monitoring
- ✅ Offline/online detection
- ✅ Timeout handling
- ✅ Error classification

## 🚀 Cara Menggunakan

### 1. Copy file ke project frontend

```bash
cp client-helpers/ResilientAPIClient.js ../sapps/src/utils/
```

### 2. Import dan initialize

```javascript
import ResilientAPIClient from "@/utils/ResilientAPIClient";

const apiClient = new ResilientAPIClient({
	primaryEndpoint: "https://sapps-api.sapharma.co.id",
	fallbackEndpoints: ["https://sapps-api-backup.sapharma.co.id"],
	maxRetries: 3,
	timeout: 30000,
	onConnectionQualityChange: (quality, latency) => {
		// Update UI connection indicator
		updateConnectionIndicator(quality, latency);
	},
	onOffline: () => {
		showOfflineMessage();
	},
	onOnline: () => {
		hideOfflineMessage();
		retryFailedRequests();
	},
});

export default apiClient;
```

### 3. Gunakan untuk API calls

```javascript
// GET request
const users = await apiClient.get("/sapps/users", {
	headers: {
		Authorization: `Bearer ${token}`,
	},
});

// POST request
const newUser = await apiClient.post("/sapps/users", {
	name: "John Doe",
	email: "john@example.com",
});

// PUT request
const updated = await apiClient.put("/sapps/users/123", {
	name: "Jane Doe",
});

// DELETE request
await apiClient.delete("/sapps/users/123");
```

### 4. Monitor connection

```javascript
// Test connection
const testResult = await apiClient.testConnection();
if (!testResult.success) {
	console.error("Cannot connect to server");
}

// Get current quality
const { quality, latency } = apiClient.getConnectionQuality();
console.log(`Connection: ${quality} (${latency}ms)`);

// Get server health
const health = await apiClient.getHealth();
console.log("Server status:", health.status);
```

## 💡 Integration dengan Axios (Opsional)

Jika sudah menggunakan Axios, bisa buat adapter:

```javascript
import axios from "axios";
import apiClient from "@/utils/apiClient";

// Create Axios instance dengan interceptor
const axiosInstance = axios.create({
	baseURL: apiClient.primaryEndpoint,
});

// Request interceptor
axiosInstance.interceptors.request.use(
	(config) => {
		// Add auth token, etc
		return config;
	},
	(error) => Promise.reject(error)
);

// Response interceptor dengan retry logic
axiosInstance.interceptors.response.use(
	(response) => response,
	async (error) => {
		const { config, response } = error;

		// Implement retry using ResilientAPIClient
		if (!config.__retryCount) {
			config.__retryCount = 0;
		}

		if (config.__retryCount < 3) {
			config.__retryCount++;
			await new Promise((r) => setTimeout(r, 1000 * config.__retryCount));
			return axiosInstance(config);
		}

		return Promise.reject(error);
	}
);
```

## 📊 Connection Quality UI Component

Contoh React component untuk menampilkan status koneksi:

```jsx
import React, { useState, useEffect } from "react";
import apiClient from "@/utils/apiClient";

function ConnectionIndicator() {
	const [quality, setQuality] = useState("unknown");
	const [latency, setLatency] = useState(null);
	const [isOnline, setIsOnline] = useState(true);

	useEffect(() => {
		// Set callback untuk quality changes
		apiClient.onConnectionQualityChange = (q, l) => {
			setQuality(q);
			setLatency(l);
		};

		apiClient.onOffline = () => setIsOnline(false);
		apiClient.onOnline = () => setIsOnline(true);

		// Test connection on mount
		apiClient.testConnection();
	}, []);

	const getColor = () => {
		if (!isOnline) return "red";
		switch (quality) {
			case "excellent":
				return "green";
			case "good":
				return "lightgreen";
			case "fair":
				return "yellow";
			case "poor":
				return "orange";
			default:
				return "gray";
		}
	};

	return (
		<div
			style={{
				position: "fixed",
				bottom: 20,
				right: 20,
				padding: "10px 15px",
				background: getColor(),
				borderRadius: 5,
				color: "white",
			}}
		>
			{isOnline ? (
				<>
					<strong>Connection:</strong> {quality}
					{latency && ` (${Math.round(latency)}ms)`}
				</>
			) : (
				<strong>Offline</strong>
			)}
		</div>
	);
}

export default ConnectionIndicator;
```

## 🔧 Konfigurasi Lanjutan

### Custom Error Handling

```javascript
const apiClient = new ResilientAPIClient({
	// ... config lainnya
});

// Wrap semua calls dengan error handler
async function safeAPICall(fn) {
	try {
		return await fn();
	} catch (error) {
		// Log error
		console.error("API Error:", error);

		// Check if ISP blocking
		if (error.message.includes("All endpoints failed")) {
			// Show ISP blocking message
			showISPBlockingMessage();
		}

		// Rethrow or return default value
		throw error;
	}
}

// Usage
const users = await safeAPICall(() => apiClient.get("/sapps/users"));
```

### Request Queue untuk Offline Support

```javascript
class OfflineQueue {
  constructor(apiClient) {
    this.apiClient = apiClient;
    this.queue = [];
    this.processing = false;
  }

  async add(request) {
    this.queue.push(request);
    await this.process();
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;

    this.processing = true;

    while (this.queue.length > 0) {
      const request = this.queue[0];

      try {
        await this.apiClient.fetch(request.path, request.options);
        this.queue.shift(); // Remove on success
      } catch (error) {
        console.error('Queue processing failed:', error);
        break; // Stop processing on error
      }
    }

    this.processing = false;
  }
}

// Usage
const queue = new OfflineQueue(apiClient);

// Add requests to queue when offline
if (!navigator.onLine) {
  await queue.add({
    path: '/sapps/users',
    options: { method: 'POST', ... }
  });
}
```

---

**Note:** File-file ini adalah client-side helpers dan tidak di-deploy ke backend. Copy ke frontend project untuk digunakan.
