Skip to content

Commit

Permalink
Feat: Added transaction view with basic search and filter
Browse files Browse the repository at this point in the history
  • Loading branch information
tommyah committed May 19, 2026
1 parent 3265666 commit a860e36
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 10 deletions.
5 changes: 4 additions & 1 deletion src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ public void start(final Stage stage) throws Exception {
stocksInFile);

TransactionsView transactionsView = new TransactionsView();
new TransactionsController(transactionsView, eventManager);
new TransactionsController(
transactionsView,
eventManager,
player.getTransactionArchive());

// In-game (Change "topBarView" to "topBarView2" if no summary section).
// Dashboard er default center-view.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions;

import edu.ntnu.idi.idatt2003.g40.mappe.engine.TransactionArchive;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Sale;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewController;
import javafx.scene.control.TextFormatter;

public class TransactionsController extends ViewController<TransactionsView> {

/**
* {@inheritDoc}
*/
public TransactionsController(final TransactionsView viewElement, final EventManager eventManager)
throws IllegalArgumentException {
private final TransactionArchive transactionArchive;
public TransactionsController(final TransactionsView viewElement,
final EventManager eventManager,
final TransactionArchive transactionArchive) {
this.transactionArchive = transactionArchive;
super(viewElement, eventManager);
getViewElement().clearCards();
}

@Override
protected void initInteractions() {

getViewElement().getWeekField().setTextFormatter(new TextFormatter<>(change -> {
if (change.getControlNewText().matches("([0-9]*(\\.[0-9]*)?)?")) {
return change;
}
return null;
}));

getViewElement().getWeekField().focusedProperty().addListener((observable, wasFocused, isNowFocused) -> {
if (!isNowFocused && getViewElement().getWeekField().getText().trim().isEmpty()) {
getViewElement().getWeekField().setText("1");
}
filterData(getViewElement().getSearchField().getText(), Integer.parseInt(getViewElement().getWeekField().getText()));
});

getViewElement().getSearchField().textProperty().addListener((observable, oldValue, newValue) -> {
filterData(newValue, Integer.parseInt(getViewElement().getWeekField().getText()));
});
}

private void filterData(final String searchKeyword, final Integer weekTarget) {
getViewElement().clearCards();
transactionArchive.getTransactions(weekTarget).forEach(t -> {
if (t.getShare().getStock().getCompany().toLowerCase().contains(searchKeyword.toLowerCase())
|| t.getShare().getStock().getSymbol().toLowerCase().contains(searchKeyword.toLowerCase())) {
String transactionType = "Purchase";
String sharePrefix = "+ ";
String moneyPrefix = "- ";

if(t.getClass().equals(Sale.class)){
transactionType = "Sale";
sharePrefix = "- ";
moneyPrefix = "+ ";
}

getViewElement().addTransactionCard(
transactionType,
t.getShare().getStock().getSymbol(),
t.getShare().getStock().getCompany(),
sharePrefix + t.getShare().getQuantity().floatValue() + " shares",
moneyPrefix + t.getCalculator().calculateTotal().toString() + " NOK",
weekTarget.toString());
}
});
}
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,188 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions;

import edu.ntnu.idi.idatt2003.g40.mappe.view.ViewElement;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;

public class TransactionsView extends ViewElement<VBox, TransactionsActions> {
/**
* View for displaying a history of all transactions for the active player.
*
* <p>Extends {@link ViewElement}</p>
* */
public final class TransactionsView
extends ViewElement<VBox, TransactionsActions> {

/**
* Search field.
* */
private TextField searchField;

/**
* Week input field.
* */
private TextField weekField;

/**
* Container element for cards.
* */
private HBox cardsContainer;

/**
* Entire search bar element.
* */
private HBox searchBar;

/**
* Search label text.
* */
private Label searchLabel;

/**
* Week label text.
* */
private Label weekLabel;

/**
* Scroll pane for cards.
* */
private ScrollPane scrollPane;

/**
* Constructor.
*
* @see ViewElement
* */
public TransactionsView() {
super(new VBox(), TransactionsActions.class);
}

@Override
protected void initLayout() {
searchBar = new HBox();
searchLabel = new Label("Search:");
searchField = new TextField();

HBox.setHgrow(searchField, Priority.ALWAYS);

weekLabel = new Label("Week:");
weekField = new TextField("2");

searchBar.getChildren().addAll(
searchLabel,
searchField,
weekLabel,
weekField
);

// Horizontal scroll pane:
cardsContainer = new HBox();

scrollPane = new ScrollPane(cardsContainer);
scrollPane.setPannable(true);

scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);

getRootPane().getChildren().addAll(searchBar, scrollPane);
}

/**
* Method to add cards dynamically based on model data.
*
* @param type the type of transaction (PURCHASE/SALE).
* @param symbol the symbol of the stock this transaction was for.
* @param companyName name of the company behind the stock of this
* transaction.
* @param shares the amount of shares gained or lost during this
* transaction.
* @param nok the amount of money in NOK gained or lost during
* the transactions.
* @param week the week this transaction took place.
*/
public void addTransactionCard(final String type,
final String symbol,
final String companyName,
final String shares,
final String nok,
final String week) {
VBox card = new VBox();

// Header (SALE / PURCHASE)
Label typeLabel = new Label(type.toUpperCase());

// Company Details
Label companyLabel = new Label(symbol + ", " + companyName);

// Info Rows (+- shares, +- NOK)
VBox infoBox = new VBox();

Label textRow1 = new Label(shares);
Label textRow2 = new Label(nok);

infoBox.getChildren().addAll(textRow1, textRow2);

Region spacer = new Region();
VBox.setVgrow(spacer, Priority.ALWAYS);

// Week Label
Label cardWeekLabel = new Label("Week " + week);

card.getChildren().addAll(
typeLabel,
companyLabel,
infoBox,
spacer,
cardWeekLabel
);
cardsContainer.getChildren().add(card);

card.getStyleClass().add("transactions-transactionCard");
typeLabel.getStyleClass().add("transactions-typeLabel");
infoBox.getStyleClass().add("transactions-infoBox");
companyLabel.getStyleClass().add("transactions-cardText");
textRow1.getStyleClass().add("transactions-cardText");
textRow2.getStyleClass().add("transactions-cardText");
cardWeekLabel.getStyleClass().add("transactions-cardText");
}

/**
* Clears the displayed list of cards.
* */
public void clearCards() {
cardsContainer.getChildren().clear();
}

/**
* Getter method for the search field.
*
* @return Search field.
* */
public TextField getSearchField() {
return searchField;
}

/**
* Getter method for the week filter field.
*
* @return week filter field.
* */
public TextField getWeekField() {
return weekField;
}

@Override
protected void initStyling() {

getRootPane().getStyleClass().add("transactions-root");
searchBar.getStyleClass().add("transactions-searchBar");
searchLabel.getStyleClass().add("transactions-searchLabel");
searchField.getStyleClass().add("transactions-searchField");
weekLabel.getStyleClass().add("transactions-searchLabel");
weekField.getStyleClass().add("transactions-weekField");
scrollPane.getStyleClass().add("transactions-scrollPane");
cardsContainer.getStyleClass().add("transactions-cardsContainer");
}
}
}
77 changes: 77 additions & 0 deletions src/main/resources/styles.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.root {
-fx-font-family: "Aptos";
-fx-text-fill: black;
}

/* Container for the buttons */
Expand Down Expand Up @@ -563,3 +564,79 @@
-fx-text-fill: #555555;
-fx-padding: 40;
}

