114 lines
3.8 KiB
TypeScript
114 lines
3.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { authFetch } from '../../../utils/authFetch';
|
|
import { log } from '../../../utils/logger';
|
|
|
|
export type AdminPool = {
|
|
id: string;
|
|
pool_name: string;
|
|
description?: string;
|
|
price?: number;
|
|
pool_type?: 'coffee' | 'other';
|
|
is_active?: boolean;
|
|
membersCount: number;
|
|
createdAt: string;
|
|
};
|
|
|
|
export function useAdminPools() {
|
|
const [pools, setPools] = useState<AdminPool[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string>('');
|
|
const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
async function load() {
|
|
setLoading(true);
|
|
setError('');
|
|
const url = `${BASE_URL}/api/admin/pools`; // reverted to /api/admin/pools
|
|
log("🌐 Pools: GET", url);
|
|
try {
|
|
const headers = { Accept: 'application/json' };
|
|
log("📤 Pools: Request headers:", headers);
|
|
|
|
const res = await authFetch(url, { headers });
|
|
log("📡 Pools: Response status:", res.status);
|
|
|
|
let body: any = null;
|
|
try {
|
|
body = await res.clone().json();
|
|
const preview = JSON.stringify(body).slice(0, 600);
|
|
log("📦 Pools: Response body preview:", preview);
|
|
} catch {
|
|
log("📦 Pools: Response body is not JSON or failed to parse");
|
|
}
|
|
|
|
if (res.status === 401) {
|
|
if (!cancelled) setError('Unauthorized. Please log in.');
|
|
return;
|
|
}
|
|
if (res.status === 403) {
|
|
if (!cancelled) setError('Forbidden. Admin access required.');
|
|
return;
|
|
}
|
|
if (!res.ok) {
|
|
if (!cancelled) setError('Failed to load pools.');
|
|
return;
|
|
}
|
|
|
|
const apiItems: any[] = Array.isArray(body?.data) ? body.data : [];
|
|
log("🔧 Pools: Mapping items count:", apiItems.length);
|
|
|
|
const mapped: AdminPool[] = apiItems.map(item => ({
|
|
id: String(item.id),
|
|
pool_name: String(item.pool_name ?? 'Unnamed Pool'),
|
|
description: String(item.description ?? ''),
|
|
price: Number(item.price ?? 0),
|
|
pool_type: item.pool_type === 'coffee' ? 'coffee' : 'other',
|
|
is_active: Boolean(item.is_active),
|
|
membersCount: 0,
|
|
createdAt: String(item.created_at ?? new Date().toISOString()),
|
|
}));
|
|
log("✅ Pools: Mapped sample:", mapped.slice(0, 3));
|
|
|
|
if (!cancelled) setPools(mapped);
|
|
} catch (e: any) {
|
|
log("❌ Pools: Network or parsing error:", e?.message || e);
|
|
if (!cancelled) setError('Network error while loading pools.');
|
|
} finally {
|
|
if (!cancelled) setLoading(false);
|
|
}
|
|
}
|
|
load();
|
|
return () => { cancelled = true; };
|
|
}, [BASE_URL]);
|
|
|
|
return {
|
|
pools,
|
|
loading,
|
|
error,
|
|
refresh: async () => {
|
|
const url = `${BASE_URL}/api/admin/pools`; // reverted to /api/admin/pools
|
|
log("🔁 Pools: Refresh GET", url);
|
|
const res = await authFetch(url, { headers: { Accept: 'application/json' } });
|
|
if (!res.ok) {
|
|
log("❌ Pools: Refresh failed status:", res.status);
|
|
return false;
|
|
}
|
|
const body = await res.json();
|
|
const apiItems: any[] = Array.isArray(body?.data) ? body.data : [];
|
|
setPools(apiItems.map(item => ({
|
|
id: String(item.id),
|
|
pool_name: String(item.pool_name ?? 'Unnamed Pool'),
|
|
description: String(item.description ?? ''),
|
|
price: Number(item.price ?? 0),
|
|
pool_type: item.pool_type === 'coffee' ? 'coffee' : 'other',
|
|
is_active: Boolean(item.is_active),
|
|
membersCount: 0,
|
|
createdAt: String(item.created_at ?? new Date().toISOString()),
|
|
})));
|
|
log("✅ Pools: Refresh succeeded, items:", apiItems.length);
|
|
return true;
|
|
}
|
|
};
|
|
}
|