import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/router'; import { isLoggedIn, getCategories, createCategory, deleteCategory } from '../lib/api'; import AppShell from '../components/AppShell'; import { Icon } from '../components/icons'; import { useToast } from '../components/ToastProvider'; import { useConfirm } from '../components/ConfirmProvider'; const ICONS = [ '๐Ÿœ', '๐Ÿฅ˜', '๐Ÿฅฌ', '๐Ÿฅฉ', '๐Ÿ”', '๐Ÿ•', 'โ˜•', '๐Ÿบ', '๐Ÿง‹', '๐ŸŽ', '๐Ÿช', '๐Ÿซ', '๐Ÿš—', '๐Ÿš•', '๐ŸšŒ', '๐Ÿš‡', 'โ›ฝ', '๐Ÿš™', '๐Ÿ›ต', 'โœˆ๏ธ', '๐Ÿšข', '๐Ÿ›’', '๐Ÿ‘”', '๐Ÿ‘•', '๐Ÿ‘–', '๐Ÿ‘Ÿ', '๐Ÿ‘“', '๐Ÿงข', '๐Ÿ‘œ', '๐ŸŽ’', '๐Ÿ’', '๐Ÿ’„', '๐Ÿ ', '๐Ÿข', '๐Ÿฆ', '๐Ÿฅ', '๐Ÿจ', '๐Ÿฉ', '๐Ÿ”ง', '๐Ÿ”จ', '๐Ÿ›‹๏ธ', '๐Ÿ“บ', '๐Ÿ’ป', '๐Ÿ“ฑ', '๐Ÿ“', '๐Ÿ’ฐ', '๐ŸŽ', '๐Ÿ“ˆ', '๐Ÿงง', '๐Ÿ’ณ', '๐ŸŽฏ', '๐Ÿ“š', '๐ŸŽต', '๐ŸŽฎ', '๐Ÿƒ', 'โšฝ', '๐ŸŠ', '๐Ÿšด', '๐ŸŽญ', '๐ŸŽจ', '๐ŸŽฌ', '๐Ÿ“ท', '๐ŸŽฅ', '๐Ÿ“บ', '๐Ÿงธ', '๐Ÿ•', '๐Ÿˆ', '๐ŸŒธ', '๐ŸŒบ' ]; export default function Categories() { const router = useRouter(); const { showToast } = useToast(); const { confirm } = useConfirm(); const [categories, setCategories] = useState({ expense: [], income: [] }); const [modalOpen, setModalOpen] = useState(false); const [categoryType, setCategoryType] = useState('expense'); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [formError, setFormError] = useState(''); const [formData, setFormData] = useState({ name: '', icon: '๐Ÿ“', }); const loadCategories = useCallback(async () => { setLoading(true); try { const data = await getCategories(); setCategories(data); } catch (err) { console.error(err); showToast(err.message, { tone: 'error' }); } finally { setLoading(false); } }, [showToast]); useEffect(() => { if (!isLoggedIn()) { router.push('/login'); return; } loadCategories(); }, [router, loadCategories]); const openAddModal = (type) => { setCategoryType(type); setFormData({ name: '', icon: '๐Ÿ“' }); setFormError(''); setModalOpen(true); }; const closeModal = () => { if (submitting) return; setModalOpen(false); setFormError(''); }; const handleSubmit = async (e) => { e.preventDefault(); if (!formData.name || !formData.icon) { setFormError('่ฏทๅกซๅ†™ๅฎŒๆ•ดไฟกๆฏ'); return; } setSubmitting(true); setFormError(''); try { await createCategory({ type: categoryType, name: formData.name, icon: formData.icon, }); closeModal(); showToast('ๅˆ†็ฑปๅทฒๅˆ›ๅปบ', { tone: 'success' }); await loadCategories(); } catch (err) { setFormError(err.message); showToast(err.message, { tone: 'error' }); } finally { setSubmitting(false); } }; const handleDelete = async (id) => { const shouldDelete = await confirm({ title: 'ๅˆ ้™คๆญคๅˆ†็ฑป๏ผŸ', description: '้ป˜่ฎคๅˆ†็ฑปไธๅฏๅˆ ้™ค๏ผŒ่‡ชๅฎšไน‰ๅˆ†็ฑปๅˆ ้™คๅŽๅฐ†ๆ— ๆณ•ๆขๅคใ€‚', confirmText: 'ๅˆ ้™ค', }); if (!shouldDelete) return; try { await deleteCategory(id); showToast('ๅˆ†็ฑปๅทฒๅˆ ้™ค', { tone: 'success' }); await loadCategories(); } catch (err) { showToast(err.message, { tone: 'error' }); } }; const actions = ( ); return ( {loading ? (
ๅŠ ่ฝฝไธญ...
) : ( <>

ๆ”ฏๅ‡บๅˆ†็ฑป

ๆ”ฏๅ‡บ

{categories.expense.map((cat) => (
{cat.icon} {cat.name} {!cat.is_default && ( )}
))}

ๆ”ถๅ…ฅๅˆ†็ฑป

ๆ”ถๅ…ฅ

{categories.income.map((cat) => (
{cat.icon} {cat.name} {!cat.is_default && ( )}
))}

้ป˜่ฎคๅˆ†็ฑปๆ— ๆณ•ๅˆ ้™ค๏ผŒ่‡ชๅฎšไน‰ๅˆ†็ฑปๅฏไปฅๅˆ ้™คใ€‚

)} {modalOpen && (
e.stopPropagation()}>

ๆ–ฐๅขžๅˆ†็ฑป

{categoryType === 'expense' ? 'ๆ–ฐๅปบๆ”ฏๅ‡บๅˆ†็ฑป' : 'ๆ–ฐๅปบๆ”ถๅ…ฅๅˆ†็ฑป'}

{formError &&
{formError}
}
setFormData({ ...formData, name: e.target.value })} placeholder="่ฏท่พ“ๅ…ฅๅˆ†็ฑปๅ็งฐ" required disabled={submitting} />
{ICONS.map((icon) => ( ))}
)}
); }