How To Create A Fullstack Bank Statement Visualization App

John FáwọléJohn Fáwọlé
5 min read

Proper tracking of monetary flows is always helpful in personal finance. I participated in a recent hackathon where I built an MVP that users can utilize in visualizing their bank statements.

This blog is a break-down of this feature. You’ll learn how you can also build the same with Python for backend and Nextjs for frontend.

Interestingly, you’ll learn how to use some python libraries for data visualization, which are quite impressive.

Building the Backend

Let’s write our backend with Python. You can create a folder, and then a file called app.py for the program.

Step 1: Dependency Installation

Head to your terminal and install .

pip install Flask Flask-CORS

Step 2: Import Dependencies

Once these deps are installed via the terminal, they should also be imported into the program.

from flask import Flask, request, jsonify
from flask_cors import CORS
import re
from collections import Counter

These are important libraries in our application.

For those who are not aware, Flask is a web framework for Python applications. In the instant case, it will be useful for building our API routes and connecting them with the web successfully.

We will also be using Request, a native Python library for efficient HTTP interaction. It will be useful for accepting data from API routes that are sending information.

Along this line, Jsonify helps us in communicating back to the API we will create so our frontend and backend can communicate effectively well.

Now, you should bear in mind that we want our API to be accessible from any point, and this is where Cross-Origin-Resource Sharing becomes useful. By the way, browsers block this to checkmate security threats, but we are enabling it intentionally for what we want to do.

Moving on to Re and Counter, their main purposes is largely for pattern matching.

Step 3: App Initialization

This is where we initialize our Flask application where name is passed as the root path. Then we enabled CORS.

app = Flask(__name__)
CORS(app)

Step 4: Transaction Extraction

This function helps us extract the data we need from the provided bank statements. The sample bank statement we have has “send to” and “received from” pre-fixes for fund flows.

As a result, we are incorporating that into our program for easier catching. We created an POST API route for it called /paste .

def extract_transactions(text):
    sent_names = re.findall(r'Send to ([A-Z\s-]+)', text, re.IGNORECASE)
    sent_counts = Counter(sent_names)

    received_names = re.findall(r'Received from ([A-Z\s-]+)', text, re.IGNORECASE)
    received_counts = Counter(received_names)

    sent_data = [{'name': name, 'value': count} for name, count in sent_counts.items()]
    received_data = [{'name': name, 'value': count} for name, count in received_counts.items()]

    return sent_data, received_data

@app.route('/paste', methods=['POST'])

Step 5: Paste Transaction

Now, many bank statements have various formats of pdf and formatting that our program might not catch. Therefore, it is better to request customers paste their statements rather than upload them.

On this note, here is a function that does that.

def paste():
    data = request.get_json()
    transactions = data.get('transactions', '')

    sent_data, received_data = extract_transactions(transactions)

    return jsonify({'sent': sent_data, 'received': received_data})

if __name__ == '__main__':
    app.run(debug=True)

Immediately after declaring the function, we also ran the application.

Here is the full code:

from flask import Flask, request, jsonify
from flask_cors import CORS
import re
from collections import Counter

app = Flask(__name__)
CORS(app)

def extract_transactions(text):
    sent_names = re.findall(r'Send to ([A-Z\s-]+)', text, re.IGNORECASE)
    sent_counts = Counter(sent_names)

    received_names = re.findall(r'Received from ([A-Z\s-]+)', text, re.IGNORECASE)
    received_counts = Counter(received_names)

    sent_data = [{'name': name, 'value': count} for name, count in sent_counts.items()]
    received_data = [{'name': name, 'value': count} for name, count in received_counts.items()]

    return sent_data, received_data

@app.route('/paste', methods=['POST'])
def paste():
    data = request.get_json()
    transactions = data.get('transactions', '')

    sent_data, received_data = extract_transactions(transactions)

    return jsonify({'sent': sent_data, 'received': received_data})

if __name__ == '__main__':
    app.run(debug=True)

Creating the Pie Component

Add a PieCharts.js component. Here is the first slice of our frontend part.

Step 1: Initialize Nextjs

