Skip to main content

Overview

The transaction tracking system is the core of BudgetView, allowing you to record every financial movement with detailed categorization, multi-currency support, and flexible date filtering.

Dual Currency Input

Enter amounts in USD or VES with automatic BCV conversion

Category Assignment

Organize transactions by custom income and expense categories

Period Filtering

Filter by 7 days, this month, last month, or custom date ranges

Real-Time Editing

Edit transaction details directly from the transaction history

Transaction Types

BudgetView supports two transaction types:
Record outgoing money for purchases, bills, or any spending.
  • Decreases wallet balance
  • Counts against budget limits
  • Displayed with red indicators

Creating Transactions

1

Select Transaction Type

Choose between “Gasto” (expense) or “Ingreso” (income) using the type buttons.
2

Enter Amount

Input the amount in USD or VES. The system shows equivalent value in the other currency.
3

Select Date

Choose the transaction date using the calendar picker (defaults to today).
4

Choose Category

Select from categories filtered by transaction type (income/expense).
5

Add Description (Optional)

Include a note up to 280 characters to remember transaction details.
6

Save Transaction

Submit to record the transaction and update wallet balance immediately.

Currency Input System

The dual-currency input system provides real-time conversion:
// Currency state management
const [amountCurrency, setAmountCurrency] = useState<"USD" | "VES">("USD")
const [formMonto, setFormMonto] = useState("")

// Real-time equivalent preview
const equivalentPreview = useMemo(() => {
  if (!parsedAmount || parsedAmount <= 0 || !bcvRate) {
    return null
  }

  if (amountCurrency === "USD") {
    return `≈ ${formatCurrency(parsedAmount * bcvRate, "VES")} BCV`
  }
  return `≈ ${currencyFormatter.format(parsedAmount / bcvRate)} USD`
}, [parsedAmount, amountCurrency, bcvRate])
When entering amounts in VES, the system converts to USD using the current BCV rate before storing.

Transaction Data Structure

type Transaction = {
  id: string
  monto: number              // Always stored in USD
  tipo: "gasto" | "ingreso"
  descripcion: string | null
  fecha_transaccion: string  // ISO 8601 timestamp
  categoria_id: string | null
  billetera_id: string       // Must be a specific wallet (not global)
  usuario_id: string
}

Period Filtering

View transactions across different time periods:
const start = startOfDay(subDays(now, 6))
const end = endOfDay(now)

Global Wallet Mode

When the “Global” wallet is selected, you can view all transactions across all wallets but cannot create new ones:
Global Mode Restrictions:
  • View-only mode for all transactions
  • Cannot create new transactions
  • Must select a specific wallet to record transactions
  • Useful for comprehensive financial overview
const isGlobalWallet = billeteraId === GLOBAL_WALLET_ID

if (!billeteraId || billeteraId === GLOBAL_WALLET_ID) {
  setFormError("Selecciona una billetera específica desde el encabezado")
  return
}

Transaction History

View all transactions in a scrollable list with:
  • Category Name: Transaction category with icon
  • Date: Formatted transaction date (dd/MMM/yyyy)
  • Description: Optional note displayed below category
  • Amount: Formatted amount with USD and BCV values
  • Type Badge: Visual indicator (Gasto/Ingreso)
  • Edit Button: Quick access to edit transaction
const dateFormatter = new Intl.DateTimeFormat("es-ES", {
  day: "numeric",
  month: "short",
  year: "numeric",
})

const currencyFormatter = new Intl.NumberFormat("es-ES", {
  style: "currency",
  currency: "USD",
})

Editing Transactions

1

Open Edit Dialog

Click the edit icon on any transaction in the history list.
2

Modify Fields

Update amount, type, category, date, or description as needed.
3

Save Changes

Submit to update the transaction and recalculate wallet balance.
Changing transaction type (income ↔ expense) automatically filters available categories.

Edit Form Validation

const handleEditSubmit = async (event: React.FormEvent) => {
  event.preventDefault()
  
  const parsedAmount = parseFloat(editMonto)
  if (Number.isNaN(parsedAmount) || parsedAmount <= 0) {
    setEditError("El monto debe ser mayor a 0.")
    return
  }

  if (!editCategoriaId) {
    setEditError("Selecciona una categoría válida.")
    return
  }

  if (!editFecha) {
    setEditError("Selecciona una fecha para la transacción.")
    return
  }

  // Update transaction in Supabase
}

Category Filtering

Categories are automatically filtered by transaction type:
const filteredCategories = useMemo(() => {
  return categories.filter((cat) => cat.tipo === formTipo)
}, [categories, formTipo])
When switching from “Gasto” to “Ingreso”, the category selection resets to ensure only compatible categories are shown.

Amount Validation

The system validates amounts before submission:
const handleMontoChange = (value: string) => {
  setFormMonto(value)

  if (!value) {
    setAmountError("Ingresa un monto mayor a 0.")
    return
  }

  const parsed = parseFloat(value)
  if (Number.isNaN(parsed) || parsed <= 0) {
    setAmountError("El monto debe ser mayor a 0.")
    return
  }

  if (amountCurrency === "VES" && !canUseVesInput) {
    setAmountError("Necesitamos la tasa BCV para convertir tu monto.")
    return
  }

  setAmountError(null)
}

Real-Time Updates

Transactions broadcast updates to other components:
// After creating/editing transaction
window.dispatchEvent(
  new CustomEvent("transactions:updated", {
    detail: { walletId: billeteraId },
  })
)

// Components listen for updates
window.addEventListener("transactions:updated", handleTransactionsUpdated)

Date Handling

Transactions store dates at noon to avoid timezone issues:
const fechaSeleccionada = new Date(formFecha)
fechaSeleccionada.setHours(12, 0, 0, 0)

const transactionData = {
  // ... other fields
  fecha_transaccion: fechaSeleccionada.toISOString(),
}

Best Practices

Always assign categories to transactions for accurate reporting and budgeting.
Add descriptions for unusual or important transactions to track context.
Record transactions daily to maintain accurate financial records.
Use different period filters to analyze spending patterns over time.
When using VES input, ensure BCV rate is loaded for accurate conversion.

Database Schema

CREATE TABLE transacciones (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  monto DECIMAL(12,2) NOT NULL,
  tipo VARCHAR(10) NOT NULL CHECK (tipo IN ('gasto', 'ingreso')),
  descripcion TEXT,
  fecha_transaccion TIMESTAMP WITH TIME ZONE NOT NULL,
  categoria_id UUID REFERENCES categorias(id),
  billetera_id UUID NOT NULL REFERENCES billeteras(id),
  usuario_id UUID NOT NULL REFERENCES auth.users(id),
  created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
All monetary amounts are stored in USD for consistency, with VES conversion calculated on display.

Build docs developers (and LLMs) love