Interactive Budget Planner JavaScript, PHP, MySQL

👤 Sharing: AI
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Interactive Budget Planner</title>
    <link rel="stylesheet" href="style.css">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        /* Basic CSS for styling */
        body {
            font-family: sans-serif;
            margin: 20px;
        }

        #budgetForm {
            margin-bottom: 20px;
        }

        #budgetForm label {
            display: block;
            margin-bottom: 5px;
        }

        #budgetForm input[type="text"],
        #budgetForm input[type="number"],
        #budgetForm select {
            width: 200px;
            padding: 5px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
        }

        #budgetForm button {
            padding: 10px 15px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }

        #budgetForm button:hover {
            background-color: #3e8e41;
        }

        #budgetSummary {
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 20px;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }

        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }

        th {
            background-color: #f2f2f2;
        }

        #chartContainer {
            width: 80%;
            margin: 0 auto;
        }
    </style>
</head>
<body>

    <h1>Interactive Budget Planner</h1>

    <div id="budgetForm">
        <h2>Add Expense/Income</h2>
        <form id="inputForm">
            <label for="description">Description:</label>
            <input type="text" id="description" name="description" required><br>

            <label for="amount">Amount:</label>
            <input type="number" id="amount" name="amount" required><br>

            <label for="type">Type:</label>
            <select id="type" name="type">
                <option value="expense">Expense</option>
                <option value="income">Income</option>
            </select><br>

            <button type="button" onclick="addTransaction()">Add Transaction</button>
        </form>
    </div>

    <div id="budgetSummary">
        <h2>Budget Summary</h2>
        <p><b>Total Income:</b> <span id="totalIncome">0</span></p>
        <p><b>Total Expenses:</b> <span id="totalExpenses">0</span></p>
        <p><b>Remaining Balance:</b> <span id="remainingBalance">0</span></p>

        <h3>Transaction History</h3>
        <table id="transactionTable">
            <thead>
                <tr>
                    <th>Description</th>
                    <th>Amount</th>
                    <th>Type</th>
                    <th>Date</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>

    <div id="chartContainer">
        <canvas id="budgetChart"></canvas>
    </div>

    <script>
        let transactions = [];

        function addTransaction() {
            const description = document.getElementById('description').value;
            const amount = parseFloat(document.getElementById('amount').value);
            const type = document.getElementById('type').value;

            if (!description || isNaN(amount)) {
                alert('Please enter a valid description and amount.');
                return;
            }

            const transaction = {
                description: description,
                amount: amount,
                type: type,
                date: new Date().toLocaleDateString() // Add date
            };

            transactions.push(transaction);
            updateBudgetSummary();
            updateTransactionTable();
            updateChart();

            // Clear the form
            document.getElementById('inputForm').reset();

             //Save to database using AJAX
             saveTransactionToDB(transaction);

        }


        function deleteTransaction(index) {
            transactions.splice(index, 1);
            updateBudgetSummary();
            updateTransactionTable();
            updateChart();
        }

        function updateBudgetSummary() {
            let totalIncome = 0;
            let totalExpenses = 0;

            transactions.forEach(transaction => {
                if (transaction.type === 'income') {
                    totalIncome += transaction.amount;
                } else {
                    totalExpenses += transaction.amount;
                }
            });

            const remainingBalance = totalIncome - totalExpenses;

            document.getElementById('totalIncome').textContent = totalIncome.toFixed(2);
            document.getElementById('totalExpenses').textContent = totalExpenses.toFixed(2);
            document.getElementById('remainingBalance').textContent = remainingBalance.toFixed(2);
        }

        function updateTransactionTable() {
            const tableBody = document.getElementById('transactionTable').getElementsByTagName('tbody')[0];
            tableBody.innerHTML = ''; // Clear existing rows

            transactions.forEach((transaction, index) => {
                let row = tableBody.insertRow();
                let descriptionCell = row.insertCell(0);
                let amountCell = row.insertCell(1);
                let typeCell = row.insertCell(2);
                let dateCell = row.insertCell(3); //Date Cell
                let actionsCell = row.insertCell(4); //Actions Cell

                descriptionCell.textContent = transaction.description;
                amountCell.textContent = transaction.amount.toFixed(2);
                typeCell.textContent = transaction.type;
                dateCell.textContent = transaction.date;  //Set Date

                // Create a delete button
                let deleteButton = document.createElement('button');
                deleteButton.textContent = 'Delete';
                deleteButton.onclick = () => deleteTransaction(index);
                actionsCell.appendChild(deleteButton);


            });
        }


        let budgetChart; // Declare the chart variable

        function updateChart() {
            const income = transactions.filter(t => t.type === 'income').reduce((acc, t) => acc + t.amount, 0);
            const expenses = transactions.filter(t => t.type === 'expense').reduce((acc, t) => acc + t.amount, 0);

            const ctx = document.getElementById('budgetChart').getContext('2d');

            if (budgetChart) {
                budgetChart.destroy(); // Destroy the previous chart instance
            }

            budgetChart = new Chart(ctx, {
                type: 'pie',
                data: {
                    labels: ['Income', 'Expenses'],
                    datasets: [{
                        label: 'Budget Distribution',
                        data: [income, expenses],
                        backgroundColor: [
                            'rgba(75, 192, 192, 0.2)',
                            'rgba(255, 99, 132, 0.2)'
                        ],
                        borderColor: [
                            'rgba(75, 192, 192, 1)',
                            'rgba(255, 99, 132, 1)'
                        ],
                        borderWidth: 1
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            position: 'top',
                        },
                        title: {
                            display: true,
                            text: 'Budget Distribution'
                        }
                    }
                }
            });
        }

        function saveTransactionToDB(transaction) {
            const xhr = new XMLHttpRequest();
            xhr.open('POST', 'save_transaction.php', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

            xhr.onload = function() {
                if (xhr.status >= 200 && xhr.status < 300) {
                    console.log('Transaction saved successfully:', xhr.responseText);
                    // Optionally, you can update the transaction list from the database here
                    // loadTransactionsFromDB();
                } else {
                    console.error('Error saving transaction:', xhr.statusText);
                }
            };

            xhr.onerror = function() {
                console.error('Network error while saving transaction.');
            };

            const params = `description=${encodeURIComponent(transaction.description)}&amount=${encodeURIComponent(transaction.amount)}&type=${encodeURIComponent(transaction.type)}&date=${encodeURIComponent(transaction.date)}`;
            xhr.send(params);
        }


       // Load transactions from the database on page load (Optional - Implement in PHP first!)
        //window.onload = loadTransactionsFromDB;  //Implement loadTransactionsFromDB in the PHP

        // Initial update (if you have initial data)
        updateBudgetSummary();
        updateTransactionTable();
        updateChart();

    </script>
</body>
</html>
```

```php
<?php
// save_transaction.php

// Database configuration - Adjust these!
$servername = "localhost";
$username = "your_username"; // Replace with your MySQL username
$password = "your_password"; // Replace with your MySQL password
$dbname = "budget_planner"; // Replace with your database name

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

// Get data from the POST request
$description = $_POST["description"];
$amount = $_POST["amount"];
$type = $_POST["type"];
$date = $_POST["date"];

// Prepare and bind the SQL statement to prevent SQL injection
$stmt = $conn->prepare("INSERT INTO transactions (description, amount, type, transaction_date) VALUES (?, ?, ?, ?)");
$stmt->bind_param("sdss", $description, $amount, $type, $date); // "sdss" means: string, double, string, string

// Execute the statement
if ($stmt->execute() === TRUE) {
  echo "New record created successfully";
} else {
  echo "Error: " . $sql . "<br>" . $conn->error;
}

$stmt->close();
$conn->close();

?>
```

```sql
-- SQL to create the database and table (run this in your MySQL client)

CREATE DATABASE IF NOT EXISTS budget_planner;

USE budget_planner;

CREATE TABLE IF NOT EXISTS transactions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    description VARCHAR(255) NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    type ENUM('income', 'expense') NOT NULL,
    transaction_date DATE NOT NULL
);
```

```css
/* style.css */

