Spending; //user's expenses
- String username;
- String pwd;
- //current total income - total
- double balance;
- // possible monthly savings, calculated using monthly income (most recent) assuming the data we have is for one year, and monthly and biweekly expenses, here you can assume yearly expenses that are recorded have already been paid.
- double monthlysavings;
- //should add constructor(s)
- User(String username,String password){}
-}
diff --git a/src/Wage.java b/src/Wage.java
deleted file mode 100644
index 777f173..0000000
--- a/src/Wage.java
+++ /dev/null
@@ -1,8 +0,0 @@
-
-public class Wage {
- String source;
- double amount;
- String Month;
-
- //should add contructor(s)
-}
diff --git a/src/main/java/edu/ferris/seng210/AppFrame.java b/src/main/java/edu/ferris/seng210/AppFrame.java
new file mode 100644
index 0000000..9efb0d4
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/AppFrame.java
@@ -0,0 +1,126 @@
+package edu.ferris.seng210;
+
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.panels.*;
+import edu.ferris.seng210.services.DisplayUpdateService;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+public class AppFrame extends JFrame {
+
+ DisplayUpdateService displayUpdateService;
+ JMenuBar navMenuBar;
+ JMenu navMenu;
+ JMenuItem homeNav, addItemNav, importNav, estimateNav, incomeReportNav, expenseReportNav, detailedReportNav, loginNav, createAccNav;
+
+ AppFrame(){
+ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ this.setMinimumSize(new Dimension(900,700));
+ this.setTitle("EWallet Application");
+
+ User user = new User("Default", "TempPassword!123");
+ displayUpdateService = new DisplayUpdateService(user);
+
+ LoginPanel loginPanel = new LoginPanel();
+ CreateAccountPanel createAccountPanel = new CreateAccountPanel();
+ HomePanel homePanel = new HomePanel(user);
+ ImportPanel importPanel = new ImportPanel(user, homePanel);
+ EstimatePanel estimatePanel = new EstimatePanel();
+ IncomeReportPanel incomeReportPanel = new IncomeReportPanel(user);
+ ExpenseReportPanel expenseReportPanel = new ExpenseReportPanel(user);
+ DetailedReportPanel detailedReportPanel = new DetailedReportPanel(user);
+ AddItemPanel addItemPanel = new AddItemPanel(user, expenseReportPanel, incomeReportPanel, homePanel);
+ addItemPanel.setName("Add Item Pane");
+ getContentPane().add(homePanel);
+ navMenuBar = new JMenuBar();
+ navMenu = new JMenu("Menu");
+ homeNav = new JMenuItem("
Home");
+ homeNav.setName("Home");
+ homeNav.addMouseListener(handleMenuClickAction(homePanel));
+
+ addItemNav = new JMenuItem("
Add Item");
+ addItemNav.setName("Add Item");
+ addItemNav.addMouseListener(handleMenuClickAction(addItemPanel));
+
+ importNav = new JMenuItem("
Import Tool");
+ importNav.setName("Import Tool");
+ importNav.addMouseListener(handleMenuClickAction(importPanel));
+
+ estimateNav = new JMenuItem("
Estimate Tool");
+ estimateNav.setName("Estimate Tool");
+ estimateNav.addMouseListener(handleMenuClickAction(estimatePanel));
+
+ incomeReportNav = new JMenuItem("
Income Report");
+ incomeReportNav.setName("Income Report");
+ incomeReportNav.addMouseListener(handleMenuClickAction(incomeReportPanel));
+
+ expenseReportNav = new JMenuItem("
Expense Report");
+ expenseReportNav.setName("Expense Report");
+ expenseReportNav.addMouseListener(handleMenuClickAction(expenseReportPanel));
+
+ detailedReportNav = new JMenuItem("
Detailed Report");
+ detailedReportNav.setName("Detailed Report");
+ detailedReportNav.addMouseListener(handleMenuClickAction(detailedReportPanel));
+
+ loginNav = new JMenuItem("
Login");
+ loginNav.setName("Login");
+ loginNav.addMouseListener(handleMenuClickAction(loginPanel));
+
+ createAccNav = new JMenuItem("
Create Account");
+ createAccNav.setName("Create Account");
+ createAccNav.addMouseListener(handleMenuClickAction(createAccountPanel));
+
+ navMenu.setFont(new Font(null, Font.PLAIN, 24));
+ homeNav.setFont(new Font(null, Font.PLAIN, 20));
+ addItemNav.setFont(new Font(null, Font.PLAIN, 20));
+ importNav.setFont(new Font(null, Font.PLAIN, 20));
+ estimateNav.setFont(new Font(null, Font.PLAIN, 20));
+ incomeReportNav.setFont(new Font(null, Font.PLAIN, 20));
+ expenseReportNav.setFont(new Font(null, Font.PLAIN, 20));
+ detailedReportNav.setFont(new Font(null, Font.PLAIN, 20));
+ loginNav.setFont(new Font(null, Font.PLAIN, 20));
+ createAccNav.setFont(new Font(null, Font.PLAIN, 20));
+
+ navMenu.add(homeNav);
+ navMenu.add(addItemNav);
+ navMenu.add(importNav);
+ navMenu.add(estimateNav);
+ navMenu.add(incomeReportNav);
+ navMenu.add(expenseReportNav);
+ navMenu.add(detailedReportNav);
+ navMenu.add(loginNav);
+ navMenu.add(createAccNav);
+ navMenuBar.add(navMenu);
+
+
+ this.setJMenuBar(navMenuBar);
+ this.setLayout(new CardLayout());
+ this.pack();
+ this.setVisible(true);
+ }
+
+ public MouseAdapter handleMenuClickAction(JComponent component) {
+ return new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+
+ super.mouseClicked(e);
+ getContentPane().removeAll();
+ getContentPane().add(component);
+ revalidate();
+ repaint();
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ super.mouseReleased(e);
+ revalidate();
+ repaint();
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/EWalletApp.java b/src/main/java/edu/ferris/seng210/EWalletApp.java
new file mode 100644
index 0000000..285bcb0
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/EWalletApp.java
@@ -0,0 +1,16 @@
+package edu.ferris.seng210;
+
+import edu.ferris.seng210.account.User;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EWalletApp {
+
+ public static List users = new ArrayList<>();
+ public static User activeUser = null;
+
+ public static void main(String[] args) {
+ AppFrame app = new AppFrame();
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/account/User.java b/src/main/java/edu/ferris/seng210/account/User.java
new file mode 100644
index 0000000..d9af3c9
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/account/User.java
@@ -0,0 +1,93 @@
+package edu.ferris.seng210.account;
+
+import edu.ferris.seng210.records.Currency;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.records.Wage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class User {
+ private List currencyRates;
+ private final List income = new ArrayList<>();
+ private final List expenses = new ArrayList<>();
+ private String username;
+ private String pwd;
+ private double balance;
+ private double totalIncome;
+ private double totalExpenses;
+
+ public User(String username, String password){
+ this.username = username;
+ this.pwd = password;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public String getPwd() {
+ return this.pwd;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public void setPwd(String password) {
+ this.pwd = password;
+ }
+
+ public void addExpense(Expense Ex) {
+ expenses.add(Ex);
+ }
+
+ public void addMonthlyIncome(Wage W) {
+ income.add(W);
+ }
+
+ public List getIncome() {
+ return this.income;
+ }
+
+ public List getExpenses() {
+ return this.expenses;
+ }
+
+ public void setBalance(double balance) {
+ this.balance = balance;
+ }
+
+ public double getBalance(){
+ return this.balance;
+ }
+
+ public void setTotalExpenses(double totalExpenses) {
+ this.totalExpenses = totalExpenses;
+ }
+
+ public double getTotalExpenses() {
+ return this.totalExpenses;
+ }
+
+ public double getTotalIncome() {
+ return this.totalIncome;
+ }
+
+ public void setTotalIncome(double totalIncome) {
+ this.totalIncome = totalIncome;
+ }
+
+ public void updateIncomeTotal() {
+ totalIncome = income.stream().map(Wage::getAmount).reduce(0D, Double::sum);
+ }
+
+ public void updateExpenseTotal() {
+ totalExpenses = expenses.stream().map(Expense::getAmount).reduce(0D, Double::sum);
+ }
+
+ public void updateBalance() {
+ balance = totalIncome - totalExpenses;
+ }
+}
+
diff --git a/src/main/java/edu/ferris/seng210/checker/PasswordChecker.java b/src/main/java/edu/ferris/seng210/checker/PasswordChecker.java
new file mode 100644
index 0000000..3e8e047
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/checker/PasswordChecker.java
@@ -0,0 +1,24 @@
+package edu.ferris.seng210.checker;
+
+import edu.ferris.seng210.csv.CsvCredentialService;
+import edu.ferris.seng210.records.Credentials;
+import java.io.IOException;
+import java.util.List;
+
+public class PasswordChecker {
+
+ public boolean check(String username, String password) {
+ CsvCredentialService credentialService = new CsvCredentialService();
+
+ try {
+ List currentCredentials = credentialService.readCredentials();
+ int accountFound = currentCredentials.indexOf(new Credentials(username, password));
+
+ return accountFound != -1;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/checker/PasswordComplexityChecker.java b/src/main/java/edu/ferris/seng210/checker/PasswordComplexityChecker.java
new file mode 100644
index 0000000..e8c8e47
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/checker/PasswordComplexityChecker.java
@@ -0,0 +1,10 @@
+package edu.ferris.seng210.checker;
+
+public class PasswordComplexityChecker {
+
+ public boolean check(String password) {
+ String passwordRegEx = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&+=])(?=\\S+$).{8,20}$";
+
+ return password.matches(passwordRegEx);
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/checker/UsernameChecker.java b/src/main/java/edu/ferris/seng210/checker/UsernameChecker.java
new file mode 100644
index 0000000..acc92aa
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/checker/UsernameChecker.java
@@ -0,0 +1,27 @@
+package edu.ferris.seng210.checker;
+
+import edu.ferris.seng210.csv.CsvCredentialService;
+import edu.ferris.seng210.records.Credentials;
+
+import java.io.IOException;
+import java.util.List;
+
+public class UsernameChecker {
+
+ public boolean exists(String username) {
+ CsvCredentialService credentialService = new CsvCredentialService();
+ try {
+ List currentCredentials = credentialService.readCredentials();
+
+ for (Credentials credential : currentCredentials) {
+ if (credential.username().equals(username)) {
+ return true;
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/constants/ExpenseFrequency.java b/src/main/java/edu/ferris/seng210/constants/ExpenseFrequency.java
new file mode 100644
index 0000000..d473a74
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/constants/ExpenseFrequency.java
@@ -0,0 +1,27 @@
+package edu.ferris.seng210.constants;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum ExpenseFrequency {
+
+ ONCE(1),
+ MONTHLY(12),
+ BIWEEKLY(24);
+
+ private final int frequency;
+
+ ExpenseFrequency(int frequency) {
+ this.frequency = frequency;
+ }
+
+ public int getFrequency() {
+ return frequency;
+ }
+
+ public static List getFrequencies() {
+ return Arrays.stream(ExpenseFrequency.values())
+ .map(ExpenseFrequency::getFrequency)
+ .toList();
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/constants/Months.java b/src/main/java/edu/ferris/seng210/constants/Months.java
new file mode 100644
index 0000000..e6440d0
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/constants/Months.java
@@ -0,0 +1,36 @@
+package edu.ferris.seng210.constants;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum Months {
+
+JANUARY("January"),
+ FEBRUARY("February"),
+ MARCH("March"),
+ APRIL("April"),
+ MAY("May"),
+ JUNE("June"),
+ JULY("July"),
+ AUGUST("August"),
+ SEPTEMBER("September"),
+ OCTOBER("October"),
+ NOVEMBER("November"),
+ DECEMBER("December");
+
+ private final String name;
+
+ Months(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static List getNames() {
+ return Arrays.stream(Months.values())
+ .map(Months::getName)
+ .toList();
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/csv/CsvCredentialService.java b/src/main/java/edu/ferris/seng210/csv/CsvCredentialService.java
new file mode 100644
index 0000000..709fc92
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/csv/CsvCredentialService.java
@@ -0,0 +1,53 @@
+package edu.ferris.seng210.csv;
+
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import edu.ferris.seng210.records.Credentials;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+public class CsvCredentialService {
+
+
+ public List readCredentials() throws IOException {
+ File credentialsCsv = new File("UserCredentials.csv");
+
+ return new CsvMapper()
+ .readerFor(Credentials.class)
+ .with(buildCsvSchemaForReadingCredentials())
+ .readValues(credentialsCsv)
+ .readAll();
+ }
+
+ public void writeCredentials(List credentials) throws IOException {
+ Path filePath = Path.of("UserCredentials.csv");
+
+ byte[] csvByteData = new CsvMapper()
+ .writer(buildCsvSchemaForWritingCredentials())
+ .writeValueAsBytes(credentials);
+
+ Files.write(filePath, csvByteData);
+ }
+
+ public CsvSchema buildCsvSchemaForWritingCredentials() {
+ return CsvSchema.builder()
+ .addColumn("username")
+ .addColumn("password")
+ .setColumnSeparator(',')
+ .build()
+ .withHeader();
+ }
+
+ public CsvSchema buildCsvSchemaForReadingCredentials() {
+ return CsvSchema.builder()
+ .setSkipFirstDataRow(true)
+ .addColumn("username")
+ .addColumn("password")
+ .setColumnSeparator(',')
+ .build();
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/interfaces/Transaction.java b/src/main/java/edu/ferris/seng210/interfaces/Transaction.java
new file mode 100644
index 0000000..596867f
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/interfaces/Transaction.java
@@ -0,0 +1,6 @@
+package edu.ferris.seng210.interfaces;
+
+public interface Transaction {
+ String getSource();
+ double getAmount();
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/AddItemPanel.java b/src/main/java/edu/ferris/seng210/panels/AddItemPanel.java
new file mode 100644
index 0000000..9e93e20
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/AddItemPanel.java
@@ -0,0 +1,240 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.DisplayUpdateService;
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.constants.Months;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.records.Wage;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+
+public class AddItemPanel extends JTabbedPane{
+
+ private final User user;
+ DisplayUpdateService displayUpdateService;
+ GridBagConstraints gbConst;
+ JPanel incomePane, expensePane;
+ JLabel addIncomeItemLbl, addExpenseItemLbl;
+ JLabel nameIncomeLbl, amountIncomeLbl, monthIncomeLbl;
+ JLabel nameExpenseLbl, amountExpenseLbl, frequencyExpLbl;
+ JTextField nameIncField, amountIncField, frequencyExpField;
+ JTextField nameExpField, amountExpField;
+ JButton addIncomeButton, addExpenseButton;
+ JComboBox monthComboBox;
+ public AddItemPanel(User user, ExpenseReportPanel expenseReportPanel, IncomeReportPanel incomeReportPanel, HomePanel homePanel) {
+ this.user = user;
+ displayUpdateService = new DisplayUpdateService(user);
+
+ incomePane = new JPanel();
+ expensePane = new JPanel();
+ expensePane.setName("Expense Pane");
+
+ monthComboBox = new JComboBox<>(Months.getNames().toArray());
+ monthComboBox.setName("Month");
+ monthComboBox.setFont(new Font(null,Font.PLAIN, 24));
+ monthComboBox.setSelectedIndex(0);
+
+ addIncomeButton = new JButton("Add");
+ addExpenseButton = new JButton("Add");
+
+ gbConst = new GridBagConstraints();
+ incomePane.setLayout(new GridBagLayout());
+ expensePane.setLayout(new GridBagLayout());
+
+ addIncomeItemLbl = new JLabel("Add Item");
+ nameIncomeLbl = new JLabel("Name");
+ amountIncomeLbl = new JLabel("Amount");
+ monthIncomeLbl = new JLabel("Month");
+
+ addExpenseItemLbl = new JLabel("Add Item");
+ nameExpenseLbl = new JLabel("Name");
+ amountExpenseLbl = new JLabel("Amount");
+ frequencyExpLbl = new JLabel("Freq.");
+
+ nameIncField = new JTextField();
+ nameIncField.setName("Income Name");
+ nameIncField.setPreferredSize(new Dimension(280, 50));
+ amountIncField = new JTextField();
+ amountIncField.setName("Income Amount");
+ amountIncField.setPreferredSize(new Dimension(280, 50));
+ frequencyExpField = new JTextField();
+ frequencyExpField.setName("Expense Frequency");
+ frequencyExpField.setPreferredSize(new Dimension(280, 50));
+
+ nameExpField = new JTextField();
+ nameExpField.setName("Expense Name");
+ nameExpField.setPreferredSize(new Dimension(280, 50));
+ amountExpField = new JTextField();
+ amountExpField.setName("Expense Amount");
+ amountExpField.setPreferredSize(new Dimension(280, 50));
+ monthComboBox.setPreferredSize(new Dimension(280, 50));
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(0,20,60,30);
+ addIncomeItemLbl.setFont(new Font(null, Font.PLAIN, 44));
+ incomePane.add(addIncomeItemLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ nameIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ incomePane.add(nameIncomeLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(10,10,30,30);
+ nameIncField.setFont(new Font(null, Font.PLAIN, 28));
+ incomePane.add(nameIncField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ amountIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ incomePane.add(amountIncomeLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(10,10,30,30);
+ amountIncField.setFont(new Font(null, Font.PLAIN, 28));
+ incomePane.add(amountIncField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ monthIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ incomePane.add(monthIncomeLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(10,10,30,30);
+ monthComboBox.setFont(new Font(null, Font.PLAIN, 28));
+ incomePane.add(monthComboBox, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 4;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(20,30,30,30);
+ addIncomeButton.setFont(new Font(null, Font.PLAIN, 28));
+ addIncomeButton.setPreferredSize(new Dimension(150,60));
+ addIncomeButton.setName("Add Income");
+ incomePane.add(addIncomeButton, gbConst);
+
+ addIncomeButton.addActionListener(addIncomeAction(incomeReportPanel, homePanel));
+
+ this.addTab("Add Income", incomePane);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.insets = new Insets(0,20,60,30);
+ addExpenseItemLbl.setFont(new Font(null, Font.PLAIN, 44));
+ expensePane.add(addExpenseItemLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ nameExpenseLbl.setFont(new Font(null, Font.PLAIN, 32));
+ expensePane.add(nameExpenseLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(10,10,30,30);
+ nameExpField.setFont(new Font(null, Font.PLAIN, 28));
+ expensePane.add(nameExpField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ amountExpenseLbl.setFont(new Font(null, Font.PLAIN, 32));
+ expensePane.add(amountExpenseLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(10,10,30,30);
+ amountExpField.setFont(new Font(null, Font.PLAIN, 28));
+ expensePane.add(amountExpField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,20,30,30);
+ frequencyExpLbl.setFont(new Font(null, Font.PLAIN, 32));
+ expensePane.add(frequencyExpLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(10,10,30,30);
+ frequencyExpField.setFont(new Font(null, Font.PLAIN, 28));
+ expensePane.add(frequencyExpField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 4;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(20,30,30,30);
+ addExpenseButton.setFont(new Font(null, Font.PLAIN, 28));
+ addExpenseButton.setName("Add Expense");
+ addExpenseButton.setPreferredSize(new Dimension(150,60));
+ expensePane.add(addExpenseButton, gbConst);
+
+ addExpenseButton.addActionListener(addExpenseAction(expenseReportPanel, homePanel));
+
+ this.addTab("Add expense", expensePane);
+ this.setFont(new Font(null, Font.PLAIN, 24));
+ }
+
+ public ActionListener addIncomeAction(IncomeReportPanel incomeReportPanel, HomePanel homePanel) {
+ return e -> {
+ if(e.getSource() == addIncomeButton) {
+
+ user.addMonthlyIncome(new Wage(nameIncField.getText(), Double.parseDouble(amountIncField.getText()), monthComboBox.getSelectedItem().toString()));
+ user.updateIncomeTotal();
+ user.updateBalance();
+
+ displayUpdateService.updateIncomeTable();
+ displayUpdateService.updateDetailedTable();
+
+ homePanel.updateTotals();
+
+ incomeReportPanel.updateSources();
+ incomeReportPanel.updateIncome();
+
+ nameIncField.setText("");
+ monthComboBox.setSelectedItem(0);
+ amountIncField.setText("");
+ }
+ };
+ }
+
+ public ActionListener addExpenseAction(ExpenseReportPanel expenseReportPanel, HomePanel homePanel) {
+ return e -> {
+ if(e.getSource() == addExpenseButton) {
+
+ user.addExpense(new Expense(nameExpField.getText(), Double.parseDouble(amountExpField.getText()), Integer.parseInt(frequencyExpField.getText())));
+ displayUpdateService.updateExpenseTable();
+ displayUpdateService.updateDetailedTable();
+
+ user.updateExpenseTotal();
+ user.updateBalance();
+
+ homePanel.updateTotals();
+
+ expenseReportPanel.updateSources();
+ expenseReportPanel.updateTotalExpense();
+
+ nameExpField.setText("");
+ frequencyExpField.setText("");
+ amountExpField.setText("");
+
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/CreateAccountPanel.java b/src/main/java/edu/ferris/seng210/panels/CreateAccountPanel.java
new file mode 100644
index 0000000..7f3f1c0
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/CreateAccountPanel.java
@@ -0,0 +1,105 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.UserCreationService;
+import edu.ferris.seng210.checker.UsernameChecker;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+
+public class CreateAccountPanel extends JPanel {
+
+ JLabel usernameLbl, passwordLbl, confPasswordLbl, createAccLbl;
+ GridBagConstraints gbConst;
+ static JTextField usernameField, passwordField, confPasswordField;
+ JButton createAccBtn;
+ String username, password, confPassword;
+
+ public CreateAccountPanel() {
+ usernameLbl = new JLabel("Enter Username:");
+ passwordLbl = new JLabel("Enter Password:");
+ confPasswordLbl = new JLabel("Confirm Password:");
+ createAccLbl = new JLabel("Create Account");
+ gbConst = new GridBagConstraints();
+ this.setLayout(new GridBagLayout());
+
+ usernameField = new JTextField();
+ usernameField.setPreferredSize(new Dimension(200, 40));
+ passwordField = new JTextField();
+ passwordField.setPreferredSize(new Dimension(200, 40));
+ confPasswordField = new JTextField();
+ confPasswordField.setPreferredSize(new Dimension(200, 40));
+
+ createAccBtn = new JButton("Create Account");
+ createAccBtn.setPreferredSize(new Dimension(200, 40));
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(0, 20, 40, 20);
+ createAccLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(createAccLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0, 40, 40, 0);
+ usernameLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(usernameLbl, gbConst);
+
+ gbConst.gridx = -1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(20, 0, 40, 40);
+ usernameField.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(usernameField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0, 40, 40, 0);
+ passwordLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(passwordLbl, gbConst);
+
+ gbConst.gridx = -1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(20, 0, 40, 40);
+ passwordField.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(passwordField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(0, 40, 40, 0);
+ confPasswordLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(confPasswordLbl, gbConst);
+
+ gbConst.gridx = -1;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(20, 0, 40, 40);
+ confPasswordField.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(confPasswordField, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 4;
+ gbConst.insets = new Insets(20, 20, 20, 20);
+ createAccBtn.setFont(new Font(null, Font.PLAIN, 14));
+ this.add(createAccBtn, gbConst);
+
+ createAccBtn.addActionListener(createAccountAction());
+ }
+
+ public ActionListener createAccountAction() {
+ return e -> {
+ if (e.getSource() == createAccBtn) {
+
+ UserCreationService userCreationService = new UserCreationService();
+ userCreationService.create(usernameField.getText(), passwordField.getText());
+ clearCredentialFields();
+
+ }
+ };
+ }
+
+ private void clearCredentialFields() {
+ usernameField.setText("");
+ passwordField.setText("");
+ confPasswordField.setText("");
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/DetailedReportPanel.java b/src/main/java/edu/ferris/seng210/panels/DetailedReportPanel.java
new file mode 100644
index 0000000..aee5f06
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/DetailedReportPanel.java
@@ -0,0 +1,86 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.DisplayUpdateService;
+import edu.ferris.seng210.services.ReportService;
+import edu.ferris.seng210.account.User;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.awt.event.ActionListener;
+
+public class DetailedReportPanel extends JPanel {
+
+ private final User user;
+ public static DefaultTableModel model;
+ DefaultTableCellRenderer centerRenderer;
+ public static JScrollPane jScrollPane;
+ Object[][] tableVals;
+ String[] columnHeadings;
+ public static JTable detailedTable;
+ JLabel detaileReportTxt;
+ JButton exportReport;
+ DisplayUpdateService displayUpdateService;
+ public DetailedReportPanel(User user) {
+ this.user = user;
+ displayUpdateService = new DisplayUpdateService(user);
+
+ this.setLayout(new BorderLayout());
+ detaileReportTxt = new JLabel("Detailed Report");
+ detaileReportTxt.setFont(new Font(null, Font.PLAIN, 40));
+ detaileReportTxt.setHorizontalAlignment(JLabel.CENTER);
+ this.add(detaileReportTxt, BorderLayout.PAGE_START);
+ centerRenderer = new DefaultTableCellRenderer();
+ columnHeadings = new String[]{"Type","Source","Amount", "Month / Freq"};
+ tableVals = new Object[user.getIncome().size() + user.getExpenses().size()][4];
+ model = new DefaultTableModel(tableVals, columnHeadings); // setting up table model
+ detailedTable = new JTable(model) {
+ public boolean isCellEditable(int row, int column) { // restricting cell editing
+ return false;
+ }
+ };
+ detailedTable.setName("Detailed Report Table");
+ jScrollPane = new JScrollPane(detailedTable);
+
+ centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+ for (int i = 0; i < detailedTable.getColumnCount(); i++) {
+ detailedTable.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
+ }
+ detailedTable.setDefaultRenderer(String.class, centerRenderer);
+
+ detailedTable.setFont(new Font(null, Font.PLAIN, 24));
+ detailedTable.setRowHeight(45);
+ detailedTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+ detailedTable.getTableHeader().setReorderingAllowed(false);
+ detailedTable.setFocusable(true);
+ detailedTable.setRowSelectionAllowed(true);
+ detailedTable.setCellSelectionEnabled(true);
+ detailedTable.getTableHeader().setFont(new Font(null, Font.PLAIN, 32));
+ detailedTable.setShowVerticalLines(false);
+
+ this.add(jScrollPane, BorderLayout.CENTER);
+
+ exportReport = new JButton("Export to CSV");
+ exportReport.addActionListener(exportReportAction());
+ exportReport.setSize(new Dimension(200,60));
+ exportReport.setFont(new Font(null, Font.PLAIN, 24));
+
+ JPanel lowerPanel = new JPanel();
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ lowerPanel.add(exportReport, BorderLayout.CENTER);
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ this.add(lowerPanel, BorderLayout.SOUTH);
+ }
+
+ public ActionListener exportReportAction() {
+ return e -> {
+ ReportService reportService = new ReportService();
+ try {
+ reportService.exportDetailedReport(user);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ };
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/EstimatePanel.java b/src/main/java/edu/ferris/seng210/panels/EstimatePanel.java
new file mode 100644
index 0000000..1f207b9
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/EstimatePanel.java
@@ -0,0 +1,91 @@
+package edu.ferris.seng210.panels;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+
+public class EstimatePanel extends JPanel {
+
+ GridBagConstraints gbConst;
+ JLabel estimateTitleLbl, nameLbl, priceLbl, estimateLbl, estimateAmtLbl;
+ JTextField nameField, priceField;
+ JButton estimateButton;
+ public EstimatePanel() {
+ this.setLayout(new GridBagLayout());
+ gbConst = new GridBagConstraints();
+
+ estimateTitleLbl = new JLabel("Estimate Tool");
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(10,20,30,30);
+ estimateTitleLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(estimateTitleLbl, gbConst);
+
+ estimateLbl = new JLabel("Estimate:");
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(10,0,30,0);
+ estimateLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(estimateLbl, gbConst);
+
+ estimateAmtLbl = new JLabel("0 days");
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(10,0,30,0);
+ estimateAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(estimateAmtLbl, gbConst);
+
+ nameLbl = new JLabel("Item Name");
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(10,20,30,30);
+ nameLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(nameLbl, gbConst);
+
+ nameField = new JTextField();
+ nameField.setPreferredSize(new Dimension(280, 50));
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(10,10,30,30);
+ nameField.setFont(new Font(null, Font.PLAIN, 28));
+ this.add(nameField, gbConst);
+
+ priceLbl = new JLabel("Item Price");
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(10,20,30,30);
+ priceLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(priceLbl, gbConst);
+
+ priceField = new JTextField();
+ priceField.setPreferredSize(new Dimension(280, 50));
+ gbConst.gridx = 1;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(10,10,30,30);
+ priceField.setFont(new Font(null, Font.PLAIN, 28));
+ this.add(priceField, gbConst);
+
+ estimateButton = new JButton("Get Estimate");
+ estimateButton.addActionListener(estimateAction());
+ estimateButton.setPreferredSize(new Dimension(220, 60));
+ gbConst.gridx = 0;
+ gbConst.gridy = 4;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(30,30,30,30);
+ estimateButton.setFont(new Font(null, Font.PLAIN, 28));
+ this.add(estimateButton, gbConst);
+
+ }
+
+ public ActionListener estimateAction() {
+ return e -> {
+ if(e.getSource() == estimateButton) {
+ System.out.println("Get Estimate Button Clicked.");
+ nameField.setText("");
+ priceField.setText("");
+ }
+ };
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/ExpenseReportPanel.java b/src/main/java/edu/ferris/seng210/panels/ExpenseReportPanel.java
new file mode 100644
index 0000000..4e6aaa6
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/ExpenseReportPanel.java
@@ -0,0 +1,204 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.FilterService;
+import edu.ferris.seng210.services.ReportService;
+import edu.ferris.seng210.constants.ExpenseFrequency;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.account.User;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.List;
+
+public class ExpenseReportPanel extends JPanel {
+ private final User user;
+ public static DefaultTableModel model;
+ DefaultTableCellRenderer centerRenderer;
+ public static JScrollPane jScrollPane;
+ Object[][] tableVals;
+ String[] columnHeadings;
+ public static JTable spendingTable;
+ JLabel expenseText;
+ JLabel totalExpenseLbl, totalFilteredExpenseLbl, filterTxt ;
+ public static JLabel totalExpenseAmtLbl, totalFilteredExpenseAmtLbl;
+ JButton exportReport, applyFilter;
+ GridBagConstraints gbConst;
+ JPanel upperPanel;
+ JComboBox frequencySelector;
+ public static JComboBox typeSelector;
+
+ public ExpenseReportPanel(User user) {
+ this.setLayout(new BorderLayout());
+ this.user = user;
+
+ expenseText = new JLabel("Expense Report");
+ expenseText.setFont(new Font(null, Font.PLAIN, 40));
+ expenseText.setHorizontalAlignment(JLabel.CENTER);
+
+ gbConst = new GridBagConstraints();
+ upperPanel = new JPanel();
+ upperPanel.setLayout(new GridBagLayout());
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 4;
+ gbConst.insets = new Insets(20,0,20,0);
+ upperPanel.add(expenseText, gbConst);
+
+ totalExpenseLbl = new JLabel("Expense");
+ totalExpenseLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridwidth = 1;
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,20,20,0);
+ upperPanel.add(totalExpenseLbl,gbConst);
+
+ totalExpenseAmtLbl = new JLabel("0.00");
+ totalExpenseAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,5);
+ upperPanel.add(totalExpenseAmtLbl,gbConst);
+
+ totalFilteredExpenseLbl = new JLabel("Expenses (Filtered)");
+ totalFilteredExpenseLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 2;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,5);
+ upperPanel.add(totalFilteredExpenseLbl,gbConst);
+
+ totalFilteredExpenseAmtLbl = new JLabel("0.00");
+ totalFilteredExpenseAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 3;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,20);
+ upperPanel.add(totalFilteredExpenseAmtLbl,gbConst);
+
+ filterTxt = new JLabel("Apply a filter");
+ filterTxt.setFont(new Font(null, Font.PLAIN, 24));
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,0);
+ upperPanel.add(filterTxt,gbConst);
+
+ frequencySelector = new JComboBox<>(ExpenseFrequency.getFrequencies().toArray());
+ frequencySelector.setFont(new Font(null, Font.PLAIN, 24));
+ frequencySelector.setPreferredSize(new Dimension(200,50));
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(frequencySelector,gbConst);
+
+ FilterService filterService = new FilterService<>();
+ typeSelector = new JComboBox<>(filterService.getSources(user.getExpenses()).toArray());
+ typeSelector.setFont(new Font(null, Font.PLAIN, 24));
+ typeSelector.setPreferredSize(new Dimension(200,50));
+ gbConst.gridx = 2;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(typeSelector,gbConst);
+
+ applyFilter = new JButton("Filter");
+ applyFilter.addActionListener(filterAction(filterService));
+ applyFilter.setFont(new Font(null, Font.PLAIN, 24));
+ gbConst.gridx = 3;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(applyFilter,gbConst);
+
+ this.add(upperPanel, BorderLayout.PAGE_START);
+
+ centerRenderer = new DefaultTableCellRenderer();
+ columnHeadings = new String[]{"Source","Amount", "Frequency"};
+ tableVals = new Object[user.getExpenses().size()][3];
+ model = new DefaultTableModel(tableVals, columnHeadings);
+ spendingTable = new JTable(model) {
+ public boolean isCellEditable(int row, int column) { // restricting cell editing
+ return false;
+ }
+ };
+ jScrollPane = new JScrollPane(spendingTable);
+
+ centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+ for (int i = 0; i < spendingTable.getColumnCount(); i++) {
+ spendingTable.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
+ }
+ spendingTable.setDefaultRenderer(String.class, centerRenderer);
+
+ spendingTable.setFont(new Font(null, Font.PLAIN, 24));
+ spendingTable.setRowHeight(45);
+ spendingTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+ spendingTable.getTableHeader().setReorderingAllowed(false);
+ spendingTable.setFocusable(true);
+ spendingTable.setRowSelectionAllowed(true);
+ spendingTable.setCellSelectionEnabled(true);
+ spendingTable.getTableHeader().setFont(new Font(null, Font.PLAIN, 32));
+ spendingTable.setShowVerticalLines(false);
+ spendingTable.setName("Expense Table");
+
+ this.add(jScrollPane, BorderLayout.CENTER);
+
+ exportReport = new JButton("Export to CSV");
+ exportReport.addActionListener(exportToCsvAction(filterService));
+ exportReport.setSize(new Dimension(200,60));
+ exportReport.setFont(new Font(null, Font.PLAIN, 24));
+
+ JPanel lowerPanel = new JPanel();
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ lowerPanel.add(exportReport, BorderLayout.CENTER);
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ this.add(lowerPanel, BorderLayout.SOUTH);
+
+ }
+
+ public void updateTotalExpense() {
+ totalExpenseAmtLbl.setText(String.format("$%.2f", user.getTotalExpenses()));
+ }
+
+ public void updateSources() {
+ typeSelector.removeAllItems();
+
+ for(Object source : new FilterService().getSources(user.getExpenses())){
+ typeSelector.addItem(source);
+ }
+ }
+
+ public ActionListener exportToCsvAction(FilterService filterService) {
+ return e -> {
+ if(e.getSource() == exportReport) {
+ ReportService reportService = new ReportService();
+ try {
+ List filteredSpending = filterService.filterByFrequency(user.getExpenses(), Integer.parseInt(frequencySelector.getSelectedItem().toString()));
+ filteredSpending = filterService.filterBySource(filteredSpending, (String)typeSelector.getItemAt(typeSelector.getSelectedIndex()));
+
+ reportService.exportExpenseReport(user, filteredSpending);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ };
+ }
+
+ public ActionListener filterAction(FilterService filterService) {
+ return e -> {
+ if(e.getSource() == applyFilter) {
+ List filteredSpending = filterService.filterByFrequency(user.getExpenses(), Integer.parseInt(frequencySelector.getSelectedItem().toString()));
+ filteredSpending = filterService.filterBySource(filteredSpending, (String)typeSelector.getItemAt(typeSelector.getSelectedIndex()));
+ model.setNumRows(filteredSpending.size());
+ int i = 0;
+ double expenseSum = 0.00f;
+ for(Expense exp : filteredSpending) {
+ spendingTable.setValueAt(exp.getSource(), i, 0);
+ spendingTable.setValueAt(String.format("$%.2f",exp.getAmount()), i, 1);
+ spendingTable.setValueAt(String.valueOf(exp.yearlyFrequency()), i, 2);
+ ++i;
+ expenseSum += exp.getAmount();
+ }
+ totalFilteredExpenseAmtLbl.setText(String.format("$%.2f",expenseSum));
+ }
+ };
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/HomePanel.java b/src/main/java/edu/ferris/seng210/panels/HomePanel.java
new file mode 100644
index 0000000..3b3421c
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/HomePanel.java
@@ -0,0 +1,79 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.account.User;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class HomePanel extends JPanel {
+ private final User user;
+ JLabel summaryTxt, totalIncomeLbl ,totalExpensesLbl, totalSavingsLbl;
+ public static JLabel totalExpensesAmtLbl, totalSavingsAmtLbl, totalIncomeAmtLbl;
+ GridBagConstraints gbConst;
+ public HomePanel(User user) {
+ this.user = user;
+ summaryTxt = new JLabel("User Summary");
+ totalIncomeLbl = new JLabel("Total Income: ");
+ totalIncomeAmtLbl = new JLabel("$0.00");
+ totalIncomeAmtLbl.setName("Total Income Amount");
+ totalExpensesLbl = new JLabel("Total Expenses: ");
+ totalExpensesAmtLbl = new JLabel("$0.00");
+ totalExpensesAmtLbl.setName("Total Expenses Amount");
+ totalSavingsLbl = new JLabel("Total Savings: ");
+ totalSavingsAmtLbl = new JLabel("$0.00");
+ totalSavingsAmtLbl.setName("Total Savings Amount");
+ gbConst = new GridBagConstraints();
+ this.setLayout(new GridBagLayout());
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(20,20,60,20);
+ summaryTxt.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(summaryTxt, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(20,40,20,5);
+ totalIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalIncomeLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(20,10,20,40);
+ totalIncomeAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalIncomeAmtLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(20,40,20,5);
+ totalExpensesLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalExpensesLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(20,10,20,40);
+ totalExpensesAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalExpensesAmtLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(20,40,40,5);
+ totalSavingsLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalSavingsLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(20,10,40,40);
+ totalSavingsAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ this.add(totalSavingsAmtLbl, gbConst);
+ }
+
+ public void updateTotals() {
+ HomePanel.totalExpensesAmtLbl.setText(String.format("$%.2f", user.getTotalExpenses()));
+ HomePanel.totalIncomeAmtLbl.setText(String.format("$%.2f", user.getTotalIncome()));
+ HomePanel.totalSavingsAmtLbl.setText(String.format("$%.2f", user.getBalance()));
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/ImportPanel.java b/src/main/java/edu/ferris/seng210/panels/ImportPanel.java
new file mode 100644
index 0000000..fa6b461
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/ImportPanel.java
@@ -0,0 +1,140 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.DisplayUpdateService;
+import edu.ferris.seng210.services.ImportService;
+import edu.ferris.seng210.account.User;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+public class ImportPanel extends JPanel {
+
+ private final User user;
+ DisplayUpdateService displayUpdateService;
+ GridBagConstraints gbConst;
+ JLabel importLbl, selectFileLbl, selectTypeLbl, descriptionLbl;
+ JButton selectFileButton, importButton;
+ JFileChooser fileChooser;
+ String[] typesOfImports = {"Income", "Expense"};
+ JComboBox options;
+ File userFile;
+ public ImportPanel(User user, HomePanel homePanel) {
+
+ this.user = user;
+
+ displayUpdateService = new DisplayUpdateService(user);
+
+ fileChooser = new JFileChooser();
+
+ this.setLayout(new GridBagLayout());
+ gbConst = new GridBagConstraints();
+ options = new JComboBox<>(typesOfImports);
+ options.setSelectedIndex(0);
+
+ importLbl = new JLabel("Import From File");
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(10,30,20,30);
+ importLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(importLbl, gbConst);
+
+ selectFileButton = new JButton("File");
+ selectFileButton.addActionListener(selectFileAction());
+
+ selectFileLbl = new JLabel("Select File");
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(30,30,20,0);
+ selectFileLbl.setFont(new Font(null, Font.PLAIN, 24));
+ this.add(selectFileLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(30,0,20,30);
+ selectFileButton.setFont(new Font(null, Font.PLAIN, 24));
+ this.add(selectFileButton, gbConst);
+
+ selectTypeLbl = new JLabel("Select Type");
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(30,30,20,0);
+ selectTypeLbl.setFont(new Font(null, Font.PLAIN, 24));
+ this.add(selectTypeLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(30,0,20,30);
+ options.setFont(new Font(null, Font.PLAIN, 24));
+ this.add(options, gbConst);
+
+ descriptionLbl = new JLabel("Note: Only csv files are supported. The format of the csv file matters. The first line of the file needs to contain \"source,amount,month\" or \"source,amount,frequency\", depending on the type Once you select a file, click the import button.");
+ gbConst.gridwidth = 2;
+ gbConst.gridheight = 2;
+ gbConst.gridx = 0;
+ gbConst.gridy = 3;
+ gbConst.insets = new Insets(30,30,30,30);
+ descriptionLbl.setFont(new Font(null, Font.PLAIN, 20));
+ this.add(descriptionLbl, gbConst);
+
+ importButton = new JButton("Import");
+ importButton.addActionListener(importAction(homePanel));
+ gbConst.gridheight = 1;
+ gbConst.gridx = 0;
+ gbConst.gridy = 5;
+ gbConst.insets = new Insets(30,0,30,30);
+ importButton.setFont(new Font(null, Font.PLAIN, 24));
+ this.add(importButton, gbConst);
+
+ }
+
+ public ActionListener importAction(HomePanel homePanel) {
+ return e -> {
+
+ if(userFile == null) JOptionPane.showMessageDialog(null,"No file selected!", "Warning User!", JOptionPane.ERROR_MESSAGE);
+
+ ImportService importService = new ImportService();
+
+ if(options.getItemAt(options.getSelectedIndex()).equalsIgnoreCase("income")) {
+
+ importService.incomeFromCsv(userFile.getAbsolutePath(), user);
+ displayUpdateService.updateIncomeTable();
+
+ } else if (options.getItemAt(options.getSelectedIndex()).equalsIgnoreCase("expense")) {
+
+ importService.expenseFromCsv(userFile.getAbsolutePath(), user);
+ displayUpdateService.updateExpenseTable();
+ }
+
+ user.updateExpenseTotal();
+ user.updateIncomeTotal();
+ user.updateBalance();
+
+ displayUpdateService.updateDetailedTable();
+
+ homePanel.updateTotals();
+ };
+ }
+
+ public ActionListener selectFileAction() {
+ return e -> {
+ if (e.getSource() == selectFileButton) {
+ int userDecision = fileChooser.showOpenDialog(null);
+ if(userDecision == JFileChooser.APPROVE_OPTION) {
+ userFile = fileChooser.getSelectedFile();
+ if(!userFile.getAbsolutePath().endsWith(".csv")){
+ JOptionPane.showMessageDialog(null,"Warning. Only csv files are supported. Select something else.", "Warning!", JOptionPane.ERROR_MESSAGE);
+ System.out.println("User selected a non csv file!");
+ }
+ System.out.println("The user selected: " + userFile.getAbsolutePath());
+ } else if (userDecision == JFileChooser.CANCEL_OPTION) {
+ System.out.println("The user canceled the operation.");
+ }
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/IncomeReportPanel.java b/src/main/java/edu/ferris/seng210/panels/IncomeReportPanel.java
new file mode 100644
index 0000000..aca7fc0
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/IncomeReportPanel.java
@@ -0,0 +1,211 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.services.DisplayUpdateService;
+import edu.ferris.seng210.services.FilterService;
+import edu.ferris.seng210.services.ReportService;
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.constants.Months;
+import edu.ferris.seng210.records.Wage;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.List;
+
+public class IncomeReportPanel extends JPanel {
+
+ private final User user;
+ public static DefaultTableModel model;
+ DefaultTableCellRenderer centerRenderer;
+ public static JScrollPane jScrollPane;
+ Object[][] tableVals;
+ String[] columnHeadings = {"Source","Amount", "Month"};
+ public static JTable incomeTable;
+ JLabel incomeText, filterTxt;
+ JLabel totalIncomeLbl, totalFilteredIncomeLbl;
+ public static JLabel totalIncomeAmtLbl, totalFilteredIncomeAmtLbl;
+ JButton exportReport, applyFilter;
+ DisplayUpdateService displayUpdateService;
+ GridBagConstraints gbConst;
+ JPanel upperPanel;
+ JComboBox monthSelector;
+ public static JComboBox typeSelector;
+
+ public IncomeReportPanel(User user) {
+ this.user = user;
+
+ displayUpdateService = new DisplayUpdateService(user);
+
+ this.setLayout(new BorderLayout());
+
+ incomeText = new JLabel("Income Report");
+ incomeText.setFont(new Font(null, Font.PLAIN, 40));
+ incomeText.setHorizontalAlignment(JLabel.CENTER);
+
+ gbConst = new GridBagConstraints();
+ upperPanel = new JPanel();
+ upperPanel.setLayout(new GridBagLayout());
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 4;
+ gbConst.insets = new Insets(20,0,20,0);
+ upperPanel.add(incomeText, gbConst);
+
+ totalIncomeLbl = new JLabel("Total Income");
+ totalIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridwidth = 1;
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,20,20,0);
+ upperPanel.add(totalIncomeLbl,gbConst);
+
+ totalIncomeAmtLbl = new JLabel("0.00");
+ totalIncomeAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,5);
+ upperPanel.add(totalIncomeAmtLbl,gbConst);
+
+ totalFilteredIncomeLbl = new JLabel("Income (Filtered)");
+ totalFilteredIncomeLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 2;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,5);
+ upperPanel.add(totalFilteredIncomeLbl,gbConst);
+
+ totalFilteredIncomeAmtLbl = new JLabel("0.00");
+ totalFilteredIncomeAmtLbl.setFont(new Font(null, Font.PLAIN, 32));
+ gbConst.gridx = 3;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,20);
+ upperPanel.add(totalFilteredIncomeAmtLbl,gbConst);
+
+ filterTxt = new JLabel("Apply a filter");
+ filterTxt.setFont(new Font(null, Font.PLAIN, 24));
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,0);
+ upperPanel.add(filterTxt,gbConst);
+
+ monthSelector = new JComboBox<>(Months.getNames().toArray());
+ monthSelector.setPreferredSize(new Dimension(200,50));
+ monthSelector.setFont(new Font(null, Font.PLAIN, 24));
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(monthSelector,gbConst);
+
+ FilterService filterService = new FilterService<>();
+ typeSelector = new JComboBox<>(filterService.getSources(user.getIncome()).toArray());
+ typeSelector.setFont(new Font(null, Font.PLAIN, 24));
+ typeSelector.setPreferredSize(new Dimension(200,50));
+ gbConst.gridx = 2;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(typeSelector,gbConst);
+
+ applyFilter = new JButton("Filter");
+ applyFilter.addActionListener(applyFilterAction(filterService));
+ applyFilter.setFont(new Font(null, Font.PLAIN, 24));
+ gbConst.gridx = 3;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,20,20,20);
+ upperPanel.add(applyFilter,gbConst);
+
+ this.add(upperPanel, BorderLayout.PAGE_START);
+
+ centerRenderer = new DefaultTableCellRenderer();
+ tableVals = new Object[user.getIncome().size()][3];
+ model = new DefaultTableModel(tableVals, columnHeadings);
+ incomeTable = new JTable(model) {
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+ };
+ jScrollPane = new JScrollPane(incomeTable);
+
+ centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+ for (int i = 0; i < incomeTable.getColumnCount(); i++) {
+ incomeTable.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
+ }
+ incomeTable.setDefaultRenderer(String.class, centerRenderer);
+
+ incomeTable.setFont(new Font(null, Font.PLAIN, 24));
+ incomeTable.setRowHeight(45);
+ incomeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+ incomeTable.getTableHeader().setReorderingAllowed(false);
+ incomeTable.setFocusable(true);
+ incomeTable.setRowSelectionAllowed(true);
+ incomeTable.setCellSelectionEnabled(true);
+ incomeTable.getTableHeader().setFont(new Font(null, Font.PLAIN, 32));
+ incomeTable.setShowVerticalLines(false);
+ incomeTable.setName("Income Table");
+
+ this.add(jScrollPane, BorderLayout.CENTER);
+
+ exportReport = new JButton("Export to CSV");
+ exportReport.addActionListener(exportReportAction(filterService));
+ exportReport.setSize(new Dimension(200,60));
+ exportReport.setFont(new Font(null, Font.PLAIN, 24));
+
+ JPanel lowerPanel = new JPanel();
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ lowerPanel.add(exportReport, BorderLayout.CENTER);
+ lowerPanel.add(Box.createRigidArea(new Dimension(25,50)));
+ this.add(lowerPanel, BorderLayout.SOUTH);
+
+ }
+
+ public ActionListener exportReportAction(FilterService filterService) {
+ return e -> {
+ ReportService reportService = new ReportService();
+ try {
+ List filteredIncome = filterService.filterByMonth(user.getIncome(), (String)monthSelector.getItemAt(monthSelector.getSelectedIndex()));
+ filteredIncome = filterService.filterBySource(filteredIncome, (String)typeSelector.getItemAt(typeSelector.getSelectedIndex()));
+
+ reportService.exportIncomeReport(user, filteredIncome);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ };
+ }
+
+ public ActionListener applyFilterAction(FilterService filterService) {
+ return e -> {
+ if(e.getSource() == applyFilter) {
+
+ List filteredIncome = filterService.filterByMonth(user.getIncome(), (String)monthSelector.getItemAt(monthSelector.getSelectedIndex()));
+ filteredIncome = filterService.filterBySource(filteredIncome, (String)typeSelector.getItemAt(typeSelector.getSelectedIndex()));
+
+ model.setNumRows(filteredIncome.size());
+ int i = 0;
+ double incomeSum = 0.00f;
+ for(Wage wage : filteredIncome) {
+ incomeTable.setValueAt(wage.getSource(), i, 0);
+ incomeTable.setValueAt(String.format("$%.2f",wage.getAmount()), i, 1);
+ incomeTable.setValueAt(wage.month(), i, 2);
+ ++i;
+ incomeSum += wage.getAmount();
+ }
+ totalFilteredIncomeAmtLbl.setText(String.format("$%.2f",incomeSum));
+ }
+ };
+ }
+
+ public void updateIncome() {
+ totalIncomeAmtLbl.setText(String.format("$%.2f",user.getTotalIncome()));
+ }
+
+ public void updateSources() {
+ typeSelector.removeAllItems();
+
+ for(Object source : new FilterService().getSources(user.getIncome())){
+ typeSelector.addItem(source);
+ }
+
+ }
+
+}
diff --git a/src/main/java/edu/ferris/seng210/panels/LoginPanel.java b/src/main/java/edu/ferris/seng210/panels/LoginPanel.java
new file mode 100644
index 0000000..6fa61a3
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/panels/LoginPanel.java
@@ -0,0 +1,93 @@
+package edu.ferris.seng210.panels;
+
+import edu.ferris.seng210.checker.PasswordChecker;
+import edu.ferris.seng210.checker.UsernameChecker;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+
+public class LoginPanel extends JPanel {
+
+ JLabel usernameLbl, passwordLbl, loginLbl;
+ GridBagConstraints gbConst;
+ JTextField usernameIncField, passwordIncField;
+ JButton loginBtn;
+
+ public LoginPanel() {
+ loginLbl = new JLabel("LOGIN");
+ usernameLbl = new JLabel("Username: ");
+ passwordLbl = new JLabel("Password: ");
+ loginBtn = new JButton("Login");
+ gbConst = new GridBagConstraints();
+ this.setLayout(new GridBagLayout());
+
+ passwordIncField = new JTextField();
+ passwordIncField.setPreferredSize(new Dimension(200, 40));
+ usernameIncField = new JTextField();
+ usernameIncField.setPreferredSize(new Dimension(200, 40));
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 0;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(20,10,20,40);
+ loginLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(loginLbl, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 2;
+ gbConst.gridwidth = 1;
+ gbConst.insets = new Insets(0,5,20,30);
+ passwordIncField.setFont(new Font(null, Font.PLAIN, 28));
+ this.add(passwordIncField, gbConst);
+
+ gbConst.gridx = 1;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,5,20,30);
+ usernameIncField.setFont(new Font(null, Font.PLAIN, 28));
+ this.add(usernameIncField, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 2;
+ gbConst.insets = new Insets(0,0,20,20);
+ passwordLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(passwordLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 1;
+ gbConst.insets = new Insets(0,0,20,20);
+ usernameLbl.setFont(new Font(null, Font.PLAIN, 44));
+ this.add(usernameLbl, gbConst);
+
+ gbConst.gridx = 0;
+ gbConst.gridy = 4;
+ gbConst.gridwidth = 2;
+ gbConst.insets = new Insets(20,30,30,30);
+ loginBtn.setFont(new Font(null, Font.PLAIN, 28));
+ loginBtn.setPreferredSize(new Dimension(150,60));
+ this.add(loginBtn, gbConst);
+
+ loginBtn.addActionListener(loginAction());
+
+
+ }
+
+ public ActionListener loginAction() {
+ return e -> {
+ String username = usernameIncField.getText();
+ String password = passwordIncField.getText();
+
+ UsernameChecker usernameChecker = new UsernameChecker();
+ PasswordChecker passwordChecker = new PasswordChecker();
+
+ if(usernameChecker.exists(username) && passwordChecker.check(username, password)) {
+ usernameIncField.setText("");
+ passwordIncField.setText("");
+ System.out.println("Login Successful");
+ JOptionPane.showMessageDialog(null,"Login Successful. Welcome " + username + ".");
+ } else {
+ JOptionPane.showMessageDialog(null,"Incorrect Credentials!");
+ }
+ };
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/records/Credentials.java b/src/main/java/edu/ferris/seng210/records/Credentials.java
new file mode 100644
index 0000000..76384f5
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/records/Credentials.java
@@ -0,0 +1,7 @@
+package edu.ferris.seng210.records;
+
+public record Credentials(
+ String username,
+ String password
+) {
+}
diff --git a/src/main/java/edu/ferris/seng210/records/Currency.java b/src/main/java/edu/ferris/seng210/records/Currency.java
new file mode 100644
index 0000000..4d14226
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/records/Currency.java
@@ -0,0 +1,4 @@
+package edu.ferris.seng210.records;
+
+public record Currency(double rate, String name) {
+}
diff --git a/src/main/java/edu/ferris/seng210/records/Expense.java b/src/main/java/edu/ferris/seng210/records/Expense.java
new file mode 100644
index 0000000..2f9b3dd
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/records/Expense.java
@@ -0,0 +1,16 @@
+package edu.ferris.seng210.records;
+
+import edu.ferris.seng210.interfaces.Transaction;
+
+public record Expense(String source, double amount, int yearlyFrequency) implements Transaction {
+
+ @Override
+ public String getSource() {
+ return this.source;
+ }
+
+ @Override
+ public double getAmount() {
+ return this.amount;
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/records/Wage.java b/src/main/java/edu/ferris/seng210/records/Wage.java
new file mode 100644
index 0000000..ed056b1
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/records/Wage.java
@@ -0,0 +1,16 @@
+package edu.ferris.seng210.records;
+
+import edu.ferris.seng210.interfaces.Transaction;
+
+public record Wage(String source, double amount, String month) implements Transaction {
+
+ @Override
+ public String getSource() {
+ return this.source;
+ }
+
+ @Override
+ public double getAmount() {
+ return this.amount;
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/DisplayUpdateService.java b/src/main/java/edu/ferris/seng210/services/DisplayUpdateService.java
new file mode 100644
index 0000000..0998d3a
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/DisplayUpdateService.java
@@ -0,0 +1,82 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.panels.DetailedReportPanel;
+import edu.ferris.seng210.panels.ExpenseReportPanel;
+import edu.ferris.seng210.panels.IncomeReportPanel;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.records.Wage;
+
+public class DisplayUpdateService {
+
+ private final User user;
+
+ public DisplayUpdateService(User user) {
+ this.user = user;
+ }
+
+ public void updateIncomeTable() {
+
+ IncomeReportPanel.model.setNumRows(0);
+
+ for(int j = 0; j < user.getIncome().size(); j++ ) {
+ IncomeReportPanel.model.addRow(new Object[]{});
+ }
+
+ user.setBalance(0.00f);
+
+ int i = 0;
+ for(Wage wage : user.getIncome()) {
+ user.setBalance(user.getBalance() + wage.getAmount());
+ IncomeReportPanel.incomeTable.setValueAt(wage.getSource(), i, 0);
+ IncomeReportPanel.incomeTable.setValueAt(String.format("$%.2f",wage.getAmount()), i, 1);
+ IncomeReportPanel.incomeTable.setValueAt(wage.month(), i, 2);
+ ++i;
+ }
+ }
+
+ public void updateDetailedTable() {
+ DetailedReportPanel.model.setNumRows(0);
+
+ for(int j = 0; j < user.getIncome().size() + user.getExpenses().size(); j++ ) {
+ DetailedReportPanel.model.addRow(new Object[]{});
+ }
+
+ int i = 0;
+ for(Wage wage : user.getIncome()) {
+ DetailedReportPanel.detailedTable.setValueAt("Income", i, 0);
+ DetailedReportPanel.detailedTable.setValueAt(wage.getSource(), i, 1);
+ DetailedReportPanel.detailedTable.setValueAt(String.format("$%.2f",wage.getAmount()), i, 2);
+ DetailedReportPanel.detailedTable.setValueAt(wage.month(), i, 3);
+ ++i;
+ }
+
+ for(Expense expense : user.getExpenses()) {
+ DetailedReportPanel.detailedTable.setValueAt("Expense", i, 0);
+ DetailedReportPanel.detailedTable.setValueAt(expense.getSource(), i, 1);
+ DetailedReportPanel.detailedTable.setValueAt(String.format("$%.2f",expense.getAmount()), i, 2);
+ DetailedReportPanel.detailedTable.setValueAt(expense.yearlyFrequency(), i, 3);
+ ++i;
+ }
+
+ }
+
+ public void updateExpenseTable() {
+
+ ExpenseReportPanel.model.setNumRows(0);
+
+ for(int j = 0; j < user.getExpenses().size(); j++ ) {
+ ExpenseReportPanel.model.addRow(new Object[]{});
+ }
+
+ user.setTotalExpenses(0.00f);
+ int i = 0;
+ for(Expense expense : user.getExpenses()) {
+ user.setTotalExpenses(user.getTotalExpenses() + expense.getAmount());
+ ExpenseReportPanel.spendingTable.setValueAt(expense.getSource(), i, 0);
+ ExpenseReportPanel.spendingTable.setValueAt(String.format("$%.2f",expense.getAmount()), i, 1);
+ ExpenseReportPanel.spendingTable.setValueAt(expense.yearlyFrequency(), i, 2);
+ ++i;
+ }
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/FilterService.java b/src/main/java/edu/ferris/seng210/services/FilterService.java
new file mode 100644
index 0000000..8c4b641
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/FilterService.java
@@ -0,0 +1,35 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.interfaces.Transaction;
+import edu.ferris.seng210.records.Wage;
+
+import java.util.List;
+
+public class FilterService {
+
+ public List filterBySource(List transactions, String source) {
+ return transactions.stream()
+ .filter(transaction -> transaction.getSource().equalsIgnoreCase(source))
+ .toList();
+ }
+
+ public List filterByFrequency(List transactions, int frequency) {
+ return transactions.stream()
+ .filter(transaction -> transaction.yearlyFrequency() == frequency)
+ .toList();
+ }
+
+ public List filterByMonth(List transactions, String month) {
+ return transactions.stream()
+ .filter(transaction -> transaction.month().equalsIgnoreCase(month))
+ .toList();
+ }
+
+ public List getSources(List transactions) {
+ return transactions.stream()
+ .map(Transaction::getSource)
+ .distinct()
+ .toList();
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/ImportService.java b/src/main/java/edu/ferris/seng210/services/ImportService.java
new file mode 100644
index 0000000..8717fe8
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/ImportService.java
@@ -0,0 +1,147 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.panels.ExpenseReportPanel;
+import edu.ferris.seng210.panels.IncomeReportPanel;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.records.Wage;
+
+import java.io.*;
+
+public class ImportService {
+
+ public boolean incomeFromCsv(String filePath, User user) {
+
+ String lineText = "";
+ BufferedReader bufferedLineReader = null;
+ BufferedReader bufferedTextReader = null;
+ File userFile = new File(filePath);
+ String source = "", month = "", amount = "";
+
+
+ try {
+ int linesInFile = 0;
+ bufferedLineReader = new BufferedReader(new FileReader(userFile));
+ bufferedTextReader = new BufferedReader(new FileReader(userFile));
+ while (bufferedLineReader.readLine() != null) { // count lines in file
+ linesInFile++;
+ }
+ Wage wage;
+ for (int lineIndex = 0; lineIndex < linesInFile; lineIndex++) {
+ lineText = bufferedTextReader.readLine();
+ if( lineIndex == 0 && lineText.equalsIgnoreCase("source,amount,month")) {
+ System.out.println("File start setup correctly.");
+ }
+ else {
+ source = "";
+ month = "";
+ amount = "";
+
+ for(int sourceIndex = 0; sourceIndex < lineText.indexOf(',', 0); sourceIndex++) {
+ source += lineText.charAt(sourceIndex);
+ }
+
+ for(int amountindex = lineText.indexOf(',') + 1; amountindex < lineText.lastIndexOf(','); amountindex++) {
+ amount += lineText.charAt(amountindex);
+ }
+ for(int monthIndex = lineText.lastIndexOf(',') + 1; monthIndex < lineText.length(); monthIndex++) {
+ month += lineText.charAt(monthIndex);
+ }
+
+ System.out.println("Text read: " + source + "," + amount + "," + month);
+
+ wage = new Wage(source,Double.parseDouble(amount),month);
+
+ user.setBalance(user.getBalance() + wage.getAmount());
+ user.addMonthlyIncome(wage);
+
+ if(IncomeReportPanel.typeSelector.getItemCount() > 0) {
+ boolean contains = false;
+ for (int i = 0; i < IncomeReportPanel.typeSelector.getItemCount(); i++) {
+ if (IncomeReportPanel.typeSelector.getItemAt(i).equals(wage.getSource())) {
+ contains = true;
+ }
+ }
+ if (!contains) {
+ IncomeReportPanel.typeSelector.addItem(wage.getSource());
+ }
+ } else {
+ IncomeReportPanel.typeSelector.addItem(wage.getSource());
+ }
+
+ }
+ }
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean expenseFromCsv(String filePath, User user) {
+ String lineText = "";
+ BufferedReader bufferedLineReader = null;
+ BufferedReader bufferedTextReader = null;
+ File userFile = new File(filePath);
+ String source = "", frequency = "", amount = "";
+
+ try {
+ int linesInFile = 0;
+ bufferedLineReader = new BufferedReader(new FileReader(userFile));
+ bufferedTextReader = new BufferedReader(new FileReader(userFile));
+ while (bufferedLineReader.readLine() != null) { // count lines in file
+ linesInFile++;
+ }
+ Expense expense;
+ for (int lineIndex = 0; lineIndex < linesInFile; lineIndex++) {
+ lineText = bufferedTextReader.readLine();
+ if(lineIndex == 0 && lineText.trim().equals("source,amount,frequency")) {
+ System.out.println("File start setup correctly.");
+ }
+ else if (lineIndex > 0){
+ source = "";
+ frequency = "";
+ amount = "";
+
+ for(int sourceIndex = 0; sourceIndex < lineText.indexOf(',', 0); sourceIndex++) {
+ source += lineText.charAt(sourceIndex);
+ }
+ for(int amountIndex = lineText.indexOf(',') + 1; amountIndex < lineText.lastIndexOf(','); amountIndex++) {
+ amount += lineText.charAt(amountIndex);
+ }
+ for(int freqIndex = lineText.lastIndexOf(',') + 1; freqIndex < lineText.length(); freqIndex++) {
+ frequency += lineText.charAt(freqIndex);
+ }
+
+ System.out.println("Text read: " + source + "," + amount + "," + frequency);
+
+ expense = new Expense(source,Double.parseDouble(amount),Integer.valueOf(frequency));
+
+ user.setTotalExpenses(user.getTotalExpenses() + expense.getAmount());
+ user.addExpense(expense);
+
+ if(ExpenseReportPanel.typeSelector.getItemCount() > 0) {
+ boolean contains = false;
+ for (int i = 0; i < ExpenseReportPanel.typeSelector.getItemCount(); i++) {
+ if (ExpenseReportPanel.typeSelector.getItemAt(i).equals(expense.getSource())) {
+ contains = true;
+ }
+ }
+ if (!contains) {
+ ExpenseReportPanel.typeSelector.addItem(expense.getSource());
+ }
+ } else {
+ ExpenseReportPanel.typeSelector.addItem(expense.getSource());
+ }
+
+ }
+ }
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/ReportService.java b/src/main/java/edu/ferris/seng210/services/ReportService.java
new file mode 100644
index 0000000..05cc914
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/ReportService.java
@@ -0,0 +1,84 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.records.Expense;
+import edu.ferris.seng210.records.Wage;
+
+import java.io.*;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+public class ReportService {
+
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("hh.mm.ss-MM-dd-yyyy");
+
+ public void exportExpenseReport(User user, List filteredExpenses) throws IOException {
+ String fileName = String.format("expense-report-%s.csv", LocalDateTime.now().format(dateTimeFormatter));
+ File file = new File(fileName);
+
+ double filteredTotal = new TotalingService().getTotal(filteredExpenses);
+
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+
+ try (PrintWriter printWriter = new PrintWriter(new FileOutputStream(file))) {
+ printWriter.printf("Total Income, %f\n", user.getTotalIncome());
+ printWriter.printf("Total Expense, %f\n", user.getTotalExpenses());
+ printWriter.printf("Filtered Expenses, %f\n", filteredTotal);
+ printWriter.printf("Total Savings, %f\n", user.getBalance());
+ printWriter.println("Source,Amount,Frequency");
+
+ for (Expense expense : filteredExpenses) {
+ printWriter.printf("%s, %f, %d\n", expense.getSource(), expense.getAmount(), expense.yearlyFrequency());
+ }
+ }
+ }
+
+ public void exportIncomeReport(User user, List filteredIncome) throws IOException {
+ String fileName = String.format("income-report-%s.csv", LocalDateTime.now().format(dateTimeFormatter));
+ File file = new File(fileName);
+
+ double filteredTotal = new TotalingService().getTotal(filteredIncome);
+
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+
+ try (PrintWriter printWriter = new PrintWriter(new FileOutputStream(file))) {
+ printWriter.printf("Total Income, %f\n", user.getTotalIncome());
+ printWriter.printf("Total Expense, %f\n", user.getTotalExpenses());
+ printWriter.printf("Filtered Income, %f\n", filteredTotal);
+ printWriter.println("Source,Amount,Frequency");
+
+ for (Wage wage : filteredIncome) {
+ printWriter.printf("%s, %f, %s\n", wage.getSource(), wage.getAmount(), wage.month());
+ }
+ }
+ }
+
+ public void exportDetailedReport(User user) throws IOException {
+ String fileName = String.format("detailed-report-%s.csv", LocalDateTime.now().format(dateTimeFormatter));
+ File file = new File(fileName);
+
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+
+ try (PrintWriter printWriter = new PrintWriter(new FileOutputStream(file))) {
+ printWriter.printf("Total Income, %f\n", user.getBalance());
+ printWriter.printf("Total Expense, %f\n", user.getTotalExpenses());
+ printWriter.printf("Total Savings, %f\n", user.getTotalIncome());
+ printWriter.println("Type,Source,Amount,Frequency / Month");
+
+ for (Wage wage : user.getIncome()) {
+ printWriter.printf("Income, %s, %f, %s\n", wage.getSource(), wage.getAmount(), wage.month());
+ }
+
+ for (Expense expense : user.getExpenses()) {
+ printWriter.printf("Income, %s, %f, %d\n", expense.getSource(), expense.getAmount(), expense.yearlyFrequency());
+ }
+ }
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/TotalingService.java b/src/main/java/edu/ferris/seng210/services/TotalingService.java
new file mode 100644
index 0000000..46c26dd
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/TotalingService.java
@@ -0,0 +1,14 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.interfaces.Transaction;
+
+import java.util.List;
+
+public class TotalingService {
+
+ public Double getTotal(List wage) {
+ return wage.stream()
+ .map(Transaction::getAmount)
+ .reduce(0D, Double::sum);
+ }
+}
diff --git a/src/main/java/edu/ferris/seng210/services/UserCreationService.java b/src/main/java/edu/ferris/seng210/services/UserCreationService.java
new file mode 100644
index 0000000..69ffcdf
--- /dev/null
+++ b/src/main/java/edu/ferris/seng210/services/UserCreationService.java
@@ -0,0 +1,39 @@
+package edu.ferris.seng210.services;
+
+import edu.ferris.seng210.EWalletApp;
+import edu.ferris.seng210.account.User;
+import edu.ferris.seng210.checker.PasswordComplexityChecker;
+import edu.ferris.seng210.checker.UsernameChecker;
+import edu.ferris.seng210.csv.CsvCredentialService;
+import edu.ferris.seng210.records.Credentials;
+
+import javax.swing.*;
+import java.io.*;
+import java.util.List;
+
+public class UserCreationService {
+
+ public void create(String username, String password) {
+
+ UsernameChecker checker = new UsernameChecker();
+ CsvCredentialService credentialService = new CsvCredentialService();
+ PasswordComplexityChecker passwordComplexityChecker = new PasswordComplexityChecker();
+
+ if (!checker.exists(username) && passwordComplexityChecker.check(password)) {
+ User user = new User(username, password);
+ EWalletApp.users.add(user);
+
+ try {
+ List currentCredentials = credentialService.readCredentials();
+ currentCredentials.add(new Credentials(username, password));
+ credentialService.writeCredentials(currentCredentials);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ JOptionPane.showMessageDialog(null, "Username already exists or password does not meet complexity requirements.");
+ }
+ }
+
+}
diff --git a/src/test/java/edu/ferris/seng210/GUITest.java b/src/test/java/edu/ferris/seng210/GUITest.java
new file mode 100644
index 0000000..c4f2d0f
--- /dev/null
+++ b/src/test/java/edu/ferris/seng210/GUITest.java
@@ -0,0 +1,226 @@
+package edu.ferris.seng210;
+
+import org.assertj.swing.data.TableCell;
+import org.assertj.swing.edt.GuiActionRunner;
+import org.assertj.swing.fixture.FrameFixture;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class GUITest {
+
+ private FrameFixture window;
+
+ @BeforeEach
+ public void setUp() {
+ AppFrame appFrame = GuiActionRunner.execute(AppFrame::new);
+ window = new FrameFixture(appFrame);
+ window.show();
+ }
+
+ @AfterEach
+ public void tearDown() {
+ window.cleanUp();
+ }
+
+ @Test
+ public void incomeChargesShowsWhenIncomeAdded() {
+ window.menuItem("Add Item").click();
+ window.textBox("Income Name").setText("Salary");
+ window.textBox("Income Amount").setText("1000");
+ window.comboBox("Month").selectItem(0);
+ window.button("Add Income").click();
+
+ window.textBox("Income Name").requireText("");
+ window.textBox("Income Amount").requireText("");
+
+ window.menuItem("Home").click();
+ window.label("Total Income Amount").requireText("$1000.00");
+ window.label("Total Expenses Amount").requireText("$0.00");
+ window.label("Total Savings Amount").requireText("$1000.00");
+
+ window.menuItem("Income Report").click();
+ window.table("Income Table").requireRowCount(1);
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(0), "Salary");
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(1), "$1000.00");
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(2), "January");
+
+ window.menuItem("Detailed Report").click();
+ window.table("Detailed Report Table").requireRowCount(1);
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(0), "Income");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(1), "Salary");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(2), "$1000.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(3), "January");
+ }
+
+ @Test
+ public void multipleIncomeChargesShowsWhenIncomeAdded() {
+ window.menuItem("Add Item").click();
+
+ window.textBox("Income Name").setText("Salary");
+ window.textBox("Income Amount").setText("1000");
+ window.comboBox("Month").selectItem(0);
+ window.button("Add Income").click();
+
+ window.textBox("Income Name").requireText("");
+ window.textBox("Income Amount").requireText("");
+
+ window.textBox("Income Name").setText("Salary");
+ window.textBox("Income Amount").setText("1250");
+ window.comboBox("Month").selectItem(1);
+ window.button("Add Income").click();
+
+ window.textBox("Income Name").requireText("");
+ window.textBox("Income Amount").requireText("");
+
+ window.textBox("Income Name").setText("Salary");
+ window.textBox("Income Amount").setText("1500");
+ window.comboBox("Month").selectItem(2);
+ window.button("Add Income").click();
+
+ window.textBox("Income Name").requireText("");
+ window.textBox("Income Amount").requireText("");
+
+ window.menuItem("Home").click();
+ window.label("Total Income Amount").requireText("$3750.00");
+ window.label("Total Expenses Amount").requireText("$0.00");
+ window.label("Total Savings Amount").requireText("$3750.00");
+
+ window.menuItem("Income Report").click();
+ window.table("Income Table").requireRowCount(3);
+
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(0), "Salary");
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(1), "$1000.00");
+ window.table("Income Table").requireCellValue(TableCell.row(0).column(2), "January");
+
+ window.table("Income Table").requireCellValue(TableCell.row(1).column(0), "Salary");
+ window.table("Income Table").requireCellValue(TableCell.row(1).column(1), "$1250.00");
+ window.table("Income Table").requireCellValue(TableCell.row(1).column(2), "February");
+
+ window.table("Income Table").requireCellValue(TableCell.row(2).column(0), "Salary");
+ window.table("Income Table").requireCellValue(TableCell.row(2).column(1), "$1500.00");
+ window.table("Income Table").requireCellValue(TableCell.row(2).column(2), "March");
+
+ window.menuItem("Detailed Report").click();
+ window.table("Detailed Report Table").requireRowCount(3);
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(0), "Income");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(1), "Salary");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(2), "$1000.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(3), "January");
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(0), "Income");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(1), "Salary");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(2), "$1250.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(3), "February");
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(0), "Income");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(1), "Salary");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(2), "$1500.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(3), "March");
+ }
+
+ @Test
+ public void expenseChargesShowsWhenExpensesAreAdded() {
+ window.menuItem("Add Item").click();
+ window.tabbedPane("Add Item Pane").selectTab("Add expense");
+
+ window.textBox("Expense Name").setText("Coffee");
+ window.textBox("Expense Amount").setText("5");
+ window.textBox("Expense Frequency").setText("1");
+ window.button("Add Expense").click();
+
+ window.textBox("Expense Name").requireText("");
+ window.textBox("Expense Amount").requireText("");
+ window.textBox("Expense Frequency").requireText("");
+
+ window.menuItem("Home").click();
+ window.label("Total Income Amount").requireText("$0.00");
+ window.label("Total Expenses Amount").requireText("$5.00");
+ window.label("Total Savings Amount").requireText("$-5.00");
+
+ window.menuItem("Expense Report").click();
+ window.table("Expense Table").requireRowCount(1);
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(0), "Coffee");
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(1), "$5.00");
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(2), "1");
+
+ window.menuItem("Detailed Report").click();
+ window.table("Detailed Report Table").requireRowCount(1);
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(0), "Expense");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(1), "Coffee");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(2), "$5.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(3), "1");
+ }
+
+ @Test
+ public void multipleExpenseChargesShowsWhenExpensesAreAdded() {
+ window.menuItem("Add Item").click();
+ window.tabbedPane("Add Item Pane").selectTab("Add expense");
+
+ window.textBox("Expense Name").setText("Coffee");
+ window.textBox("Expense Amount").setText("5");
+ window.textBox("Expense Frequency").setText("1");
+ window.button("Add Expense").click();
+
+ window.textBox("Expense Name").requireText("");
+ window.textBox("Expense Amount").requireText("");
+ window.textBox("Expense Frequency").requireText("");
+
+ window.textBox("Expense Name").setText("Meal");
+ window.textBox("Expense Amount").setText("15");
+ window.textBox("Expense Frequency").setText("1");
+ window.button("Add Expense").click();
+
+ window.textBox("Expense Name").requireText("");
+ window.textBox("Expense Amount").requireText("");
+ window.textBox("Expense Frequency").requireText("");
+
+ window.textBox("Expense Name").setText("Spotify");
+ window.textBox("Expense Amount").setText("15");
+ window.textBox("Expense Frequency").setText("12");
+ window.button("Add Expense").click();
+
+ window.textBox("Expense Name").requireText("");
+ window.textBox("Expense Amount").requireText("");
+ window.textBox("Expense Frequency").requireText("");
+
+ window.menuItem("Home").click();
+ window.label("Total Income Amount").requireText("$0.00");
+ window.label("Total Expenses Amount").requireText("$35.00");
+ window.label("Total Savings Amount").requireText("$-35.00");
+
+ window.menuItem("Expense Report").click();
+ window.table("Expense Table").requireRowCount(3);
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(0), "Coffee");
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(1), "$5.00");
+ window.table("Expense Table").requireCellValue(TableCell.row(0).column(2), "1");
+
+ window.table("Expense Table").requireCellValue(TableCell.row(1).column(0), "Meal");
+ window.table("Expense Table").requireCellValue(TableCell.row(1).column(1), "$15.00");
+ window.table("Expense Table").requireCellValue(TableCell.row(1).column(2), "1");
+
+ window.table("Expense Table").requireCellValue(TableCell.row(2).column(0), "Spotify");
+ window.table("Expense Table").requireCellValue(TableCell.row(2).column(1), "$15.00");
+ window.table("Expense Table").requireCellValue(TableCell.row(2).column(2), "12");
+
+ window.menuItem("Detailed Report").click();
+ window.table("Detailed Report Table").requireRowCount(3);
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(0), "Expense");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(1), "Coffee");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(2), "$5.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(0).column(3), "1");
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(0), "Expense");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(1), "Meal");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(2), "$15.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(1).column(3), "1");
+
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(0), "Expense");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(1), "Spotify");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(2), "$15.00");
+ window.table("Detailed Report Table").requireCellValue(TableCell.row(2).column(3), "12");
+ }
+
+}