diff --git a/src/Budget.Client/src/pages/OutgoPage.tsx b/src/Budget.Client/src/pages/OutgoPage.tsx
index 03586ca..7dc266d 100644
--- a/src/Budget.Client/src/pages/OutgoPage.tsx
+++ b/src/Budget.Client/src/pages/OutgoPage.tsx
@@ -1,5 +1,7 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
+import { useToast } from '../components/Toast';
+import { LoadingSkeleton } from '../components/LoadingSkeleton';
import {
DndContext,
closestCenter,
@@ -130,13 +132,20 @@ export function OutgoPage() {
const [outgos, setOutgos] = useState
([]);
const [categories, setCategories] = useState([]);
const [paymentSources, setPaymentSources] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const { showError } = useToast();
const sensors = useSensors(useSensor(PointerSensor));
useEffect(() => {
if (!budgetId) return;
- api.get(`/api/budgets/${budgetId}/outgos`).then(setOutgos);
- api.get(`/api/budgets/${budgetId}/outgos/categories`).then(setCategories);
- api.get(`/api/budgets/${budgetId}/outgos/payment-sources`).then(setPaymentSources);
+ setLoading(true);
+ Promise.all([
+ api.get(`/api/budgets/${budgetId}/outgos`),
+ api.get(`/api/budgets/${budgetId}/outgos/categories`),
+ api.get(`/api/budgets/${budgetId}/outgos/payment-sources`),
+ ]).then(([o, c, p]) => { setOutgos(o); setCategories(c); setPaymentSources(p); })
+ .catch(e => showError(String(e)))
+ .finally(() => setLoading(false));
}, [budgetId]);
const refreshSuggestions = () => {
@@ -146,35 +155,42 @@ export function OutgoPage() {
};
const handleSave = async (id: string, edit: EditState) => {
- const updated = await api.put(`/api/budgets/${budgetId}/outgos/${id}`, {
- name: edit.name,
- category: edit.category || null,
- type: edit.type,
- frequency: edit.frequency,
- amount: parseFloat(edit.amount),
- paymentSource: edit.paymentSource || null,
- notes: edit.notes || null,
- });
- setOutgos(prev => prev.map(o => o.id === id ? updated : o));
- refreshSuggestions();
+ try {
+ const updated = await api.put(`/api/budgets/${budgetId}/outgos/${id}`, {
+ name: edit.name,
+ category: edit.category || null,
+ type: edit.type,
+ frequency: edit.frequency,
+ amount: parseFloat(edit.amount),
+ paymentSource: edit.paymentSource || null,
+ notes: edit.notes || null,
+ });
+ setOutgos(prev => prev.map(o => o.id === id ? updated : o));
+ refreshSuggestions();
+ } catch (e) { showError(String(e)); }
};
const handleDelete = async (id: string) => {
- await api.delete(`/api/budgets/${budgetId}/outgos/${id}`);
- setOutgos(prev => prev.filter(o => o.id !== id));
+ if (!confirm('Delete this outgo row?')) return;
+ try {
+ await api.delete(`/api/budgets/${budgetId}/outgos/${id}`);
+ setOutgos(prev => prev.filter(o => o.id !== id));
+ } catch (e) { showError(String(e)); }
};
const handleAdd = async () => {
- const created = await api.post(`/api/budgets/${budgetId}/outgos`, {
- name: 'New Outgo',
- category: null,
- type: 'Need',
- frequency: 'Monthly',
- amount: 0,
- paymentSource: null,
- notes: null,
- });
- setOutgos(prev => [...prev, created]);
+ try {
+ const created = await api.post(`/api/budgets/${budgetId}/outgos`, {
+ name: 'New Outgo',
+ category: null,
+ type: 'Need',
+ frequency: 'Monthly',
+ amount: 0,
+ paymentSource: null,
+ notes: null,
+ });
+ setOutgos(prev => [...prev, created]);
+ } catch (e) { showError(String(e)); }
};
const handleDragEnd = async (event: DragEndEvent) => {
@@ -189,6 +205,8 @@ export function OutgoPage() {
});
};
+ if (loading) return <>>;
+
return (