deckhearth/lib/use-card-editor.js

186 lines
4.8 KiB
JavaScript
Raw Normal View History

import { useState, useEffect } from 'react';
const EMPTY_FORM = {
name: '',
set_name: '',
set_code: '',
card_number: '',
rarity: '',
game: '',
mana_cost: '',
cmc: '',
card_type: '',
colors: [],
oracle_text: '',
power: '',
toughness: '',
image_url: '',
stock_image_url: '',
current_price: '',
market_price: '',
};
/**
* Admin card editor state and handlers (god-component split).
*/
export function useCardEditor(router) {
const { id } = router.query;
const [card, setCard] = useState(null);
const [fetchLoading, setFetchLoading] = useState(false);
const loading = id ? fetchLoading : false;
const [saving, setSaving] = useState(false);
const [message, setMessage] = useState('');
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false);
const [formData, setFormData] = useState(EMPTY_FORM);
const fetchCard = async (cardId) => {
setFetchLoading(true);
try {
const response = await fetch(`/api/cards/${cardId}`);
if (response.ok) {
const cardData = await response.json();
setCard(cardData);
setFormData({
name: cardData.name || '',
set_name: cardData.set_name || '',
set_code: cardData.set_code || '',
card_number: cardData.card_number || '',
rarity: cardData.rarity || '',
game: cardData.game || '',
mana_cost: cardData.mana_cost || '',
cmc: cardData.cmc || '',
card_type: cardData.card_type || '',
colors: Array.isArray(cardData.colors) ? cardData.colors : [],
oracle_text: cardData.oracle_text || '',
power: cardData.power || '',
toughness: cardData.toughness || '',
image_url: cardData.image_url || '',
stock_image_url: cardData.stock_image_url || '',
current_price: cardData.current_price || '',
market_price: cardData.market_price || '',
});
} else {
setMessage('Card not found');
}
} catch (error) {
setMessage('Error loading card: ' + error.message);
} finally {
setFetchLoading(false);
}
};
useEffect(() => {
if (id) {
// eslint-disable-next-line react-hooks/set-state-in-effect -- load card when route id is set
fetchCard(id);
}
}, [id]);
const searchCards = async (query) => {
if (!query.trim()) {
setSearchResults([]);
return;
}
setSearchLoading(true);
try {
const response = await fetch(
`/api/cards/search?query=${encodeURIComponent(query)}&limit=20`
);
if (response.ok) {
const data = await response.json();
setSearchResults(data.cards || []);
}
} catch (error) {
console.error('Search error:', error);
} finally {
setSearchLoading(false);
}
};
const handleInputChange = (field, value) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
};
const handleColorChange = (color, checked) => {
setFormData((prev) => ({
...prev,
colors: checked
? [...prev.colors, color]
: prev.colors.filter((c) => c !== color),
}));
};
const handleSave = async () => {
if (!card?.id) {
setMessage('No card selected to edit');
return;
}
setSaving(true);
setMessage('');
try {
const response = await fetch(`/api/cards/${card.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...formData,
cmc: formData.cmc ? parseInt(formData.cmc, 10) : null,
current_price: formData.current_price ? parseFloat(formData.current_price) : null,
market_price: formData.market_price ? parseFloat(formData.market_price) : null,
}),
});
if (response.ok) {
const updatedCard = await response.json();
setCard(updatedCard);
setMessage('Card updated successfully!');
setTimeout(() => setMessage(''), 3000);
} else {
const errorData = await response.json();
setMessage('Error updating card: ' + (errorData.error || 'Unknown error'));
}
} catch (error) {
setMessage('Error updating card: ' + error.message);
} finally {
setSaving(false);
}
};
const selectCard = (selectedCard) => {
router.push(`/admin/card-editor?id=${selectedCard.id}`);
};
const onSearchQueryChange = (value) => {
setSearchQuery(value);
searchCards(value);
};
return {
card,
formData,
handleColorChange,
handleInputChange,
handleSave,
loading,
message,
onSearchQueryChange,
router,
saving,
searchLoading,
searchQuery,
searchResults,
selectCard,
showEmptyState: !card && !loading,
};
}