body {
  font-family: sans-serif;
  margin: 20px;
}

#budgetForm {
  margin-bottom: 20px;
}

#budgetForm label {
  display: block;
  margin-bottom: 5px;
}

#budgetForm input[type="text"],
#budgetForm input[type="number"],
#budgetForm select {
  width: 200px;
  padding: 5px;
  margin-bottom: 10px;
  border: 1px solid #ccc;
}

#budgetForm button {
  padding: 10px 15px;
  background-color: #4CAF50;
  color: white;
  border: none;
  cursor: pointer;
}

#budgetForm button:hover {
  background-color: #3e8e41;
}

#budgetSummary {
  border: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 20px;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 10px;
}

th, td {
  border: 1px solid #ddd;
  padding: 8px;
  text-align: left;
}

th {
  background-color: #f2f2f2;
}

#chartContainer {
  width: 80%;
  margin: 0 auto;
}
```

**Explanation:**

**1. HTML (index.html):**

*   **Structure:** Sets up the basic HTML structure, including the `head` (title, CSS link, Chart.js library import) and `body`.
*   **Form:**  Creates a form (`budgetForm`) to input transaction details (description, amount, type).  The `onclick="addTransaction()"` on the button triggers the JavaScript function when the button is clicked.
*   **Budget Summary:**  Displays the total income, total expenses, and remaining balance.  These are updated dynamically by JavaScript.
*   **Transaction Table:** A table to display the transaction history.
*   **Chart Canvas:** A `<canvas>` element where the budget chart will be rendered using Chart.js.
*   **CSS Styling:** Basic inline CSS is provided, but it's generally better to put this in a separate `style.css` file. I've also included a separate `style.css` file (empty, but ready to use).
*   **JavaScript Link:** Links to the JavaScript code at the end of the body. This is important for performance, as it allows the HTML to load first.

**2. JavaScript (inside index.html):**

*   **`transactions` Array:**  An array to store the transaction objects. This is where you'll hold the data *temporarily* on the client-side.
*   **`addTransaction()` Function:**
    *   Gets values from the input fields.
    *   Validates the input.
    *   Creates a `transaction` object.
    *   Adds the `transaction` to the `transactions` array.
    *   Calls `updateBudgetSummary()`, `updateTransactionTable()`, and `updateChart()` to refresh the display.
    *   Clears the input form.
    *   Calls  `saveTransactionToDB()` to send the data to the server (PHP) for database storage.
*   **`deleteTransaction(index)` Function:**
    *   Removes a transaction from the `transactions` array based on its index.
    *   Updates the display.
*   **`updateBudgetSummary()` Function:**
    *   Calculates the total income, total expenses, and remaining balance based on the `transactions` array.
    *   Updates the corresponding HTML elements with the calculated values.
*   **`updateTransactionTable()` Function:**
    *   Clears the existing table rows.
    *   Iterates through the `transactions` array and creates a new row in the table for each transaction.
    *   Adds a "Delete" button to each row, which calls `deleteTransaction()` when clicked.
*   **`updateChart()` Function:**
    *   Calculates the total income and expenses from the `transactions` array.
    *   Uses Chart.js to create a pie chart visualizing the income and expense distribution.  It also destroys any existing chart to prevent memory leaks and ensure the chart is updated correctly.
*  **`saveTransactionToDB(transaction)` function:**
    *   Uses `XMLHttpRequest` (AJAX) to send the transaction data to the `save_transaction.php` script.
    *   Handles the response from the server (success or error).
*   **`window.onload = loadTransactionsFromDB;`  (Commented Out - Needs PHP Implementation)**
    *   This line is *commented out* because it relies on a `loadTransactionsFromDB()` function that would fetch data from the database when the page loads.  This functionality needs to be implemented in the PHP part of the application (see below).
*   **Initial Updates:**  Calls `updateBudgetSummary()`, `updateTransactionTable()`, and `updateChart()` when the page loads to initialize the display (even if the `transactions` array is initially empty).

**3. PHP (save_transaction.php):**

*   **Database Connection:**  Establishes a connection to the MySQL database using the provided credentials (server name, username, password, database name). **Important:**  Replace the placeholder values with your actual database credentials.
*   **Error Handling:**  Checks if the connection was successful. If not, it terminates the script and displays an error message.
*   **Data Retrieval:**  Retrieves the transaction data (description, amount, type, date) from the `$_POST` array.  This data is sent from the JavaScript code using AJAX.
*   **SQL Injection Prevention (Prepared Statements):**  Uses prepared statements to prevent SQL injection vulnerabilities. Prepared statements allow you to separate the SQL code from the data, making it much harder for attackers to inject malicious code into your database queries.
*   **SQL Query:** Constructs an SQL `INSERT` query to insert the transaction data into the `transactions` table.
*   **Query Execution:** Executes the SQL query using `mysqli_query()`.
*   **Result Handling:**  Checks if the query was executed successfully. If so, it displays a success message. Otherwise, it displays an error message.
*   **Connection Closure:**  Closes the database connection using `mysqli_close()`. This is important to release database resources.

**4. SQL (for creating the database and table):**

*   **`CREATE DATABASE IF NOT EXISTS budget_planner;`:** Creates a database named `budget_planner` if it doesn't already exist.
*   **`USE budget_planner;`:**  Selects the `budget_planner` database for use.
*   **`CREATE TABLE IF NOT EXISTS transactions (...)`:** Creates a table named `transactions` if it doesn't already exist.  The table has the following columns:
    *   `id`:  An auto-incrementing primary key (integer).
    *   `description`:  A string (VARCHAR) for the transaction description.
    *   `amount`:  A decimal number for the transaction amount.
    *   `type`:  An ENUM (enumeration) type that can only be 'income' or 'expense'.  This helps ensure data integrity.
    *   `transaction_date`: A DATE to store the transaction date.

**How to Run This:**

1.  **Set up a web server (like Apache or Nginx):** You'll need a web server to serve the HTML, CSS, and JavaScript files.
2.  **Install PHP:** Make sure PHP is installed and configured on your web server.
3.  **Install MySQL:** Install MySQL (or MariaDB) and create a database named `budget_planner`.
4.  **Create the `transactions` table:**  Run the SQL code provided above in your MySQL client (e.g., MySQL Workbench, phpMyAdmin) to create the table.
5.  **Configure the database connection:**  Open `save_transaction.php` and replace the placeholder database credentials with your actual MySQL username, password, and database name.
6.  **Place the files in your web server's document root:**  Put the `index.html`, `style.css`, and `save_transaction.php` files in the appropriate directory (usually `htdocs` for Apache on Windows, or `/var/www/html` on Linux).
7.  **Access the application in your browser:**  Open your web browser and go to `http://localhost/index.html` (or the correct URL for your setup).

