-
due {ordinal(bill.due_day)}
- {bill.category && (
-
{bill.category}
- )}
+
+ {/* Bills */}
+
+
Bills
+ {paycheck.bills.length === 0 ? (
+
(none)
+ ) : (
+ paycheck.bills.map((bill) => (
+
+
onBillPaidToggle(bill.paycheck_bill_id, !bill.paid)}
+ className="bill-row__check"
+ />
+
+
+ {bill.name}
+ {formatCurrency(bill.effective_amount)}
+
+
+ due {ordinal(bill.due_day)}
+ {bill.category && {bill.category}}
+
-
- ))
- )}
-
-
-
-
One-time expenses
-
- {paycheck.one_time_expenses.length === 0 ? (
-
(none)
- ) : (
- paycheck.one_time_expenses.map((ote) => (
-
- onOtePaidToggle(ote.id, !ote.paid)}
- style={styles.checkbox}
- />
-
- {ote.name}
-
- {formatCurrency(ote.amount)}
-
-
- ))
- )}
-
- setNewOteName(e.target.value)}
- style={styles.oteAddInput}
- />
- setNewOteAmount(e.target.value)}
- min="0"
- step="0.01"
- style={{ ...styles.oteAddInput, width: '80px' }}
- />
-
+ ))
+ )}
-
-
-
Variable Spending
-
-
- {actualsLoading &&
Loadingβ¦
}
- {actualsError &&
Error: {actualsError}
}
-
- {!actualsLoading && actuals.length === 0 && (
-
(none)
- )}
-
- {actuals.map((actual) => (
-
-
-
- {actual.category_name || Uncategorized}
-
- {formatCurrency(actual.amount)}
-
-
- {actual.note && {actual.note}}
- {actual.date}
-
-
-
- ))}
-
-
);
@@ -323,19 +302,14 @@ function PaycheckColumn({ paycheck, onBillPaidToggle, categories, onOtePaidToggl
function PaycheckView() {
const now = new Date();
const [year, setYear] = useState(now.getFullYear());
- const [month, setMonth] = useState(now.getMonth() + 1); // 1-based
+ const [month, setMonth] = useState(now.getMonth() + 1);
const [paychecks, setPaychecks] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [categories, setCategories] = useState([]);
- useEffect(() => {
- loadPaychecks(year, month);
- }, [year, month]);
-
- useEffect(() => {
- loadCategories();
- }, []);
+ useEffect(() => { loadPaychecks(year, month); }, [year, month]);
+ useEffect(() => { loadCategories(); }, []);
async function loadPaychecks(y, m) {
setLoading(true);
@@ -343,8 +317,7 @@ function PaycheckView() {
try {
const res = await fetch(`/api/paychecks?year=${y}&month=${m}`);
if (!res.ok) throw new Error(`Server error: ${res.status}`);
- const data = await res.json();
- setPaychecks(data);
+ setPaychecks(await res.json());
} catch (err) {
setError(err.message);
} finally {
@@ -355,30 +328,17 @@ function PaycheckView() {
async function loadCategories() {
try {
const res = await fetch('/api/expense-categories');
- if (!res.ok) throw new Error(`Server error: ${res.status}`);
- const data = await res.json();
- setCategories(data);
- } catch (err) {
- console.error('Failed to load expense categories:', err.message);
- }
+ if (!res.ok) return;
+ setCategories(await res.json());
+ } catch { /* silent */ }
}
function prevMonth() {
- if (month === 1) {
- setYear(y => y - 1);
- setMonth(12);
- } else {
- setMonth(m => m - 1);
- }
+ if (month === 1) { setYear(y => y - 1); setMonth(12); } else { setMonth(m => m - 1); }
}
function nextMonth() {
- if (month === 12) {
- setYear(y => y + 1);
- setMonth(1);
- } else {
- setMonth(m => m + 1);
- }
+ if (month === 12) { setYear(y => y + 1); setMonth(1); } else { setMonth(m => m + 1); }
}
async function handleOtePaidToggle(oteId, paid) {
@@ -421,7 +381,6 @@ function PaycheckView() {
}
async function handleBillPaidToggle(paycheckBillId, paid) {
- // Optimistic update
setPaychecks(prev =>
prev.map(pc => ({
...pc,
@@ -441,7 +400,6 @@ function PaycheckView() {
});
if (!res.ok) throw new Error(`Server error: ${res.status}`);
const updated = await res.json();
- // Sync server response
setPaychecks(prev =>
prev.map(pc => ({
...pc,
@@ -453,14 +411,11 @@ function PaycheckView() {
}))
);
} catch (err) {
- // Revert optimistic update on failure
setPaychecks(prev =>
prev.map(pc => ({
...pc,
bills: pc.bills.map(b =>
- b.paycheck_bill_id === paycheckBillId
- ? { ...b, paid: !paid }
- : b
+ b.paycheck_bill_id === paycheckBillId ? { ...b, paid: !paid } : b
),
}))
);
@@ -472,21 +427,19 @@ function PaycheckView() {
const pc2 = paychecks.find(p => p.paycheck_number === 2) || null;
return (
-
-
-
-
{MONTH_NAMES[month - 1]} {year}
-
+
+
+
+ {MONTH_NAMES[month - 1]} {year}
+
- {error && (
-
Error: {error}
- )}
+ {error &&
Error: {error}
}
{loading ? (
-
Loading...
+
Loadingβ¦
) : (
-
+
{
fetch('/api/config')
- .then((res) => res.json())
- .then((data) => {
+ .then(res => res.json())
+ .then(data => {
setForm({
paycheck1_day: data.paycheck1_day ?? '',
paycheck2_day: data.paycheck2_day ?? '',
@@ -82,7 +33,7 @@ function Settings() {
function handleChange(e) {
const { name, value } = e.target;
setSaved(false);
- setForm((prev) => ({ ...prev, [name]: value }));
+ setForm(prev => ({ ...prev, [name]: value }));
}
function handleSubmit(e) {
@@ -92,9 +43,7 @@ function Settings() {
const payload = {};
for (const [key, val] of Object.entries(form)) {
- if (val !== '' && val !== null) {
- payload[key] = Number(val);
- }
+ if (val !== '' && val !== null) payload[key] = Number(val);
}
fetch('/api/config', {
@@ -102,11 +51,11 @@ function Settings() {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
- .then((res) => {
+ .then(res => {
if (!res.ok) throw new Error('Save failed');
return res.json();
})
- .then((data) => {
+ .then(data => {
setForm({
paycheck1_day: data.paycheck1_day ?? '',
paycheck2_day: data.paycheck2_day ?? '',
@@ -121,115 +70,74 @@ function Settings() {
}
return (
-
-
Settings
+
+
+
Settings
+
- {error &&
{error}
}
+ {error &&
{error}
}