Expense Split Calculator JavaScript

👤 Sharing: AI
```javascript
function expenseSplitCalculator() {
  let participants = [];
  let expenses = [];

  function addParticipant(name) {
    participants.push({ name: name, owed: 0, paid: 0 });
  }

  function addExpense(description, amount, payer, beneficiaries) {
    if (amount <= 0) {
      console.error("Expense amount must be positive.");
      return;
    }

    const payerIndex = participants.findIndex((p) => p.name === payer);
    if (payerIndex === -1) {
      console.error(`Payer "${payer}" not found.`);
      return;
    }

    const beneficiaryIndices = beneficiaries.map((name) =>
      participants.findIndex((p) => p.name === name)
    );
    if (beneficiaryIndices.some((index) => index === -1)) {
      console.error("One or more beneficiaries not found.");
      return;
    }

    expenses.push({ description, amount, payer, beneficiaries });

    participants[payerIndex].paid += amount;

    const splitAmount = amount / beneficiaries.length;

    beneficiaries.forEach((beneficiary) => {
      const beneficiaryIndex = participants.findIndex(
        (p) => p.name === beneficiary
      );
      participants[beneficiaryIndex].owed += splitAmount;
    });
  }


  function calculateBalances() {
    return participants.map(participant => ({
      name: participant.name,
      balance: participant.paid - participant.owed
    }));
  }

  function generateSettlements() {
    const balances = calculateBalances();
    const settlements = [];

    // Separate participants into those who are owed money (creditors) and those who owe money (debtors)
    const creditors = balances.filter(b => b.balance > 0).sort((a, b) => b.balance - a.balance);
    const debtors = balances.filter(b => b.balance < 0).sort((a, b) => a.balance - b.balance);


    let i = 0;
    let j = 0;

    while (i < creditors.length && j < debtors.length) {
      const creditor = creditors[i];
      const debtor = debtors[j];

      const amount = Math.min(creditor.balance, Math.abs(debtor.balance));

      settlements.push({
        from: debtor.name,
        to: creditor.name,
        amount: amount
      });

      creditor.balance -= amount;
      debtor.balance += amount;

      if (creditor.balance === 0) {
        i++;
      }
      if (debtor.balance === 0) {
        j++;
      }
    }

    return settlements;
  }

  function getParticipants() {
    return participants.map(p => p.name); // Return just the names, not the entire object.
  }

  function getExpenses() {
    return expenses;
  }



  return {
    addParticipant,
    addExpense,
    calculateBalances,
    generateSettlements,
    getParticipants,
    getExpenses
  };
}


// Example usage (demonstrates the API, you can adapt to UI)
function runExample() {
  const calculator = expenseSplitCalculator();

  calculator.addParticipant("Alice");
  calculator.addParticipant("Bob");
  calculator.addParticipant("Charlie");

  calculator.addExpense("Dinner", 60, "Alice", ["Alice", "Bob", "Charlie"]);
  calculator.addExpense("Drinks", 30, "Bob", ["Bob", "Charlie"]);
  calculator.addExpense("Taxi", 15, "Charlie", ["Alice", "Charlie"]);


  console.log("Participants:", calculator.getParticipants());
  console.log("Expenses:", calculator.getExpenses());

  const balances = calculator.calculateBalances();
  console.log("Balances:", balances);

  const settlements = calculator.generateSettlements();
  console.log("Settlements:", settlements);
}


//runExample(); // Uncomment to run the example.  Remember to remove the comment before deploying, or it will execute on page load.


// **Important Considerations for UI Integration:**

// 1.  **UI Input:** You'll need to create HTML elements (input fields, buttons, etc.) for users to input participants, expenses, payer, and beneficiaries.

// 2.  **Event Handlers:**  Attach event listeners to your UI elements (e.g., button clicks) to call the functions in the `expenseSplitCalculator` object (`addParticipant`, `addExpense`, etc.).

// 3.  **Data Storage:**  You might want to store the participants and expenses in local storage or a database to persist data between sessions.

// 4.  **Display Results:**  Use the `calculateBalances` and `generateSettlements` functions, and update the UI to display the results to the user.  Use tables, lists, or other visual components to make the information clear.

// 5.  **Error Handling:**  Provide user-friendly error messages in the UI if there are issues with the input data (e.g., invalid amount, payer not found).

// 6. **Modularity:** The code is designed to be modular.  You can further break down the UI logic into separate functions or modules for better organization.
```
👁️ Viewed: 8

Comments