Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 8 additions & 76 deletions frontend/src/components/ItemsSection.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -29,8 +29,6 @@ export function ItemsSection({
const [amount, setAmount] = useState("");
const [categoryId, setCategoryId] = useState<string>("");
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;
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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 = () => {
Expand All @@ -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 (
<Card className="col-span-full">
Expand Down Expand Up @@ -147,23 +144,7 @@ export function ItemsSection({
onChange={(e) => setSpentOn(e.target.value)}
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mt-3 mb-3">
<div>
<label className="text-sm text-charcoal-700 dark:text-sand-300 mb-1 block">
Where should this money go?
</label>
<Select
options={[
{ value: "none", label: "Spent" },
{ value: "savings", label: "Savings" },
{ value: "retirement_savings", label: "Retirement Savings" },
]}
value={savingsDestination}
onChange={(e) => setSavingsDestination(e.target.value)}
/>
</div>
</div>
<div className="flex gap-2">
<div className="flex gap-2 mt-3">
<Button size="sm" onClick={handleAdd}>
<Check size={16} className="mr-1" />
Add
Expand Down Expand Up @@ -192,23 +173,11 @@ export function ItemsSection({
<th className="text-right py-2 px-1 font-medium text-charcoal-600 dark:text-sand-400 text-xs md:text-sm">
Amount
</th>
<th className="text-center py-2 px-1 font-medium text-charcoal-600 dark:text-sand-400 text-xs md:text-sm">
<div className="flex items-center justify-center gap-1">
{showDestination && <span className="hidden sm:inline">Destination</span>}
<button
onClick={() => setShowDestination(!showDestination)}
className="p-2 md:p-1 hover:bg-sand-200 dark:hover:bg-charcoal-800 active:bg-sand-300 dark:active:bg-charcoal-700 transition-colors rounded touch-manipulation"
title={showDestination ? "Hide destination column" : "Show destination column"}
>
{showDestination ? <Eye size={14} /> : <EyeOff size={14} />}
</button>
</div>
</th>
{!isReadOnly && <th className="w-16 md:w-20"></th>}
</tr>
</thead>
<tbody>
{items.map((item) => (
{spendingItems.map((item) => (
<tr
key={item.id}
className="border-b border-sand-200 dark:border-charcoal-800 hover:bg-sand-100 dark:hover:bg-charcoal-900/50 active:bg-sand-200 dark:active:bg-charcoal-900 transition-colors"
Expand Down Expand Up @@ -248,20 +217,6 @@ export function ItemsSection({
className="text-xs text-right"
/>
</td>
{showDestination && (
<td className="py-2">
<Select
options={[
{ value: "none", label: "Spent" },
{ value: "savings", label: "Savings" },
{ value: "retirement_savings", label: "Retirement" },
]}
value={savingsDestination}
onChange={(e) => setSavingsDestination(e.target.value)}
className="text-xs"
/>
</td>
)}
<td className="py-2">
<div className="flex gap-0.5 md:gap-1 justify-end">
<button
Expand Down Expand Up @@ -295,32 +250,9 @@ export function ItemsSection({
{item.category_label}
</span>
</td>
<td className={`py-2 px-1 text-right font-medium text-xs md:text-sm whitespace-nowrap ${item.savings_destination === "none"
? 'text-terracotta-600 dark:text-terracotta-400'
: 'text-sage-600 dark:text-sage-400'
}`}>
{item.savings_destination !== "none" && '→ '}
<td className={`py-2 px-1 text-right font-medium text-xs md:text-sm whitespace-nowrap text-terracotta-600 dark:text-terracotta-400`}>
{formatCurrency(item.amount)}
</td>
{showDestination && (
<td className="py-2 px-1 text-center">
{item.savings_destination === "none" && (
<span className="text-[10px] md:text-xs px-1.5 md:px-2 py-0.5 md:py-1 rounded bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-200 whitespace-nowrap">
Spent
</span>
)}
{item.savings_destination === "savings" && (
<span className="text-[10px] md:text-xs px-1.5 md:px-2 py-0.5 md:py-1 rounded bg-sage-100 dark:bg-sage-900 text-sage-700 dark:text-sage-200 whitespace-nowrap">
Savings
</span>
)}
{item.savings_destination === "retirement_savings" && (
<span className="text-[10px] md:text-xs px-1.5 md:px-2 py-0.5 md:py-1 rounded bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-200 whitespace-nowrap">
Retirement
</span>
)}
</td>
)}
{!isReadOnly && (
<td className="py-2 px-1">
<div className="flex gap-0.5 md:gap-1 justify-end">
Expand All @@ -346,7 +278,7 @@ export function ItemsSection({
</tbody>
</table>

{items.length === 0 && (
{spendingItems.length === 0 && (
<div className="text-sm text-charcoal-400 dark:text-charcoal-600 py-8 text-center">
No spending items
</div>
Expand Down
Loading