forked from syntaxbullet/aurorabot
100 lines
2.3 KiB
TypeScript
100 lines
2.3 KiB
TypeScript
import { useCallback, useEffect, useState } from "react";
|
|
import { get } from "./api";
|
|
|
|
export interface Item {
|
|
id: number;
|
|
name: string;
|
|
description: string | null;
|
|
type: string;
|
|
rarity: string;
|
|
price: string | null;
|
|
iconUrl: string;
|
|
imageUrl: string;
|
|
}
|
|
|
|
export interface ItemFilters {
|
|
search: string;
|
|
type: string | null;
|
|
rarity: string | null;
|
|
}
|
|
|
|
export function useItems() {
|
|
const [items, setItems] = useState<Item[]>([]);
|
|
const [total, setTotal] = useState(0);
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
const [limit, setLimit] = useState(50);
|
|
const [filters, setFiltersState] = useState<ItemFilters>({
|
|
search: "",
|
|
type: null,
|
|
rarity: null,
|
|
});
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchItems = useCallback(async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
const params = new URLSearchParams();
|
|
if (filters.search) params.set("search", filters.search);
|
|
if (filters.type) params.set("type", filters.type);
|
|
if (filters.rarity) params.set("rarity", filters.rarity);
|
|
params.set("limit", String(limit));
|
|
params.set("offset", String((currentPage - 1) * limit));
|
|
|
|
const data = await get<{ items: Item[]; total: number }>(
|
|
`/api/items?${params.toString()}`
|
|
);
|
|
|
|
setItems(data.items);
|
|
setTotal(data.total);
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : "Failed to load items");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [filters, currentPage, limit]);
|
|
|
|
const setFilters = useCallback((newFilters: Partial<ItemFilters>) => {
|
|
setFiltersState((prev) => ({ ...prev, ...newFilters }));
|
|
setCurrentPage(1);
|
|
}, []);
|
|
|
|
const setSearchDebounced = useCallback(
|
|
(() => {
|
|
let timeoutId: NodeJS.Timeout;
|
|
return (search: string) => {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = setTimeout(() => {
|
|
setFilters({ search });
|
|
}, 300);
|
|
};
|
|
})(),
|
|
[setFilters]
|
|
);
|
|
|
|
const setPage = useCallback((page: number) => {
|
|
setCurrentPage(page);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
fetchItems();
|
|
}, [fetchItems]);
|
|
|
|
return {
|
|
items,
|
|
total,
|
|
currentPage,
|
|
limit,
|
|
setLimit,
|
|
filters,
|
|
setFilters,
|
|
setSearchDebounced,
|
|
setPage,
|
|
loading,
|
|
error,
|
|
refetch: fetchItems,
|
|
};
|
|
}
|