diff --git a/.classpath b/.classpath deleted file mode 100644 index 75ae95b..0000000 --- a/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.gitignore b/.gitignore index ae3c172..09e3bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /bin/ +/target/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..4c00fb1 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +EWallet \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..005f67d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..17de8cc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.project b/.project deleted file mode 100644 index ceb4c39..0000000 --- a/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - 210Project-2021 - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/UserCredentials.csv b/UserCredentials.csv new file mode 100644 index 0000000..a289545 --- /dev/null +++ b/UserCredentials.csv @@ -0,0 +1,8 @@ +username,password +admin,"Password!123" +Test1,"FirstTest1!" +Test2,"SecondTest!2" +Test3,"ThirdTest3!" +Test4,"FourthTest!4" +john,"mySecurePassword!123" +joe,"mySecurePassword!123" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a0e3508 --- /dev/null +++ b/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + edu.ferris.seng210 + ewallet + 1.0-SNAPSHOT + + + 23 + 23 + UTF-8 + + + + + + org.assertj + assertj-swing + 3.17.1 + + + + + org.junit.jupiter + junit-jupiter + 5.12.1 + test + + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-csv + 2.18.2 + + + + + \ No newline at end of file diff --git a/requirements.md b/requirements.md new file mode 100644 index 0000000..0508d26 --- /dev/null +++ b/requirements.md @@ -0,0 +1,21 @@ +# Requirements + +## User Stories + +- As a user I would like to provide an item and a price and get an estimate in number of months needed to save up to buy +this item (based on current monthly saving). +- As a user I would like to load multiple income from an external file all at once returning true if loaded successfully +and false otherwise. +- As a user I would like to load multiple expenses from an external file all at once returning true if loaded successfully +and false otherwise. +- As a user I would like to view my current balance in a different currency and back. +- As a user I would like to choose a report and export it as an external file (any type is fine preferences are csv or JSON) +- As a user I would like to view a detailed report of expense of a certain type , and summary information for expenses +- As a user I would like to view a detailed report of income of a certain type, and summary information for income +- As a user I would like to view a detailed report of all income, and summary information for income +- As a user I would like to view a detailed report of all expenses, and summary information for expenses +- As a user I would like to view a detailed report of all expenses, income, and summary information. +summary information include : total income, total income for each type, total income for each month, total expense, total expense for each type, +total savings (total income- total expenses) to date, if the total savings are less than zero it should be reported as total new debt. +- As a user I'd like to add a monthly income so I can track and report my income all year. +- As a user I'd like to add a monthly expense so I can track and report my expenses \ No newline at end of file diff --git a/src/Currency.java b/src/Currency.java deleted file mode 100644 index c5b6c8b..0000000 --- a/src/Currency.java +++ /dev/null @@ -1,6 +0,0 @@ - -public class Currency { - public double rate; - public String name; - -} diff --git a/src/EWalletApp.java b/src/EWalletApp.java deleted file mode 100644 index d6106ce..0000000 --- a/src/EWalletApp.java +++ /dev/null @@ -1,8 +0,0 @@ -import java.util.ArrayList; - -public class EWalletApp { - //this is the app class, has the GUI and create one object of your expense calculator class. The expense calculator class is the implementation of the Expenser interface - private ArrayList AllData; - public void CreateUser(String username, String password) {} - -} diff --git a/src/Expense.java b/src/Expense.java deleted file mode 100644 index c386160..0000000 --- a/src/Expense.java +++ /dev/null @@ -1,7 +0,0 @@ - -public class Expense { - String source; - double amount; - int yearlyfrequency; //1 for 1 time or once a year, 12 for monthly or or 24 for biweekly - //should add contructor(s) -} diff --git a/src/Expenser.java b/src/Expenser.java deleted file mode 100644 index 115e8a0..0000000 --- a/src/Expenser.java +++ /dev/null @@ -1,36 +0,0 @@ -import java.util.ArrayList; - -public interface Expenser { -public User userAtHand= null; - // As a user I'd like to add a monthly expense so I can track and report my expenses - 3pts - public void addExpense (Expense Ex); - // As a user I'd like to add a monthly income so I can track and report my income all year - 3pts - public void addMonthlyIncome (Wage W); - //As a user I would like to view a detailed report of all expenses, income, and summary information - //summary information include : total income, total income for each type, total income for each month, total expense, total expense for each type, - //total savings (total income- total expenses) to date, if the total savings are less than zero it should be reported as total new debt. - public void PrintFullreport(); - //As a user I would like to view a detailed report of all expenses, and summary information for expenses - public void PrintExpensereport(); - //As a user I would like to view a detailed report of all income, and summary information for income - public void PrintIncomereport(); - //As a user I would like to view a detailed report of income of a certain type, and summary information for income - public void PrintIncomereportbyTpe(); - //As a user I would like to view a detailed report of expense of a certain type , and summary information for expenses - public void PrintExpensebyType(); - // As a user I would like to choose a report and export it as an external file (any type is fine preferences are csv or JSON) - public void exportReport(String reportTitle); - // As a user I would like to view my current balance in a different currency - //Bonus : try to use the same convert function to convert from foreign currency to USD - public Currency convertForeignCurrency(Currency C, double amount); - // As a user I would like to load multiple expenses from an external file all at once returning true if loaded successfully and false otherwise - public boolean loadExpenseFile(String filePath); - // As a user I would like to load multiple income from an external file all at once returning true if loaded successfully and false otherwise - public boolean loadIncomeFile(String filePath); - // As a user I would like to provide an item and a price and get an estimate in number of months needed to save up to buy this item. (based on current monthly saving. - public int whenCanIBuy(String itemname,double price); - // updates monthly savings based on latest added income and expenses. This is an internal function not called by the users. Bonus: what is the most efficient way to call it (when?)? - public void updateMonthlySavings(); - - -} diff --git a/src/User.java b/src/User.java deleted file mode 100644 index 8327a21..0000000 --- a/src/User.java +++ /dev/null @@ -1,15 +0,0 @@ -import java.util.ArrayList; - -public class User { - private ArrayList currencyRates; - private ArrayList Income; // user income sources that user can record or view or search by type or month - private ArrayList 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"); + } + +}