89 lines
3.1 KiB
TypeScript
89 lines
3.1 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { authFetch } from '../../utils/authFetch';
|
|
|
|
export type ActiveCoffee = {
|
|
id: string | number;
|
|
title: string;
|
|
description: string;
|
|
price: string | number; // price can be a string or number
|
|
pictureUrl?: string;
|
|
state: number; // 1 for active, 0 for inactive
|
|
};
|
|
|
|
export type CoffeeItem = {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
pricePer10: number; // price for 10 pieces
|
|
image: string;
|
|
};
|
|
|
|
export function useActiveCoffees() {
|
|
const [coffees, setCoffees] = useState<CoffeeItem[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
const base = (process.env.NEXT_PUBLIC_API_BASE_URL || '').replace(/\/+$/, '');
|
|
const url = `${base}/api/admin/coffee/active`;
|
|
|
|
console.log('[useActiveCoffees] Fetching active coffees from:', url);
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
authFetch(url, {
|
|
method: 'GET',
|
|
headers: { Accept: 'application/json' },
|
|
credentials: 'include',
|
|
})
|
|
.then(async (response) => {
|
|
const contentType = response.headers.get('content-type') || '';
|
|
console.log('[useActiveCoffees] Response status:', response.status);
|
|
console.log('[useActiveCoffees] Response content-type:', contentType);
|
|
|
|
if (!response.ok || !contentType.includes('application/json')) {
|
|
const text = await response.text().catch(() => '');
|
|
console.warn('[useActiveCoffees] Non-JSON response or error body:', text.slice(0, 200));
|
|
throw new Error(`Request failed: ${response.status} ${text.slice(0, 160)}`);
|
|
}
|
|
|
|
const json = await response.json();
|
|
console.log('[useActiveCoffees] Raw JSON response:', json);
|
|
|
|
const data: ActiveCoffee[] =
|
|
Array.isArray(json?.data) ? json.data :
|
|
Array.isArray(json) ? json :
|
|
[]
|
|
console.log('[useActiveCoffees] Parsed coffee data:', data);
|
|
|
|
const mapped: CoffeeItem[] = data
|
|
.filter((coffee) => (coffee as any).state === 1 || (coffee as any).state === true || (coffee as any).state === '1')
|
|
.map((coffee) => {
|
|
const price = typeof coffee.price === 'string' ? parseFloat(coffee.price) : coffee.price
|
|
return {
|
|
id: String(coffee.id),
|
|
name: coffee.title || `Coffee ${coffee.id}`,
|
|
description: coffee.description || '',
|
|
pricePer10: !isNaN(price as number) ? (price as number) * 10 : 0,
|
|
image: coffee.pictureUrl || '',
|
|
}
|
|
})
|
|
|
|
console.log('[useActiveCoffees] Mapped coffee items:', mapped)
|
|
setCoffees(mapped)
|
|
})
|
|
.catch((error: any) => {
|
|
console.error('[useActiveCoffees] Error fetching coffees:', error);
|
|
setError(error?.message || 'Failed to load active coffees');
|
|
setCoffees([]);
|
|
})
|
|
.finally(() => {
|
|
setLoading(false);
|
|
console.log('[useActiveCoffees] Fetch complete. Loading state:', false);
|
|
});
|
|
}, []);
|
|
|
|
return { coffees, loading, error };
|
|
}
|