From 5767aaab5cc6485f317899ee0c8205e5c6b60c94 Mon Sep 17 00:00:00 2001 From: Fredrik Marjoni Date: Sun, 12 Apr 2026 18:33:17 +0200 Subject: [PATCH] update[DonationPage]: Refactor donation selection, add confirmation dialog, and improve custom amount UI --- .../app/control/DonationController.java | 54 +++++++-- .../view/donationpage/DonationPageView.java | 104 +++++++++++------- src/main/resources/donationpage/donation.css | 38 +++++++ 3 files changed, 152 insertions(+), 44 deletions(-) diff --git a/src/main/java/edu/group5/app/control/DonationController.java b/src/main/java/edu/group5/app/control/DonationController.java index 97a1c9d..907caa3 100644 --- a/src/main/java/edu/group5/app/control/DonationController.java +++ b/src/main/java/edu/group5/app/control/DonationController.java @@ -12,6 +12,9 @@ import java.util.Map; import java.util.Set; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; + public class DonationController { private final AppState appState; private final NavigationController nav; @@ -38,26 +41,55 @@ public Set getUniqueOrgs() { return uniqueOrgs; } - public void handleDonate() { - // Get session data from MainController + public void requestDonationConfirmation() { + // Get session data User currentUser = appState.getCurrentUser(); Organization currentOrg = appState.getCurrentOrganization(); BigDecimal amount = appState.getCurrentDonationAmount(); + // Validate before showing dialog if (currentUser == null) { - System.err.println("Error: No user logged in"); + showError("Error: No user logged in"); return; } - if (!(currentUser instanceof Customer customer)) { - System.err.println("Error: Only customers can donate"); + if (!(currentUser instanceof Customer)) { + showError("Error: Only customers can donate"); return; } if (currentOrg == null) { - System.err.println("Error: No organization selected"); + showError("Error: No organization selected"); return; } if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { - System.err.println("Error: Invalid donation amount"); + showError("Please select a donation amount first"); + return; + } + + // Show confirmation dialog + Alert confirmDialog = new Alert(Alert.AlertType.CONFIRMATION); + confirmDialog.setTitle("Confirm Donation"); + confirmDialog.setHeaderText("Confirm Your Donation"); + confirmDialog.setContentText( + "Organization: " + currentOrg.name() + "\n" + + "Amount: " + amount + " kr\n\n" + + "Are you sure you want to proceed?" + ); + + // If user clicks OK, process donation + if (confirmDialog.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK) { + handleDonate(); + } + // If Cancel, dialog just closes and nothing happens + } + + private void handleDonate() { + // This now only handles the actual donation processing + User currentUser = appState.getCurrentUser(); + Organization currentOrg = appState.getCurrentOrganization(); + BigDecimal amount = appState.getCurrentDonationAmount(); + + if (!(currentUser instanceof Customer customer)) { + System.err.println("Error: Only customers can donate"); return; } @@ -81,4 +113,12 @@ public void handleDonate() { // Navigate to payment complete nav.showPaymentCompletePage(); } + + private void showError(String message) { + Alert errorAlert = new Alert(Alert.AlertType.WARNING); + errorAlert.setTitle("Donation Error"); + errorAlert.setHeaderText("Cannot Process Donation"); + errorAlert.setContentText(message); + errorAlert.showAndWait(); + } } diff --git a/src/main/java/edu/group5/app/view/donationpage/DonationPageView.java b/src/main/java/edu/group5/app/view/donationpage/DonationPageView.java index 5087267..49a9a73 100644 --- a/src/main/java/edu/group5/app/view/donationpage/DonationPageView.java +++ b/src/main/java/edu/group5/app/view/donationpage/DonationPageView.java @@ -5,8 +5,8 @@ import edu.group5.app.model.AppState; import javafx.geometry.Insets; import javafx.geometry.Pos; -import javafx.scene.control.Button; import javafx.scene.control.TextField; +import javafx.scene.control.Button; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.TilePane; @@ -16,18 +16,14 @@ import javafx.scene.Node; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; public class DonationPageView extends BorderPane { private final AppState appState; private final NavigationController nav; private final DonationController donationController; - private final List allDonationElements = new ArrayList<>(); - private final Map elementAmounts = new HashMap<>(); + private Node currentlySelected = null; + private TextField customAmountField; public DonationPageView(AppState appState, NavigationController nav, DonationController donationController) { this.appState = appState; @@ -38,6 +34,12 @@ public DonationPageView(AppState appState, NavigationController nav, DonationCon VBox content = new VBox(); content.getChildren().addAll(createDonationGrid(), createDonateSection()); + + content.setOnMouseClicked(e -> { + if (e.getTarget() == content) { + clearSelection(); + } + }); setCenter(content); } @@ -75,14 +77,12 @@ public Button createDonationButton(String title, String amount) { button.getStyleClass().add("donation-button"); BigDecimal parsedAmount = parseAmount(amount); - elementAmounts.put(button, parsedAmount); + button.setUserData(parsedAmount); - button.setOnAction(e -> { - selectDonationElement(button); - }); - allDonationElements.add(button); + button.setOnAction(e -> selectDonation(button)); return button; } + private VBox createCustomButton() { Text titleText = new Text("Custom Donation"); titleText.getStyleClass().add("donation-title"); @@ -93,8 +93,10 @@ private VBox createCustomButton() { Text krText = new Text("kr"); krText.getStyleClass().add("donation-amount"); - TextField amountField = new TextField(); + this.customAmountField = new TextField(); + TextField amountField = customAmountField; amountField.getStyleClass().add("donation-input"); + amountField.setPromptText("Enter amount"); amountRow.getChildren().addAll(amountField, krText); @@ -103,48 +105,76 @@ private VBox createCustomButton() { box.getStyleClass().add("donation-button"); box.setOnMouseClicked(e -> { - try { - BigDecimal amount = new BigDecimal(amountField.getText().trim()); - elementAmounts.put(box, amount); - selectDonationElement(box); - } catch (NumberFormatException exception) { - System.err.println("Invalid custom donation amount: " + amountField.getText()); - } + selectDonation(box); + amountField.requestFocus(); + }); + + amountField.setOnMouseClicked(e -> + { + selectDonation(box); + amountField.requestFocus(); }); - allDonationElements.add(box); + // NEW: On text field input - update the amount in real-time + amountField.textProperty().addListener((obs, oldVal, newVal) -> { + if (!newVal.trim().isEmpty()) { + try { + BigDecimal amount = new BigDecimal(newVal.trim()); + box.setUserData(amount); + updateDonationAmount(amount); + } catch (NumberFormatException ignored) { + // User is still typing, silently ignore + } + } else { + box.setUserData(null); + if (currentlySelected == box) { + updateDonationAmount(null); + } + } + }); return box; } + private HBox createDonateSection() { Button donateBtn = new Button("Donate"); donateBtn.getStyleClass().add("donate-button"); - donateBtn.setOnAction(e -> donationController.handleDonate()); + donateBtn.setOnAction(e -> donationController.requestDonationConfirmation()); - HBox section = new HBox(donateBtn); + Button clearBtn = new Button("Clear"); + clearBtn.getStyleClass().add("clear-button"); + clearBtn.setOnAction(e -> clearSelection()); + + HBox section = new HBox(20, clearBtn, donateBtn); section.setAlignment(Pos.CENTER); section.setPadding(new Insets(20, 0, 30, 0)); return section; } - private void selectDonationElement(Node element) { - // Remove selected class from all elements - for (Node node : allDonationElements) { - node.getStyleClass().remove("donation-button-selected"); + private void selectDonation(Node element) { + if (currentlySelected != null) { + currentlySelected.getStyleClass().remove("donation-button-selected"); } + currentlySelected = element; + currentlySelected.getStyleClass().add("donation-button-selected"); - element.getStyleClass().add("donation-button-selected"); - - // Extract and store the amount - extractAndStoreAmount(element); + BigDecimal amount = (BigDecimal) element.getUserData(); + updateDonationAmount(amount); } - private void extractAndStoreAmount(Node element) { - BigDecimal amount = elementAmounts.get(element); - if (amount != null) { - appState.setCurrentDonationAmount(amount); - } else { - System.err.println("Error: No amount found for selected element"); + private void clearSelection() { + if (currentlySelected != null) { + currentlySelected.getStyleClass().remove("donation-button-selected"); + currentlySelected = null; + updateDonationAmount(null); } + + if (customAmountField != null) { + customAmountField.clear(); + } + } + + private void updateDonationAmount(BigDecimal amount) { + appState.setCurrentDonationAmount(amount); } private BigDecimal parseAmount(String amountStr) { diff --git a/src/main/resources/donationpage/donation.css b/src/main/resources/donationpage/donation.css index f690337..edacdd3 100644 --- a/src/main/resources/donationpage/donation.css +++ b/src/main/resources/donationpage/donation.css @@ -55,4 +55,42 @@ .donate-button:hover { -fx-background-color: #c02020; +} + +.clear-button { + -fx-pref-height: 55px; + -fx-background-color: #f0f0f0; + -fx-text-fill: #333; + -fx-font-size: 16px; + -fx-font-weight: bold; + -fx-background-radius: 8; + -fx-cursor: hand; + -fx-padding: 0 30 0 30; + -fx-border-color: #ccc; + -fx-border-width: 1; +} + +.clear-button:hover { + -fx-background-color: #e0e0e0; +} + +.clear-button:pressed { + -fx-background-color: #d0d0d0; +} + +.donation-button-selected .donation-title { + -fx-fill: white; +} + +.donation-button-selected .donation-amount { + -fx-fill: white; +} + +.donation-button-selected .donation-input { + -fx-text-fill: white; +} + +.donation-button-selected .donation-input:focused { + -fx-text-fill: white; + -fx-border-color: transparent transparent white transparent; } \ No newline at end of file