diff --git a/src/main/java/app/Main.java b/src/main/java/app/Main.java index c30aa59..a1c0d3e 100644 --- a/src/main/java/app/Main.java +++ b/src/main/java/app/Main.java @@ -8,6 +8,7 @@ import domain.user.User; import integration.security.Sha256PasswordHasher; import java.math.BigDecimal; +import java.sql.SQLException; import java.util.List; import persistence.DonationDao; import persistence.OrganizationDao; @@ -35,6 +36,8 @@ public void start(Stage stage) throws Exception { orgDao.insert(org); } + addTestdata(); + Parent root = FXMLLoader.load(getClass().getResource("/view/MainView.fxml")); Scene scene = new Scene(root, 1275, 725); @@ -42,4 +45,39 @@ public void start(Stage stage) throws Exception { stage.setScene(scene); stage.show(); } + + private void addTestdata() throws SQLException { + UserDao userDao = new UserDao(); + DonationDao donationDao = new DonationDao(); + OrganizationDao orgDao = new OrganizationDao(); + + if (userDao.existsByEmail("test@test.no")) return; + + PasswordHasher hasher = new Sha256PasswordHasher(); + String hashedPassword = hasher.hash("test"); + User user = new User("test", "12345678", hashedPassword, "test@test.no"); + userDao.insert(user); + + Organization org = orgDao.getAll().get(0); + + donationDao.insert(new Donation(new BigDecimal(100), user, org)); + donationDao.insert(new Donation(new BigDecimal(250), user, org)); + donationDao.insert(new Donation(new BigDecimal(500), user, org)); + donationDao.insert(new Donation(new BigDecimal(300), user, org)); + donationDao.insert(new Donation(new BigDecimal(1000), user, org)); + donationDao.insert(new Donation(new BigDecimal(700), user, org)); + donationDao.insert(new Donation(new BigDecimal(250), user, org)); + + if (!userDao.existsByEmail("test2@test.no")) { + String hashedPassword2 = hasher.hash("test2"); + User user2 = new User("test2", "87654321", hashedPassword2, "test2@test.no"); + userDao.insert(user2); + + Organization org2 = orgDao.getAll().get(1); + + donationDao.insert(new Donation(new BigDecimal(150), user2, org2)); + donationDao.insert(new Donation(new BigDecimal(400), user2, org2)); + donationDao.insert(new Donation(new BigDecimal(600), user2, org2)); + } + } } diff --git a/src/main/java/application/user/UserStatistics.java b/src/main/java/application/user/UserStatistics.java index 64333f1..b78f18f 100644 --- a/src/main/java/application/user/UserStatistics.java +++ b/src/main/java/application/user/UserStatistics.java @@ -5,28 +5,63 @@ import java.util.List; import persistence.DonationDao; +/** + * Provides statistical information about a user's donation activity. + * Acts as a service layer between the application and {@link DonationDao}, + * exposing user-friendly methods for retrieving donation history, + * total amounts, and favorite organizations. + */ public class UserStatistics { private DonationDao donationDao; + /** + * Constructs a new {@code UserStatistics} instance with a default {@link DonationDao}. + */ public UserStatistics() { this.donationDao = new DonationDao(); } - public List userFavoriteOrganizations(User user) { - List favoriteOrganizations = donationDao.getFavoriteOrganizations(user.getID()); - return favoriteOrganizations; + /** + * Returns the top three organizations that the user has donated to most frequently. + * + * @param user the user whose favorite organizations are to be retrieved; must not be null + * @return a list of up to three formatted strings, each representing an organization + * and its donation count; empty list if the user has no donations + */ + public List userFavoriteOrganization(User user) { + List favoriteOrganization = donationDao.getFavoriteOrganization(user.getID()); + return favoriteOrganization; } + /** + * Returns a formatted list of all donations made by the user. + * Each entry contains the donation amount, date, and organization. + * + * @param user the user whose donation history is to be retrieved; must not be null + * @return a list of formatted donation strings; empty list if the user has no donations + */ public List userDonations(User user) { List userDonationList = donationDao.getUserDonations(user.getID()); return userDonationList; } + /** + * Returns the total amount donated by the user across all donations. + * + * @param user the user whose total donation amount is to be calculated; must not be null + * @return a string representation of the total donated amount; {@code "0"} if no donations exist + */ public String userTotalDonationAmount(User user) { String totalDonations = donationDao.getTotalDonationAmount(user.getID()); return totalDonations; } + /** + * Returns the total number of donations made by the user. + * + * @param user the user whose donation count is to be retrieved; must not be null + * @return a string representation of the total number of donations; {@code "0"} if none exist + */ public String getTotalDonationsMade(User user) { String totalDonationsMade = donationDao.getTotalDonationsMade(user.getID()); return totalDonationsMade; diff --git a/src/main/java/persistence/DonationDao.java b/src/main/java/persistence/DonationDao.java index 646dba5..d467e99 100644 --- a/src/main/java/persistence/DonationDao.java +++ b/src/main/java/persistence/DonationDao.java @@ -13,8 +13,20 @@ import java.util.List; import persistence.db.Database; +/** + * Data Access Object for donation-related database operations. + * Provides methods for inserting donations and retrieving donation statistics + * such as history, total amounts, and favorite organizations for a given user. + */ public class DonationDao { - + /** + * Inserts a new donation record into the database. + * Upon successful insertion, the generated database ID is set on the donation object. + * + * @param donation the {@link Donation} to insert; must not be null and must have + * a valid amount, user, and organization + * @throws RuntimeException if a database error occurs during the insert + */ public void insert(Donation donation) { String sql = "INSERT INTO donation(amount, donation_date" + ", user_id, organization_id) VALUES(?, ?, ?, ?)"; @@ -38,6 +50,15 @@ public void insert(Donation donation) { } } + /** + * Maps a single row from the provided {@code ResultSet} into a {@link Donation} object. + * The method extracts information about the donation, user, and organization + * from the {@code ResultSet} and constructs corresponding objects. + * + * @param rs the {@code ResultSet} containing the data for a single row; must not be null + * @return a {@code Donation} object populated with data from the row in the {@code ResultSet} + * @throws SQLException if a database access error occurs or if the column labels cannot be found + */ private Donation mapRow(ResultSet rs) throws SQLException { User user = new User( rs.getString("user_name"), @@ -63,6 +84,15 @@ private Donation mapRow(ResultSet rs) throws SQLException { return donation; } + /** + * Retrieves a list of donations made by a specific user, based on the user ID. + * The donations include details such as the donation amount, date, associated user, + * and organization. + * + * @param userId the unique identifier of the user whose donations are to be retrieved + * @return a list of {@code Donation} objects representing donations made by the user + * @throws RuntimeException if an error occurs during the database operation + */ public List findByUser(long userId) { String sql = """ SELECT d.id, d.amount, d.donation_date, @@ -87,6 +117,14 @@ public List findByUser(long userId) { } } + /** + * Retrieves a formatted list of donations made by a specific user. + * Each entry is a string on the form {@code "Amount: X, Date: Y, Organization: Z"}. + * + * @param userId the unique identifier of the user whose donations are to be retrieved + * @return a list of formatted strings, one per donation; empty list if none found + * @throws RuntimeException if a database error occurs during the query + */ public List getUserDonations(long userId) { String sql = """ SELECT amount, donation_date, organization_id @@ -107,14 +145,25 @@ public List getUserDonations(long userId) { } } - public List getFavoriteOrganizations(long userId) { + /** + * Retrieves a list of the user's favorite organizations based on donation history. + * The method queries the database to find the organizations the user has donated to most frequently + * and limits the result to the top three organizations. + * + * @param userId the unique identifier of the user whose favorite organizations are to be retrieved + * @return a list of strings representing the top three organizations donated to by the user, + * ordered by the number of donations in descending order + * @throws RuntimeException if an error occurs while querying the database + */ + public List getFavoriteOrganization(long userId) { String sql = """ - SELECT organization_id, COUNT(*) AS donation_count - FROM donation - WHERE user_Id = ? - GROUP BY organization_id + SELECT o.name, COUNT(*) AS donation_count + FROM donation d + JOIN organization o ON d.organization_id = o.org_number + WHERE d.user_id = ? + GROUP BY d.organization_id ORDER BY donation_count DESC - LIMIT 3 + LIMIT 1 """; try (Connection conn = Database.getConnection()) { @@ -130,6 +179,15 @@ SELECT organization_id, COUNT(*) AS donation_count } } + /** + * Retrieves the total donation amount made by a specific user. + * The method calculates the sum of all donations associated with the given user ID. + * + * @param userId the unique identifier of the user whose total donation amount is to be retrieved + * @return a string representing the total donation amount made by the user; if no donations exist, + * the method returns "0" + * @throws RuntimeException if an error occurs during database access + */ public String getTotalDonationAmount(long userId) { String sql = """ SELECT SUM(CAST(amount as REAL)) @@ -152,6 +210,17 @@ SELECT SUM(CAST(amount as REAL)) } } + /** + * Retrieves the total number of donations made by a specific user. + * The method counts the number of donation records associated with the provided user ID + * in the database and returns the total count as a string. + * + * @param userId the unique identifier of the user whose total number of donations + * is to be retrieved + * @return a string representing the total count of donations made by the user; + * returns "0" if no donations exist + * @throws RuntimeException if a database access error occurs + */ public String getTotalDonationsMade(long userId) { String sql = """ SELECT COUNT(*) @@ -176,14 +245,31 @@ SELECT COUNT(*) } + /** + * Maps a single row from the provided {@code ResultSet} into a string representation + * consisting of the donation amount, date, and organization ID. + * + * @param rs the {@code ResultSet} containing the data for a single row; must not be null + * @return a string representing the donation with details such as amount, date, + * and organization ID + * @throws SQLException if a database access error occurs or if the column labels cannot be found + */ private String mapRowSimple(ResultSet rs) throws SQLException { return "Amount: " + rs.getString("amount") + ", Date: " + rs.getString("donation_date") + ", Organization: " + rs.getString("organization_id"); } + /** + * Maps a single row from the provided {@code ResultSet} into a formatted string + * combining the organization ID and its donation count. + * + * @param rs the {@code ResultSet} containing the data for a single row; must not be null + * @return a string on the form {@code "organization_id (N donations)"} + * @throws SQLException if a database access error occurs or a column label cannot be found + */ private String mapRowFavorite(ResultSet rs) throws SQLException { - return rs.getString("organization_id") + return rs.getString("name") + " (" + rs.getInt("donation_count") + " donasjoner)"; } diff --git a/src/main/java/ui/controller/MyProfileController.java b/src/main/java/ui/controller/MyProfileController.java index b2a9d0c..f6b82ff 100644 --- a/src/main/java/ui/controller/MyProfileController.java +++ b/src/main/java/ui/controller/MyProfileController.java @@ -1,6 +1,17 @@ package ui.controller; +import application.user.UserStatistics; +import domain.donation.Donation; +import domain.user.User; +import java.util.List; +import javafx.beans.property.SimpleStringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import persistence.DonationDao; import ui.Page; import util.SessionManager; @@ -9,11 +20,50 @@ public class MyProfileController implements NavigationAware { private Consumer onNavigate; + @FXML private Label totalDonatedLabel; + @FXML private Label numberOfDonationsLabel; + @FXML private Label favoriteOrgLabel; + @FXML private Label nameLabel; + @FXML private Label emailLabel; + @FXML private Label phoneLabel; + @FXML private TableView donationTable; + @FXML private TableColumn orgColumn; + @FXML private TableColumn amountColumn; + @FXML private TableColumn dateColumn; public void setOnNavigate(Consumer onNavigate) { this.onNavigate = onNavigate; } + @FXML + public void initialize() { + User user = SessionManager.getCurrentUser(); + if (user == null) return; + + nameLabel.setText("Name: " + user.getUsername()); + emailLabel.setText("E-mail: " + user.getEMail()); + phoneLabel.setText("Phonenumber: " + user.getPhoneNumber()); + + UserStatistics stats = new UserStatistics(); + totalDonatedLabel.setText(stats.userTotalDonationAmount(user) + " kr"); + numberOfDonationsLabel.setText(stats.getTotalDonationsMade(user)); + + List favOrg = stats.userFavoriteOrganization(user); + favoriteOrgLabel.setText(favOrg.isEmpty() ? "None" : favOrg.get(0)); + + orgColumn.setCellValueFactory(cell -> + new SimpleStringProperty(cell.getValue().getOrganization().getName())); + amountColumn.setCellValueFactory(cell -> + new SimpleStringProperty(cell.getValue().getAmount().toString() + " kr")); + dateColumn.setCellValueFactory(cell -> + new SimpleStringProperty(cell.getValue().getDateTime().toLocalDate().toString())); + + DonationDao donationDao = new DonationDao(); + ObservableList data = FXCollections.observableArrayList( + donationDao.findByUser(user.getID()) + ); + donationTable.setItems(data); + } @FXML private void handleSignOut() { diff --git a/src/main/resources/view/MyProfile.fxml b/src/main/resources/view/MyProfile.fxml index 2d28b05..40ec2de 100644 --- a/src/main/resources/view/MyProfile.fxml +++ b/src/main/resources/view/MyProfile.fxml @@ -39,22 +39,22 @@