From 40691fa5c06df5da0760e605cdef9e19925e4ef9 Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Sun, 25 Jan 2026 15:29:40 +0000 Subject: [PATCH 01/11] Added transfer card --- frontend/src/components/ItemsSection.tsx | 84 +---- frontend/src/components/TransfersCard.tsx | 382 ++++++++++++++++++++++ frontend/src/pages/Dashboard.tsx | 9 + 3 files changed, 399 insertions(+), 76 deletions(-) create mode 100644 frontend/src/components/TransfersCard.tsx diff --git a/frontend/src/components/ItemsSection.tsx b/frontend/src/components/ItemsSection.tsx index 12f38ee..889986d 100644 --- a/frontend/src/components/ItemsSection.tsx +++ b/frontend/src/components/ItemsSection.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Plus, Trash2, Edit2, Check, X, Eye, EyeOff } from "lucide-react"; +import { Plus, Trash2, Edit2, Check, X } from "lucide-react"; import { ItemWithCategory, BudgetCategory, api } from "../api/client"; import { Card } from "./ui/Card"; import { Input } from "./ui/Input"; @@ -29,8 +29,6 @@ export function ItemsSection({ const [amount, setAmount] = useState(""); const [categoryId, setCategoryId] = useState(""); const [spentOn, setSpentOn] = useState(new Date().toISOString().split("T")[0]); - const [savingsDestination, setSavingsDestination] = useState("none"); - const [showDestination, setShowDestination] = useState(true); const handleAdd = async () => { if (!description || !amount || !categoryId) return; @@ -39,7 +37,7 @@ export function ItemsSection({ amount: parseFloat(amount), category_id: parseInt(categoryId), spent_on: spentOn, - savings_destination: savingsDestination, + savings_destination: "none", }); resetForm(); await onUpdate(); @@ -52,7 +50,7 @@ export function ItemsSection({ amount: parseFloat(amount), category_id: parseInt(categoryId), spent_on: spentOn, - savings_destination: savingsDestination, + savings_destination: "none", }); resetForm(); await onUpdate(); @@ -69,7 +67,6 @@ export function ItemsSection({ setAmount(item.amount.toString()); setCategoryId(item.category_id.toString()); setSpentOn(item.spent_on); - setSavingsDestination(item.savings_destination); }; const resetForm = () => { @@ -78,11 +75,11 @@ export function ItemsSection({ setAmount(""); setCategoryId(""); setSpentOn(new Date().toISOString().split("T")[0]); - setSavingsDestination("none"); setIsAdding(false); }; const categoryOptions = categories.map((c) => ({ value: c.id, label: c.label })); + const spendingItems = items.filter((item) => item.savings_destination === "none"); return ( @@ -147,23 +144,7 @@ export function ItemsSection({ onChange={(e) => setSpentOn(e.target.value)} /> -
-
- - setSavingsDestination(e.target.value)} - className="text-xs" - /> - - )}
+ )} +
+ + {isAdding && categories.length === 0 && ( +
+

+ No budget categories yet. +

+

+ Add some in the Budget section first. +

+ +
+ )} + + {isAdding && categories.length > 0 && ( +
+
+ setDescription(e.target.value)} + /> + setAmount(e.target.value)} + /> + setSpentOn(e.target.value)} + /> +
+
+
+ + setSpentOn(e.target.value)} + className="text-xs" + /> + + + setDescription(e.target.value)} + className="text-xs" + /> + + + setAmount(e.target.value)} + className="text-xs text-right" + /> + + + setAmount(e.target.value)} - className="text-xs text-right" - /> - setAmount(e.target.value)} + className="text-xs text-right" + /> +
diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 3f2c58b..7ebab22 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -6,6 +6,7 @@ import { Select } from "../components/ui/Select"; import { Modal } from "../components/ui/Modal"; import { useAuth } from "../context/AuthContext"; import { useCurrency, SUPPORTED_CURRENCIES } from "../context/CurrencyContext"; +import { useUIPreferences } from "../context/UIPreferencesContext"; import { api } from "../api/client"; import { ArrowLeft } from "lucide-react"; @@ -16,6 +17,7 @@ interface SettingsProps { export function Settings({ onBack }: SettingsProps) { const { user, logout, updateUsername } = useAuth(); const { currency, setCurrency, formatCurrency } = useCurrency(); + const { transfersEnabled, setTransfersEnabled } = useUIPreferences(); const [newUsername, setNewUsername] = useState(user?.username || ""); const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); @@ -153,6 +155,38 @@ export function Settings({ onBack }: SettingsProps) {
+
+

+ Transferred Items +

+
+
+
+ +

+ Allow adding, editing, and deleting transferred items +

+
+ +
+
+
+

Change Username From 74019188642e0fe7f9dd236964b9ecb2f71dde20 Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Sun, 25 Jan 2026 17:22:13 +0000 Subject: [PATCH 07/11] Added HelpCircle from lucide-react --- frontend/src/pages/Settings.tsx | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 7ebab22..7ef3651 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -8,7 +8,7 @@ import { useAuth } from "../context/AuthContext"; import { useCurrency, SUPPORTED_CURRENCIES } from "../context/CurrencyContext"; import { useUIPreferences } from "../context/UIPreferencesContext"; import { api } from "../api/client"; -import { ArrowLeft } from "lucide-react"; +import { ArrowLeft, HelpCircle } from "lucide-react"; interface SettingsProps { onBack: () => void; @@ -34,6 +34,7 @@ export function Settings({ onBack }: SettingsProps) { const [passwordSuccess, setPasswordSuccess] = useState(false); const [currencySuccess, setCurrencySuccess] = useState(false); const [selectedCurrency, setSelectedCurrency] = useState(currency.code); + const [showTransfersTooltip, setShowTransfersTooltip] = useState(false); const handleChangeUsername = async (e: React.FormEvent) => { e.preventDefault(); @@ -161,10 +162,32 @@ export function Settings({ onBack }: SettingsProps) {

-
- +
+
+ +
+ + {showTransfersTooltip && ( +
e.stopPropagation()} + > +

Transfer Management

+

Track budgeted items transferred to savings or retirement.

+

When enabled: You can add, edit, and delete transfers.

+

When disabled: View only. Card hides once all transfers are deleted.

+
+
+ )} +
+

Allow adding, editing, and deleting transferred items

From 29e98b13b0b13d5d833916112e7ffaab1dae81bb Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Sun, 25 Jan 2026 18:03:06 +0000 Subject: [PATCH 08/11] Added a how to use section --- frontend/src/pages/Settings.tsx | 45 ++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 7ef3651..6d44e71 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -8,7 +8,7 @@ import { useAuth } from "../context/AuthContext"; import { useCurrency, SUPPORTED_CURRENCIES } from "../context/CurrencyContext"; import { useUIPreferences } from "../context/UIPreferencesContext"; import { api } from "../api/client"; -import { ArrowLeft, HelpCircle } from "lucide-react"; +import { ArrowLeft, HelpCircle, ChevronDown } from "lucide-react"; interface SettingsProps { onBack: () => void; @@ -35,6 +35,7 @@ export function Settings({ onBack }: SettingsProps) { const [currencySuccess, setCurrencySuccess] = useState(false); const [selectedCurrency, setSelectedCurrency] = useState(currency.code); const [showTransfersTooltip, setShowTransfersTooltip] = useState(false); + const [showTransfersHelp, setShowTransfersHelp] = useState(false); const handleChangeUsername = async (e: React.FormEvent) => { e.preventDefault(); @@ -207,8 +208,46 @@ export function Settings({ onBack }: SettingsProps) { />
-
-
+
+
+ + {showTransfersHelp && ( +
+
+

What are transfers?

+

Track portions of your budgeted spending that you plan to transfer to savings or retirement accounts instead of spending.

+
+
+

When to use transfers:

+
    +
  • You have extra budget left and want to save it
  • +
  • You want to contribute to retirement beyond regular deductions
  • +
  • You want to track discretionary savings separately
  • +
+
+
+

How to add a transfer:

+
    +
  1. First, add a budgeted item in your budget section with the amount you want to transfer
  2. +
  3. Then, open the "Transferred Items" card on the dashboard
  4. +
  5. Click the + button to create a transfer
  6. +
  7. Fill in the description, amount, category, and date (matching your budgeted item)
  8. +
  9. Choose the destination: Savings or Retirement
  10. +
  11. Click confirm
  12. +
+
+
+ )} +

From b5876553d3552682e94b2641022ef6b8e3121641 Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Sun, 25 Jan 2026 18:59:33 +0000 Subject: [PATCH 09/11] Standardised info --- frontend/src/pages/Settings.tsx | 124 ++++++++++++++++---------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 6d44e71..e614ab4 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -8,7 +8,7 @@ import { useAuth } from "../context/AuthContext"; import { useCurrency, SUPPORTED_CURRENCIES } from "../context/CurrencyContext"; import { useUIPreferences } from "../context/UIPreferencesContext"; import { api } from "../api/client"; -import { ArrowLeft, HelpCircle, ChevronDown } from "lucide-react"; +import { ArrowLeft, Info } from "lucide-react"; interface SettingsProps { onBack: () => void; @@ -34,8 +34,7 @@ export function Settings({ onBack }: SettingsProps) { const [passwordSuccess, setPasswordSuccess] = useState(false); const [currencySuccess, setCurrencySuccess] = useState(false); const [selectedCurrency, setSelectedCurrency] = useState(currency.code); - const [showTransfersTooltip, setShowTransfersTooltip] = useState(false); - const [showTransfersHelp, setShowTransfersHelp] = useState(false); + const [showTransfersModal, setShowTransfersModal] = useState(false); const handleChangeUsername = async (e: React.FormEvent) => { e.preventDefault(); @@ -168,26 +167,13 @@ export function Settings({ onBack }: SettingsProps) { -
- - {showTransfersTooltip && ( -
e.stopPropagation()} - > -

Transfer Management

-

Track budgeted items transferred to savings or retirement.

-

When enabled: You can add, edit, and delete transfers.

-

When disabled: View only. Card hides once all transfers are deleted.

-
-
- )} -
+

Allow adding, editing, and deleting transferred items @@ -208,45 +194,6 @@ export function Settings({ onBack }: SettingsProps) { />

-
-
- - {showTransfersHelp && ( -
-
-

What are transfers?

-

Track portions of your budgeted spending that you plan to transfer to savings or retirement accounts instead of spending.

-
-
-

When to use transfers:

-
    -
  • You have extra budget left and want to save it
  • -
  • You want to contribute to retirement beyond regular deductions
  • -
  • You want to track discretionary savings separately
  • -
-
-
-

How to add a transfer:

-
    -
  1. First, add a budgeted item in your budget section with the amount you want to transfer
  2. -
  3. Then, open the "Transferred Items" card on the dashboard
  4. -
  5. Click the + button to create a transfer
  6. -
  7. Fill in the description, amount, category, and date (matching your budgeted item)
  8. -
  9. Choose the destination: Savings or Retirement
  10. -
  11. Click confirm
  12. -
-
-
- )}
@@ -382,6 +329,59 @@ export function Settings({ onBack }: SettingsProps) {
+ + setShowTransfersModal(false)}> +
+

+ How to Use Transferred Items +

+ +
+
+

What are transfers?

+

Track portions of your budgeted spending that you plan to transfer to savings or retirement accounts instead of spending.

+
+ +
+

Enable/Disable behavior:

+
    +
  • When enabled: You can add, edit, and delete transfers.
  • +
  • When disabled: View only. Card hides once all transfers are deleted.
  • +
+
+ +
+

When to use transfers:

+
    +
  • You have extra budget left and want to save it
  • +
  • You want to contribute to retirement beyond regular deductions
  • +
  • You want to track discretionary savings separately
  • +
+
+ +
+

How to add a transfer:

+
    +
  1. First, add a budgeted item in your budget section with the amount you want to transfer
  2. +
  3. Then, open the "Transferred Items" card on the dashboard
  4. +
  5. Click the + button to create a transfer
  6. +
  7. Fill in the description, amount, category, and date (matching your budgeted item)
  8. +
  9. Choose the destination: Savings or Retirement
  10. +
  11. Click confirm
  12. +
+
+
+ +
+ +
+
+
); } From 4327f08fdb664dc1474912de61d0c0f922852c8d Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Tue, 27 Jan 2026 18:09:35 +0000 Subject: [PATCH 10/11] Removed category from transfers --- frontend/src/components/TransfersCard.tsx | 60 +++-------------------- frontend/src/pages/Settings.tsx | 5 +- 2 files changed, 10 insertions(+), 55 deletions(-) diff --git a/frontend/src/components/TransfersCard.tsx b/frontend/src/components/TransfersCard.tsx index fa66c0b..7fd4743 100644 --- a/frontend/src/components/TransfersCard.tsx +++ b/frontend/src/components/TransfersCard.tsx @@ -29,7 +29,6 @@ export function TransfersCard({ const [editingId, setEditingId] = useState(null); const [description, setDescription] = useState(""); const [amount, setAmount] = useState(""); - const [categoryId, setCategoryId] = useState(""); const [spentOn, setSpentOn] = useState(new Date().toISOString().split("T")[0]); const [savingsDestination, setSavingsDestination] = useState("savings"); @@ -40,11 +39,12 @@ export function TransfersCard({ ); const handleAdd = async () => { - if (!description || !amount || !categoryId) return; + if (!description || !amount) return; + const catId = categories.length > 0 ? categories[0].id : 1; await api.items.create(monthId, { description, amount: parseFloat(amount), - category_id: parseInt(categoryId), + category_id: catId, spent_on: spentOn, savings_destination: savingsDestination, }); @@ -53,11 +53,12 @@ export function TransfersCard({ }; const handleUpdate = async (id: number) => { - if (!description || !amount || !categoryId) return; + if (!description || !amount) return; + const catId = categories.length > 0 ? categories[0].id : 1; await api.items.update(monthId, id, { description, amount: parseFloat(amount), - category_id: parseInt(categoryId), + category_id: catId, spent_on: spentOn, savings_destination: savingsDestination, }); @@ -74,7 +75,6 @@ export function TransfersCard({ setEditingId(item.id); setDescription(item.description); setAmount(item.amount.toString()); - setCategoryId(item.category_id.toString()); setSpentOn(item.spent_on); setSavingsDestination(item.savings_destination); }; @@ -83,14 +83,11 @@ export function TransfersCard({ setEditingId(null); setDescription(""); setAmount(""); - setCategoryId(""); setSpentOn(new Date().toISOString().split("T")[0]); setSavingsDestination("savings"); setIsAdding(false); }; - const categoryOptions = categories.map((c) => ({ value: c.id, label: c.label })); - return (
@@ -101,9 +98,6 @@ export function TransfersCard({
- {isAdding && categories.length === 0 && ( -
-

- No budget categories yet. -

-

- Add some in the Budget section first. -

- -
- )} - - {isAdding && categories.length > 0 && ( + {isAdding && (
-
+
setAmount(e.target.value)} /> - Description - - Category - Destination @@ -228,14 +197,6 @@ export function TransfersCard({ className="text-xs" /> - - - - - {item.category_label} - - {item.savings_destination === "savings" && ( diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index e614ab4..fe72f1f 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -362,10 +362,9 @@ export function Settings({ onBack }: SettingsProps) {

How to add a transfer:

    -
  1. First, add a budgeted item in your budget section with the amount you want to transfer
  2. -
  3. Then, open the "Transferred Items" card on the dashboard
  4. +
  5. Open the "Transferred Items" card on the dashboard
  6. Click the + button to create a transfer
  7. -
  8. Fill in the description, amount, category, and date (matching your budgeted item)
  9. +
  10. Fill in the description, amount, and date
  11. Choose the destination: Savings or Retirement
  12. Click confirm
From c2819f13768818796938223c6e908773fa28cb56 Mon Sep 17 00:00:00 2001 From: Azzbo77 Date: Tue, 27 Jan 2026 19:19:11 +0000 Subject: [PATCH 11/11] Tranfered items card removed on disabled --- frontend/src/pages/Settings.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index fe72f1f..212a8a0 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -36,6 +36,7 @@ export function Settings({ onBack }: SettingsProps) { const [selectedCurrency, setSelectedCurrency] = useState(currency.code); const [showTransfersModal, setShowTransfersModal] = useState(false); + const handleChangeUsername = async (e: React.FormEvent) => { e.preventDefault(); setUsernameError(""); @@ -194,7 +195,8 @@ export function Settings({ onBack }: SettingsProps) { />
-
+
+