Run this in your terminal:

npx create-next-app@latest my-next-app

Step 2: Install Recharts

We have to install Recharts for our pie data representation:

npm install recharts

Step 3: Chart UI

The stage is set to build our pie-chart UI:

import { PieChart, Pie, Cell, Tooltip } from "recharts";

const COLORS = ["#ff4d4d", "#4d79ff", "#ffcc00", "#33cc33", "#ff66b2", "#9966ff"];

export default function CustomPieChart({ title, data }) {
  return (
    <div className="chart-box">
      <h2>{title}</h2>
      <PieChart width={500} height={500}>
        <Pie
          data={data}
          cx="50%"
          cy="50%"
          outerRadius={200}
          dataKey="value"
          label={({ name, percent }) => `${name} (${(percent * 100).toFixed(1)}%)`}
        >
          {data.map((_, index) => (
            <Cell key={index} fill={COLORS[index % COLORS.length]} />
          ))}
        </Pie>
        <Tooltip />
      </PieChart>
    </div>
  );
}

In the code above, we installed the necessary things we need from recharts, then set the colors and layout of our application.

Here is the full code:

import { PieChart, Pie, Cell, Tooltip } from "recharts";

const COLORS = ["#ff4d4d", "#4d79ff", "#ffcc00", "#33cc33", "#ff66b2", "#9966ff"];

export default function CustomPieChart({ title, data }) {
  return (
    <div className="chart-box">
      <h2>{title}</h2>
      <PieChart width={500} height={500}>
        <Pie
          data={data}
          cx="50%"
          cy="50%"
          outerRadius={200}
          dataKey="value"
          label={({ name, percent }) => `${name} (${(percent * 100).toFixed(1)}%)`}
        >
          {data.map((_, index) => (
            <Cell key={index} fill={COLORS[index % COLORS.length]} />
          ))}
        </Pie>
        <Tooltip />
      </PieChart>
    </div>
  );
}

Transaction Pasteing Interface

Create a PasteBankStatement.js page. You can paste this code:

import React, { useState } from 'react';
import CustomPieChart from '../components/PieCharts';
import styles from '../styles/PasteBankStatement.module.css';

const PasteBankStatement = () => {
  const [bankStatement, setBankStatement] = useState('');
  const [sentData, setSentData] = useState(null);
  const [receivedData, setReceivedData] = useState(null);

  const handleSubmit = async (event) => {
    event.preventDefault();

    const response = await fetch('/api/paste', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ transactions: bankStatement }),
    });

    if (response.ok) {
      const data = await response.json();
      setSentData(data.sent);
      setReceivedData(data.received);
    } else {
      const errorText = await response.text();
      console.error('Error:', errorText);
    }
  };

  return (
    <div className={styles.container}>
      <header className={styles.header}>
        <h1>Paste Your Bank Statement</h1>
      </header>
      <div className={styles.card}>
        <form onSubmit={handleSubmit} className={styles.form}>
          <textarea
            value={bankStatement}
            onChange={(e) => setBankStatement(e.target.value)}
            className={styles.textarea}
            placeholder="Paste your bank statement here..."
            required
          />
          <button type="submit" className={styles.submitButton}>
            Visualize
          </button>
        </form>
        <div className={styles.chartsContainer}>
          {sentData && (
            <div className={styles.chartBox}>
              <CustomPieChart title="Money Sent (Expenses)" data={sentData} />
            </div>
          )}
          {receivedData && (
            <div className={styles.chartBox}>
              <CustomPieChart title="Money Received (Income)" data={receivedData} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

export default PasteBankStatement;

Here is a brief rundown of what went on here:

  • importing the right libraries

  • linking API routes

  • handling the submit button

Demo

Run both the Python application and Nextjs program. Open your localhost, then paste this sample bank statement.

You should have something like this:

That’s it! Leave a comment if you find it helpful…

0
Subscribe to my newsletter

Read articles from John Fáwọlé directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

John Fáwọlé
John Fáwọlé

Web3 Technical Writer | Content Lead | Marketing Strategist | For Devs