**Important Considerations and Improvements:**

*   **Error Handling:** The PHP code has basic error handling, but you should add more robust error handling (e.g., logging errors to a file, displaying more informative error messages to the user).  The JavaScript also needs better error handling for the AJAX calls.
*   **Security:**
    *   **SQL Injection:**  The current PHP code uses prepared statements, which helps prevent SQL injection. However, always be vigilant about input validation and sanitization.
    *   **Cross-Site Scripting (XSS):**  Be careful about displaying user-provided data (e.g., transaction descriptions) without proper escaping.  Escaping converts potentially harmful characters into safe equivalents.  In PHP, you can use `htmlspecialchars()` for this.
*   **User Authentication:** For a real-world application, you'll want to add user authentication (login/registration) so that each user can manage their own budget.
*   **Data Persistence:** The current JavaScript code only stores the transaction data in memory. When the page is reloaded, the data is lost. You'll need to use a database (like MySQL) to store the data persistently.  The PHP `save_transaction.php` script handles saving to the database, but you'll also need a way to load the data from the database when the page loads (the `loadTransactionsFromDB()` function that is currently commented out).
*   **User Interface (UI):** The UI is very basic. Consider using a CSS framework (like Bootstrap or Tailwind CSS) to improve the appearance and responsiveness of the application.  You could also use a JavaScript framework (like React, Angular, or Vue.js) to build a more complex and interactive UI.
*   **Date Handling:** The JavaScript `toLocaleDateString()` method provides a basic date format.  For more control over date formats, consider using a dedicated date/time library like Moment.js or date-fns.
*   **Validation:** Implement more comprehensive client-side validation in JavaScript to prevent invalid data from being submitted to the server.
*   **Edit Functionality:** Add the ability to edit existing transactions.
*   **Categories:** Allow users to categorize their income and expenses (e.g., "Salary," "Rent," "Groceries"). This will make the budget planner more useful.
*   **Reporting:** Provide more detailed reporting and analysis of the budget data.
*   **Asynchronous Operations:** Use asynchronous JavaScript (async/await) to make the AJAX calls non-blocking. This will improve the user experience by preventing the UI from freezing while waiting for the server to respond.
*   **Modularity:**  Break the JavaScript code into smaller, more manageable functions and modules.
*   **Testing:** Write unit tests to ensure the code is working correctly.

This comprehensive example provides a solid foundation for building an interactive budget planner. Remember to adapt it to your specific needs and requirements.  Good luck!
👁️ Viewed: 7

Comments