/* ---------------- TRANSACTIONS VIEW ---------------- */
.transactions-root {
-fx-spacing: 20;
-fx-padding: 15;
-fx-alignment: TOP_CENTER;
}

.transactions-root .label {
-fx-text-fill: black;
}

.transactions-searchBar {
-fx-spacing: 10;
-fx-alignment: CENTER_LEFT;
-fx-border-color: #000000;
-fx-border-width: 1.5;
-fx-background-color: #E0E0E0;
-fx-padding: 10;
}

.transactions-searchLabel {
-fx-font-size: 14;
}

.transactions-searchField {
-fx-background-color: white;
-fx-border-color: #CCCCCC;
}

.transactions-weekField {
-fx-pref-width: 50;
-fx-alignment: CENTER;
-fx-background-color: white;
-fx-border-color: #000000;
-fx-border-width: 1.5;
}

.transactions-transactionCard {
-fx-spacing: 15;
-fx-padding: 25;
-fx-alignment: TOP_CENTER;
-fx-pref-width: 260;
-fx-pref-height: 320;
-fx-background-color: #D6D6D6;
-fx-background-radius: 35;
-fx-border-color: #000000;
-fx-border-radius: 35;
-fx-border-width: 1.5;
}

.transactions-typeLabel {
-fx-font-size: 28;
-fx-font-weight: bold;
}

.transactions-infoBox {
-fx-spacing: 8;
-fx-alignment: CENTER;
}

.transactions-cardText {
-fx-font-size: 14;
}

.transactions-cardsContainer {
-fx-spacing: 25;
-fx-alignment: CENTER_LEFT;
-fx-padding: 10;
}

.transactions-scrollPane {
-fx-fit-to-height: true;
-fx-background: transparent;
-fx-background-color: transparent;
}

0 comments on commit a860e36

Please sign in to comment.