Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/main/java/app/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -35,11 +36,48 @@ 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);

stage.setTitle("GiveHope");
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));
}
}
}
41 changes: 38 additions & 3 deletions src/main/java/application/user/UserStatistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> userFavoriteOrganizations(User user) {
List<String> 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<String> userFavoriteOrganization(User user) {
List<String> 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<String> userDonations(User user) {
List<String> 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;
Expand Down
102 changes: 94 additions & 8 deletions src/main/java/persistence/DonationDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(?, ?, ?, ?)";
Expand All @@ -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"),
Expand All @@ -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<Donation> findByUser(long userId) {
String sql = """
SELECT d.id, d.amount, d.donation_date,
Expand All @@ -87,6 +117,14 @@ public List<Donation> 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<String> getUserDonations(long userId) {
String sql = """
SELECT amount, donation_date, organization_id
Expand All @@ -107,14 +145,25 @@ public List<String> getUserDonations(long userId) {
}
}

public List<String> 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<String> 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()) {
Expand All @@ -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))
Expand All @@ -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(*)
Expand All @@ -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)";
}

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/ui/controller/MyProfileController.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -9,11 +20,50 @@
public class MyProfileController implements NavigationAware {

private Consumer<Page> 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<Donation> donationTable;
@FXML private TableColumn<Donation, String> orgColumn;
@FXML private TableColumn<Donation, String> amountColumn;
@FXML private TableColumn<Donation, String> dateColumn;

public void setOnNavigate(Consumer<Page> 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<String> 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<Donation> data = FXCollections.observableArrayList(
donationDao.findByUser(user.getID())
);
donationTable.setItems(data);
}

@FXML
private void handleSignOut() {
Expand Down
Loading