Learn React By Building A React Finance Tracker.
Published: 2023-10-07 11:19:00

In today's fast paced world managing your finances effectively is a necessity. Keeping a close eye on your income and expenses can help you make informed financial decisions, save for your goals and achieve financial stability. Fortunately, technology has made this task more accessible and user-friendly than ever before. In this blog post, we will embark on a journey to create a powerful and customizable financial tracking tool using react.

You can view the [code](https://github.com/Pauline-Oraro/finance-tracker) and live [demo](https://finance-tracker-orpin.vercel.app/).

This is what we will be building;

![Financial Tracker](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wadm0udgp4kd72lho99m.PNG)

The user can;

- Add income and expenses which have a name and a cost.

- Remove/delete the transactions.

- View the balance.

- View their total income and expenses.

#### Table of contents

- [Prerequisites](#prerequisites).

- [Setting up the project](#setting).

- [Display the financial details](#financialDetails).

- [Disply the transaction details](#transactionDetails).

- [The financial tracker](#financialTracker)


## Prerequisites <a name="prerequisites"></a>
Before we dive into the tutorial, make sure you have the following;

- Node.js and npm- Ensure you have Node.js and npm(Node Package Manager) installed on your machine. You can download and install them from the [official Node.js website](https://nodejs.org/en).

- Basic understanding of React- Familiarize yourself with the basics of React if you haven't already. You can check out the [official react documentation](https://react.dev/learn) for a quick start.

- Code editor- You can use a code editor of your choice.

## Setting up the project <a name="setting"></a>
Let's start by creating a new react application using create-react-app. Open your terminal and run the following command;


```
npx create-react-app finance-tracker
```

This command will create a new React project named "finance-tracker". Once the project is created, navigate to the project directory;

```
cd finance-tracker
```
Next we are going to install a package that allows us to generate ID's, run the following command;

```
npm i uuid
```

Jump into the src folder and create a new folder called components. Within the components folder create other three folders.

- **moneyDetails**- It shows the balance, income and expenses. It has two files; **detail.js and details.css**.

- **transactionItem** - It contains the history of all transactions and has two files; **item.js and item.css.**

- **moneyManager** - It is the financial tracker which allows users to add, view and delete transactions. It has two files; **manager.js and manager.css**.

Here is what the folder structure should look like;

![finance tracker folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jbt1429t9sk1fc2vq9r7.PNG)

## Display the financial details <a name="financialDetails"></a>

```
import './details.css';

//responsible for rendering the balance, income and expenses
const MoneyDetails = props =>{
    //represent the financial values for balance, income and expenses
    const {balanceAmount, incomeAmount, expensesAmount} = props
    return (
        <div className="money-details-container">
            <div className="balance-container">
                <img 
                src = "/balance-sheet.png"
                alt="balance"
                className='details-img'
                />
                <div>
                    <p className='details-text'>Your Balance</p>
                    <p className='details-money' testid="balanceAmount"> Ksh {balanceAmount}</p>
                </div>
            </div>
            <div className='income-container'>
                <img 
                src = "/growth.png"
                alt='income'
                className='details-img'
                />
                <div>
                    <p className='details-text'>Your Income</p>
                    <p className='details-money' testid="incomeAmount">Ksh {incomeAmount}</p>
                </div>
            </div>
            <div className='expenses-container'>
                <img 
                src='/expenses.png'
                alt='expenses'
                className='details-img'
                />
                <div>
                    <p className='details-text'>Your Expenses</p>
                    <p className='details-money' testid="expensesAmount">Ksh {expensesAmount}</p>
                </div>
            </div>
        </div>
    )
}


export default MoneyDetails;
```

Let's head into the **details.js** file which is in the **moneyDetails** folder and type the above code.

The **MoneyDetails** component is responsible for rendering a summary of financial information which include balance, income and expenses with the provided values.

The component takes three props; **balanceAmount, incomeAmount and expensesAmount**. They represent the financial values for balance, income, expenses. Props are like arguments passed into react components. They are like function arguments in Javascript and attributes in HTML.

## Display all transactions details <a name="transactionDetails"></a>

```
//display the history of the user's transactions
const TransactionItem = props => {
    const {transactionDetails, deleteTransaction} = props
    //represent the details of a transaction
    const {id, title, amount, type} = transactionDetails
    
    //it is called when the delete button is clicked
    const onDeleteTransaction = () => {
        deleteTransaction(id)
    }

    return (
        <li className='table-row'>
            <p className='transaction-text'>{title}</p>
            <p className='transaction-text'>Ksh {amount}</p>
            <p className='transaction-text'>{type}</p>
            <div className='delete-container'>
                <button className='delete-button' type='button' onClick={onDeleteTransaction} testid="delete">
                    <img 
                    className='delete-img'
                    src="/bin.png"
                    alt='delete'
                    />
                </button>
            </div>
        </li>
    )
}

export default TransactionItem;
```
Let's head into the **item.js** file which is in the **transactionItem** folder and type the above code.

**TransactionItem** component is a functional component that displays all transaction details and allows the user to delete any transaction by clicking the delete button. It takes a single argument **"props"**.

The **transactionDetails and deleteTransaction** are destructured from the **"props"** object. It allows the component to access these props easily.

The **transactionDetails** is further destructured to extract four properties; **id, title, amount, type**. These properties represent the details of a transactions.

The **onDeleteTransaction** function is called when the delete button is clicked and responsible for deleting the transaction. It takes no arguments and simply calls the **deleteTransaction** function with the id of the current transaction as an argument.

The return statement contains the JSX code that defines the structure of the transaction item. The paragraph displays the title, amount and type of the transaction. When the delete button is clicked it triggers the **onDeleteTransaction**.

## The financial tracker <a name="financialTracker"></a>

```
import { v4 } from 'uuid';
import TransactionItem from '../transactionItem/item';
import MoneyDetails from '../moneyDetails/details';
import React from 'react';

//an array that represents transaction types: income and expenses
const transactionTypeOptions = [
    {
        optionId: 'INCOME',
        displayText: 'Income',
    },
    {
        optionId: 'EXPENSES',
        displayText: 'Expenses',
    },
];

class MoneyManager extends React.Component {
    state = {
        transactionsList: [],
        titleInput: '',
        amountInput: '',
        optionId: transactionTypeOptions[0].optionId,
    }

    deleteTransaction = id => {
        const {transactionsList} = this.state;
        const updatedTransactionList = transactionsList.filter(
        eachTransaction => id !== eachTransaction.id,
    )
        this.setState({
        transactionsList: updatedTransactionList,
    })
    }


    onAddTransaction = event => {
            event.preventDefault()
            const {titleInput, amountInput, optionId} = this.state
            const typeOption = transactionTypeOptions.find(
        eachTransaction => eachTransaction.optionId === optionId,
    )
            const {displayText} = typeOption
            const newTransaction = {
        id: v4(),
        title: titleInput,
        amount: parseInt(amountInput),
        type: displayText,
    }
    this.setState(prevState => ({
        transactionsList: [...prevState.transactionsList, newTransaction],
        titleInput: '',
        amountInput: '',
        optionId: transactionTypeOptions[0].optionId,
    }))
    }

    onChangeOptionId = event => {
    this.setState({optionId: event.target.value})
    }

    onChangeAmountInput = event => {
    this.setState({amountInput: event.target.value})
    }

    onChangeTitleInput = event => {
    this.setState({titleInput: event.target.value})
    }

    getExpenses = () => {
        const {transactionsList} = this.state
        let expensesAmount = 0

        transactionsList.forEach(eachTransaction => {
        if (eachTransaction.type === transactionTypeOptions[1].displayText) {
        expensesAmount += eachTransaction.amount
        }
    })

    return expensesAmount;
    }

    getIncome = () => {
        const {transactionsList} = this.state
        let incomeAmount = 0
        transactionsList.forEach(eachTransaction => {
        if (eachTransaction.type === transactionTypeOptions[0].displayText) {
        incomeAmount += eachTransaction.amount;
        }
    })

    return incomeAmount;
    }

    getBalance = () => {
    const {transactionsList} = this.state
    let balanceAmount = 0
    let incomeAmount = 0
    let expensesAmount = 0

    transactionsList.forEach(eachTransaction => {
        if (eachTransaction.type === transactionTypeOptions[0].displayText) {
        incomeAmount += eachTransaction.amount
        } else {
        expensesAmount += eachTransaction.amount
        }
    })

    balanceAmount = incomeAmount - expensesAmount

    return balanceAmount
    }

    render() {
        const {titleInput, amountInput, optionId, transactionsList} = this.state
        const balanceAmount = this.getBalance()
        const incomeAmount = this.getIncome()
        const expensesAmount = this.getExpenses()

        return (
        <div className="app-container">
        <div className="responsive-container">
            <div className="header-container">
            <h1 className="heading">Finance Tracker &#128176;</h1>
            </div>
            <MoneyDetails
                balanceAmount={balanceAmount}
                incomeAmount={incomeAmount}
                expensesAmount={expensesAmount}
            />
            <div className="transaction-details">
            <form className="transaction-form" onSubmit={this.onAddTransaction}>
                <h1 className="transaction-header">Add Transaction</h1>
                <label className="input-label" htmlFor="title">
                    TITLE
                </label>
                <input
                    type="text"
                    id="title"
                    value={titleInput}
                    onChange={this.onChangeTitleInput}
                    className="input"
                />
                <label className="input-label" htmlFor="amount">
                    AMOUNT
                </label>
                <input
                    type="text"
                    id="amount"
                    className="input"
                    value={amountInput}
                    onChange={this.onChangeAmountInput}
                />
                <label className="input-label" htmlFor="select">
                    TYPE
                </label>
                <select
                    id="select"
                    className="input"
                    value={optionId}
                    onChange={this.onChangeOptionId}
                >
                    {transactionTypeOptions.map(eachOption => (
                    <option key={eachOption.optionId} value={eachOption.optionId}>
                        {eachOption.displayText}
                    </option>
                ))}
                </select>
                <button type="submit" className="button">ADD</button>
            </form>
            <div className='hTransactions'>
            <div className="history-transactions">
                <h1 className="transaction-header">History</h1>
                <div className="transactions-table-container">
                    <ul className="transactions-table">
                    <li className="table-header">
                        <p className="table-header-cell" >Title</p>
                        <p className="table-header-cell" >Amount</p>
                        <p className="table-header-cell" >Type</p>
                    </li>
                    {transactionsList.map(eachTransaction => (
                    <TransactionItem
                        key={eachTransaction.id}
                        transactionDetails={eachTransaction}
                        deleteTransaction={this.deleteTransaction}
                    />
                    ))}
                </ul>
                </div>
            </div>
            </div>
                
            </div>
        </div>
        </div>
    )
    }
}

export default MoneyManager;
```
Let's head into the **manager.js** file which is in the **moneyManager** folder and type the above code.

The **MoneyManager** component serves as a financial tracker which allows users to add, view and delete transactions, categorize them as income or expenses.

The **transactionTypeOptions** is an array that contains two objects representing transaction types which are income and expenses. Each object has an **optionId** and a **displayText**.

**MoneyManager** is a class component and it contains;

 **state**- it keeps track of;
         - **transactionsList** - an array to store individual transactions.
         - **titleInput** - a string to represent the title of a new transaction.
         - **amountInput** - a string to represent the amount of a new transaction.
         - **optionId** - the selected transaction type from the dropdown menu. It is initially set to the first option from **transactionTypeOptions**.

 **deleteTransaction**- It takes an id as an argument and is responsible for removing a transaction from the **transactionsList** array. It uses the filter method to create a new array that contains transactions where the id does not match the id provided as an argument to the **deleteTransaction**. The state is then updated to reflect the updated list of transactions.

**onAddTransaction** - It is called when the user submits the transaction form. It prevents the default form submission extract the **titleInput, amountInput and optionId** from the component's state. It finds the corresponding transaction type either(income or expenses) from the **transactionTypeOptions** array. It creates a new transaction. It updates the component state, appends the **newTransaction** to the existing **transactionList**.

**onChangeOptionId, onChangeAmountInput and onChangeTitleInput** are used to handle changes in the input fields and the selection of transaction type. They update the corresponding fields in the component's state.

**getExpenses** calculates the total expenses by iterating through the **transactionsList** and summing up the amounts of transactions with the expense type.

**getIncome** calculates the total income by iterating through the **transactionsList** and summing up the amounts of transactions with the income type.

**getBalance** calculates the balance by subtracting total expenses from total income.

You can style your application with my css styling or you can customize your own styling. You can check out the [code](https://github.com/Pauline-Oraro/finance-tracker) and live [demo](https://finance-tracker-orpin.vercel.app/).