Merge Table Fixes #161

Merged
RecentRunner merged 10 commits from table-fixes into main 2026-04-09 21:49:18 -06:00
34 changed files with 835 additions and 113 deletions

View File

@@ -16,6 +16,7 @@ import org.example.petshopdesktop.api.endpoints.AdoptionApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.AdoptionDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.AdoptionDialogController;
import org.example.petshopdesktop.models.Adoption; import org.example.petshopdesktop.models.Adoption;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
@@ -34,6 +35,12 @@ public class AdoptionController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<Adoption, Integer> colAdoptionId; private TableColumn<Adoption, Integer> colAdoptionId;
@@ -78,8 +85,10 @@ public class AdoptionController {
colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate")); colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate"));
colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee")); colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee"));
colAdoptionStatus.setCellValueFactory(new PropertyValueFactory<>("adoptionStatus")); colAdoptionStatus.setCellValueFactory(new PropertyValueFactory<>("adoptionStatus"));
TableViewSupport.applyCurrencyColumn(colAdoptionFee);
displayAdoptions(); displayAdoptions();
TableViewSupport.installDoubleClickAction(tvAdoptions, selected -> openDialog(selected, "Edit"));
tvAdoptions.getSelectionModel().selectedItemProperty().addListener( tvAdoptions.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> { (observable, oldValue, newValue) -> {
@@ -101,6 +110,14 @@ public class AdoptionController {
}); });
} }
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvAdoptions.getSortOrder().clear();
displayAdoptions();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -6,6 +6,8 @@ import javafx.fxml.FXML;
import javafx.scene.chart.*; import javafx.scene.chart.*;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import org.example.petshopdesktop.api.dto.analytics.DailySales; import org.example.petshopdesktop.api.dto.analytics.DailySales;
import org.example.petshopdesktop.api.dto.analytics.DashboardResponse; import org.example.petshopdesktop.api.dto.analytics.DashboardResponse;
import org.example.petshopdesktop.api.dto.analytics.TopProduct; import org.example.petshopdesktop.api.dto.analytics.TopProduct;
@@ -15,6 +17,7 @@ import org.example.petshopdesktop.api.endpoints.AnalyticsApi;
import org.example.petshopdesktop.api.endpoints.SaleApi; import org.example.petshopdesktop.api.endpoints.SaleApi;
import org.example.petshopdesktop.auth.UserSession; import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
@@ -32,6 +35,9 @@ public class AnalyticsController {
@FXML @FXML
private Button btnRefresh; private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private Label lblError; private Label lblError;
@@ -65,6 +71,9 @@ public class AnalyticsController {
@FXML @FXML
private BarChart<String, Number> chartEmployeePerformance; private BarChart<String, Number> chartEmployeePerformance;
@FXML
private TabPane tabPane;
private static final String SALES_COLOR = "#ff6b35"; private static final String SALES_COLOR = "#ff6b35";
private static final String REVENUE_COLOR = "#4ecdc4"; private static final String REVENUE_COLOR = "#4ecdc4";
private static final String QUANTITY_COLOR = "#ff9f1c"; private static final String QUANTITY_COLOR = "#ff9f1c";
@@ -79,6 +88,13 @@ public class AnalyticsController {
@FXML @FXML
public void initialize() { public void initialize() {
configureCharts(); configureCharts();
if (tabPane != null) {
tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> {
if (oldTab != newTab && newTab != null) {
loadAnalyticsData();
}
});
}
loadAnalyticsData(); loadAnalyticsData();
} }
@@ -126,6 +142,9 @@ public class AnalyticsController {
private void loadAnalyticsData() { private void loadAnalyticsData() {
lblError.setVisible(false); lblError.setVisible(false);
if (lblStatus != null) {
lblStatus.setVisible(false);
}
new Thread(() -> { new Thread(() -> {
try { try {
DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10); DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10);
@@ -472,5 +491,6 @@ public class AnalyticsController {
@FXML @FXML
void handleRefresh(ActionEvent event) { void handleRefresh(ActionEvent event) {
loadAnalyticsData(); loadAnalyticsData();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
} }
} }

View File

@@ -18,6 +18,7 @@ import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse;
import org.example.petshopdesktop.api.endpoints.AppointmentApi; import org.example.petshopdesktop.api.endpoints.AppointmentApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.AppointmentDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.AppointmentDialogController;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.util.List; import java.util.List;
import java.util.Comparator; import java.util.Comparator;
@@ -39,6 +40,9 @@ public class AppointmentController {
@FXML private Button btnAdd; @FXML private Button btnAdd;
@FXML private Button btnEdit; @FXML private Button btnEdit;
@FXML private Button btnDelete; @FXML private Button btnDelete;
@FXML private Button btnRefresh;
@FXML private Label lblStatus;
@FXML private TextField txtSearch; @FXML private TextField txtSearch;
@@ -61,7 +65,8 @@ public class AppointmentController {
colAppointmentStatus.setCellValueFactory(new PropertyValueFactory<>("appointmentStatus")); colAppointmentStatus.setCellValueFactory(new PropertyValueFactory<>("appointmentStatus"));
filtered = new FilteredList<>(appointments, a -> true); filtered = new FilteredList<>(appointments, a -> true);
tvAppointments.setItems(filtered); TableViewSupport.bindSortedItems(tvAppointments, filtered);
TableViewSupport.installDoubleClickAction(tvAppointments, selected -> openDialog(selected, "Edit"));
if (txtSearch != null) { if (txtSearch != null) {
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n)); txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
@@ -133,6 +138,14 @@ public class AppointmentController {
}).start(); }).start();
} }
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvAppointments.getSortOrder().clear();
loadAppointments();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event){ void btnAddClicked(ActionEvent event){
openDialog(null, "Add"); openDialog(null, "Add");
@@ -250,7 +263,20 @@ public class AppointmentController {
response.getEmployeeName() != null ? response.getEmployeeName() : "", response.getEmployeeName() != null ? response.getEmployeeName() : "",
response.getAppointmentDate() != null ? response.getAppointmentDate().toString() : "", response.getAppointmentDate() != null ? response.getAppointmentDate().toString() : "",
response.getAppointmentTime() != null ? response.getAppointmentTime().toString() : "", response.getAppointmentTime() != null ? response.getAppointmentTime().toString() : "",
response.getAppointmentStatus() != null ? response.getAppointmentStatus() : "" normalizeAppointmentStatus(response.getAppointmentStatus())
); );
} }
private String normalizeAppointmentStatus(String status) {
if (status == null) {
return "Booked";
}
return switch (status.trim().toLowerCase()) {
case "booked" -> "Booked";
case "completed" -> "Completed";
case "missed" -> "Missed";
case "cancelled", "canceled" -> "Cancelled";
default -> "Booked";
};
}
} }

View File

@@ -16,6 +16,7 @@ import org.example.petshopdesktop.api.endpoints.InventoryApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.InventoryDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.InventoryDialogController;
import org.example.petshopdesktop.models.Inventory; import org.example.petshopdesktop.models.Inventory;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -34,6 +35,12 @@ public class InventoryController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<Inventory, Integer> colInventoryId; private TableColumn<Inventory, Integer> colInventoryId;
@@ -70,6 +77,7 @@ public class InventoryController {
colQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity")); colQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
displayInventory(); displayInventory();
TableViewSupport.installDoubleClickAction(tvInventory, selected -> openDialog(selected, "Edit"));
tvInventory.getSelectionModel().selectedItemProperty().addListener( tvInventory.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> { (observable, oldValue, newValue) -> {
@@ -92,6 +100,14 @@ public class InventoryController {
} }
//Opens dialog in add mode //Opens dialog in add mode
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvInventory.getSortOrder().clear();
displayInventory();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -22,6 +22,7 @@ import org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogControl
import org.example.petshopdesktop.models.Pet; import org.example.petshopdesktop.models.Pet;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.DesktopImageSupport; import org.example.petshopdesktop.util.DesktopImageSupport;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -39,6 +40,12 @@ public class PetController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<Pet, Integer> colPetAge; private TableColumn<Pet, Integer> colPetAge;
@@ -81,6 +88,20 @@ public class PetController {
@FXML @FXML
private TextField txtSearch; private TextField txtSearch;
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
if (cbSpeciesFilter != null) {
cbSpeciesFilter.getSelectionModel().selectFirst();
}
if (cbStatusFilter != null) {
cbStatusFilter.getSelectionModel().selectFirst();
}
tvPets.getSortOrder().clear();
displayPets();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";
@@ -162,6 +183,7 @@ public class PetController {
colPetAge.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petAge")); colPetAge.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petAge"));
colPetStatus.setCellValueFactory(new PropertyValueFactory<Pet,String>("petStatus")); colPetStatus.setCellValueFactory(new PropertyValueFactory<Pet,String>("petStatus"));
colPetPrice.setCellValueFactory(new PropertyValueFactory<Pet,Double>("petPrice")); colPetPrice.setCellValueFactory(new PropertyValueFactory<Pet,Double>("petPrice"));
TableViewSupport.applyCurrencyColumn(colPetPrice);
colCustomerName.setCellValueFactory(new PropertyValueFactory<Pet,String>("customerName")); colCustomerName.setCellValueFactory(new PropertyValueFactory<Pet,String>("customerName"));
colStoreName.setCellValueFactory(new PropertyValueFactory<Pet,String>("storeName")); colStoreName.setCellValueFactory(new PropertyValueFactory<Pet,String>("storeName"));
configureImageColumn(colPetImage); configureImageColumn(colPetImage);
@@ -172,6 +194,7 @@ public class PetController {
cbStatusFilter.getSelectionModel().selectFirst(); cbStatusFilter.getSelectionModel().selectFirst();
displayPets(); displayPets();
TableViewSupport.installDoubleClickAction(tvPets, selected -> openDialog(selected, "Edit"));
tvPets.getSelectionModel().selectedItemProperty().addListener( tvPets.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> { (observable, oldValue, newValue) -> {
@@ -357,7 +380,7 @@ public class PetController {
setGraphic(null); setGraphic(null);
return; return;
} }
DesktopImageSupport.loadImageInto(imageView, item, 48, 48); DesktopImageSupport.loadImageInto(imageView, item, 24, 24);
setGraphic(container); setGraphic(container);
} }
}); });

View File

@@ -22,6 +22,7 @@ import org.example.petshopdesktop.api.endpoints.ProductApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.DesktopImageSupport; import org.example.petshopdesktop.util.DesktopImageSupport;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -43,6 +44,12 @@ public class ProductController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<ProductDTO, String> colProductCategory; private TableColumn<ProductDTO, String> colProductCategory;
@@ -91,10 +98,12 @@ public class ProductController {
colProductPrice.setCellValueFactory(new PropertyValueFactory<ProductDTO,Double>("prodPrice")); colProductPrice.setCellValueFactory(new PropertyValueFactory<ProductDTO,Double>("prodPrice"));
colProductCategory.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("categoryName")); colProductCategory.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("categoryName"));
colProductDesc.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodDesc")); colProductDesc.setCellValueFactory(new PropertyValueFactory<ProductDTO,String>("prodDesc"));
TableViewSupport.applyCurrencyColumn(colProductPrice);
configureImageColumn(colProductImage); configureImageColumn(colProductImage);
loadCategoryFilter(); loadCategoryFilter();
displayProduct(); displayProduct();
TableViewSupport.installDoubleClickAction(tvProducts, selected -> openDialog(selected, "Edit"));
//EventListener to Enable buttons when a row is selected //EventListener to Enable buttons when a row is selected
tvProducts.getSelectionModel().selectedItemProperty().addListener( tvProducts.getSelectionModel().selectedItemProperty().addListener(
@@ -154,6 +163,17 @@ public class ProductController {
* open a new dialog for adding a product * open a new dialog for adding a product
* @param event click event for button * @param event click event for button
*/ */
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
if (cbCategoryFilter != null) {
cbCategoryFilter.getSelectionModel().selectFirst();
}
tvProducts.getSortOrder().clear();
displayProduct();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -16,6 +16,7 @@ import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRespons
import org.example.petshopdesktop.api.endpoints.ProductSupplierApi; import org.example.petshopdesktop.api.endpoints.ProductSupplierApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -33,6 +34,12 @@ public class ProductSupplierController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<ProductSupplierDTO, Double> colCost; private TableColumn<ProductSupplierDTO, Double> colCost;
@@ -76,6 +83,7 @@ public class ProductSupplierController {
colCost.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,Double>("cost")); colCost.setCellValueFactory(new PropertyValueFactory<ProductSupplierDTO,Double>("cost"));
displayProductSupplier(); displayProductSupplier();
TableViewSupport.installDoubleClickAction(tvProductSuppliers, selected -> openDialog(selected, "Edit"));
//EventListener to Enable buttons when a row is selected //EventListener to Enable buttons when a row is selected
tvProductSuppliers.getSelectionModel().selectedItemProperty().addListener( tvProductSuppliers.getSelectionModel().selectedItemProperty().addListener(
@@ -165,6 +173,14 @@ public class ProductSupplierController {
* open a new dialog for adding a productSupplier * open a new dialog for adding a productSupplier
* @param event click event for button * @param event click event for button
*/ */
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvProductSuppliers.getSortOrder().clear();
displayProductSupplier();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -5,13 +5,21 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse;
import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi; import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.PurchaseOrderDetailsDialogController;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Comparator; import java.util.Comparator;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -20,6 +28,8 @@ public class PurchaseOrderController {
@FXML private Button btnRefresh; @FXML private Button btnRefresh;
@FXML private Label lblStatus;
@FXML @FXML
private TextField txtSearch; private TextField txtSearch;
@@ -49,7 +59,8 @@ public class PurchaseOrderController {
new PropertyValueFactory<>("status")); new PropertyValueFactory<>("status"));
filtered = new FilteredList<>(purchaseOrders, p -> true); filtered = new FilteredList<>(purchaseOrders, p -> true);
tvPurchaseOrders.setItems(filtered); TableViewSupport.bindSortedItems(tvPurchaseOrders, filtered);
TableViewSupport.installDoubleClickAction(tvPurchaseOrders, this::openDetailsDialog);
if (txtSearch != null) { if (txtSearch != null) {
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n)); txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
@@ -69,7 +80,6 @@ public class PurchaseOrderController {
Platform.runLater(() -> { Platform.runLater(() -> {
purchaseOrders.setAll(dtos); purchaseOrders.setAll(dtos);
tvPurchaseOrders.setItems(filtered);
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -109,7 +119,34 @@ public class PurchaseOrderController {
@FXML @FXML
void btnRefresh() { void btnRefresh() {
if (txtSearch != null) {
txtSearch.clear();
}
TableViewSupport.clearSort(tvPurchaseOrders);
loadPurchaseOrders(); loadPurchaseOrders();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
private void openDetailsDialog(PurchaseOrderDTO selected) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml"));
Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.setTitle("Purchase Order Details");
dialog.setScene(new Scene(loader.load()));
PurchaseOrderDetailsDialogController controller = loader.getController();
controller.displayPurchaseOrder(selected);
controller.setCloseAction(() -> dialog.close());
dialog.initOwner(tvPurchaseOrders.getScene().getWindow());
dialog.setResizable(false);
dialog.showAndWait();
} catch (IOException e) {
ActivityLogger.getInstance().logException(
"PurchaseOrderController.openDetailsDialog",
e,
"Opening purchase order details");
new Alert(Alert.AlertType.ERROR, "Unable to open purchase order details").showAndWait();
}
} }
private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) { private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) {

View File

@@ -7,7 +7,6 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.input.MouseButton;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@@ -37,6 +36,7 @@ import org.example.petshopdesktop.models.SaleCartItem;
import org.example.petshopdesktop.models.SaleDetail; import org.example.petshopdesktop.models.SaleDetail;
import org.example.petshopdesktop.models.SaleLineItem; import org.example.petshopdesktop.models.SaleLineItem;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.NumberFormat; import java.text.NumberFormat;
@@ -51,6 +51,9 @@ public class SaleController {
@FXML @FXML
private Button btnRefresh; private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private Button btnRefund; private Button btnRefund;
@@ -153,10 +156,12 @@ public class SaleController {
colCartQty.setCellValueFactory(new PropertyValueFactory<>("quantity")); colCartQty.setCellValueFactory(new PropertyValueFactory<>("quantity"));
colCartUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice")); colCartUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
colCartTotal.setCellValueFactory(new PropertyValueFactory<>("total")); colCartTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
TableViewSupport.applyCurrencyColumn(colCartUnitPrice);
TableViewSupport.applyCurrencyColumn(colCartTotal);
tvCart.setItems(cartItems); tvCart.setItems(cartItems);
tvCart.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); tvCart.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
tvSales.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tvSales.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
tvSales.setFixedCellSize(34); tvSales.setFixedCellSize(34);
colSaleId.setCellValueFactory(new PropertyValueFactory<>("saleId")); colSaleId.setCellValueFactory(new PropertyValueFactory<>("saleId"));
colSaleDate.setCellValueFactory(new PropertyValueFactory<>("saleDate")); colSaleDate.setCellValueFactory(new PropertyValueFactory<>("saleDate"));
@@ -166,18 +171,12 @@ public class SaleController {
colSaleUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice")); colSaleUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
colSaleTotal.setCellValueFactory(new PropertyValueFactory<>("total")); colSaleTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
colSalePaymentType.setCellValueFactory(new PropertyValueFactory<>("paymentMethod")); colSalePaymentType.setCellValueFactory(new PropertyValueFactory<>("paymentMethod"));
TableViewSupport.applyCurrencyColumn(colSaleUnitPrice);
TableViewSupport.applyCurrencyColumn(colSaleTotal);
filteredSales = new FilteredList<>(saleItems, s -> true); filteredSales = new FilteredList<>(saleItems, s -> true);
tvSales.setItems(filteredSales); TableViewSupport.bindSortedItems(tvSales, filteredSales);
TableViewSupport.installDoubleClickAction(tvSales, selected -> openSaleDetailDialog(selected.getSaleId()));
tvSales.setOnMouseClicked(event -> {
if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2) {
SaleLineItem selected = tvSales.getSelectionModel().getSelectedItem();
if (selected != null) {
openSaleDetailDialog(selected.getSaleId());
}
}
});
txtSearch.textProperty().addListener((obs, oldVal, newVal) -> applySalesFilter(newVal)); txtSearch.textProperty().addListener((obs, oldVal, newVal) -> applySalesFilter(newVal));
} }
@@ -300,7 +299,10 @@ public class SaleController {
@FXML @FXML
void btnRefresh(ActionEvent event) { void btnRefresh(ActionEvent event) {
refreshSales(true); txtSearch.clear();
TableViewSupport.clearSort(tvSales);
refreshSales(false);
TableViewSupport.flashStatus(lblStatus, "Refreshed");
} }
@FXML @FXML
@@ -433,10 +435,11 @@ public class SaleController {
@FXML @FXML
void btnRefund(ActionEvent event) { void btnRefund(ActionEvent event) {
openRefundDialog(); SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem();
openRefundDialog(selectedSale != null ? (long) selectedSale.getSaleId() : null);
} }
private void openRefundDialog() { private void openRefundDialog(Long saleId) {
try { try {
SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem(); SaleLineItem selectedSale = tvSales.getSelectionModel().getSelectedItem();
if (selectedSale != null && selectedSale.isRefund()) { if (selectedSale != null && selectedSale.isRefund()) {
@@ -452,8 +455,8 @@ public class SaleController {
dialog.setTitle("Process Refund"); dialog.setTitle("Process Refund");
dialog.setScene(new Scene(loader.load())); dialog.setScene(new Scene(loader.load()));
var controller = loader.<org.example.petshopdesktop.controllers.dialogcontrollers.RefundDialogController>getController(); var controller = loader.<org.example.petshopdesktop.controllers.dialogcontrollers.RefundDialogController>getController();
if (selectedSale != null) { if (saleId != null) {
controller.prefillSale((long) selectedSale.getSaleId()); controller.prefillSale(saleId);
} }
dialog.setMinWidth(860); dialog.setMinWidth(860);
dialog.setMinHeight(680); dialog.setMinHeight(680);
@@ -485,6 +488,8 @@ public class SaleController {
dialog.setTitle("Sale Details"); dialog.setTitle("Sale Details");
dialog.setScene(new Scene(loader.load())); dialog.setScene(new Scene(loader.load()));
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.SaleDetailDialogController) loader.getController(); var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.SaleDetailDialogController) loader.getController();
controller.setSaleId((long) sale.getSaleId());
controller.setRefundAction(this::openRefundDialog);
controller.displaySaleDetails(mapToSaleDetail(sale)); controller.displaySaleDetails(mapToSaleDetail(sale));
dialog.setResizable(false); dialog.setResizable(false);
dialog.showAndWait(); dialog.showAndWait();
@@ -528,6 +533,7 @@ public class SaleController {
sale.getTotalAmount() != null ? sale.getTotalAmount().doubleValue() : 0.0, sale.getTotalAmount() != null ? sale.getTotalAmount().doubleValue() : 0.0,
sale.getPaymentMethod(), sale.getPaymentMethod(),
sale.getEmployeeName(), sale.getEmployeeName(),
Boolean.TRUE.equals(sale.getIsRefund()),
items items
); );
} }

View File

@@ -15,6 +15,7 @@ import org.example.petshopdesktop.api.dto.service.ServiceResponse;
import org.example.petshopdesktop.api.endpoints.ServiceApi; import org.example.petshopdesktop.api.endpoints.ServiceApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import javafx.stage.Modality; import javafx.stage.Modality;
import java.util.List; import java.util.List;
@@ -27,6 +28,9 @@ public class ServiceController {
@FXML private Button btnAdd; @FXML private Button btnAdd;
@FXML private Button btnDelete; @FXML private Button btnDelete;
@FXML private Button btnEdit; @FXML private Button btnEdit;
@FXML private Button btnRefresh;
@FXML private Label lblStatus;
@FXML private TableColumn<ServiceDTO, Integer> colServiceId; @FXML private TableColumn<ServiceDTO, Integer> colServiceId;
@FXML private TableColumn<ServiceDTO, String> colServiceName; @FXML private TableColumn<ServiceDTO, String> colServiceName;
@@ -52,8 +56,10 @@ public class ServiceController {
colServiceDesc.setCellValueFactory(new PropertyValueFactory<>("serviceDesc")); colServiceDesc.setCellValueFactory(new PropertyValueFactory<>("serviceDesc"));
colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration")); colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration"));
colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice")); colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice"));
TableViewSupport.applyCurrencyColumn(colServicePrice);
displayServices(); displayServices();
TableViewSupport.installDoubleClickAction(tvServices, selected -> openDialog(selected, "Edit"));
tvServices.getSelectionModel().selectedItemProperty().addListener( tvServices.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> { (observable, oldValue, newValue) -> {
@@ -129,6 +135,14 @@ public class ServiceController {
} }
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvServices.getSortOrder().clear();
displayServices();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -21,6 +21,7 @@ import org.example.petshopdesktop.api.endpoints.EmployeeApi;
import org.example.petshopdesktop.auth.UserSession; import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.models.StaffAccount; import org.example.petshopdesktop.models.StaffAccount;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.ZoneId; import java.time.ZoneId;
@@ -57,6 +58,12 @@ public class StaffAccountsController {
@FXML @FXML
private Label lblError; private Label lblError;
@FXML
private Label lblStatus;
@FXML
private Button btnRefresh;
@FXML @FXML
private Button btnCreateAccount; private Button btnCreateAccount;
@@ -76,7 +83,8 @@ public class StaffAccountsController {
colCreated.setCellValueFactory(new PropertyValueFactory<>("createdAt")); colCreated.setCellValueFactory(new PropertyValueFactory<>("createdAt"));
filtered = new FilteredList<>(staffAccounts, a -> true); filtered = new FilteredList<>(staffAccounts, a -> true);
tvStaff.setItems(filtered); TableViewSupport.bindSortedItems(tvStaff, filtered);
TableViewSupport.installDoubleClickAction(tvStaff, this::openEditDialog);
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n)); txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
@@ -105,7 +113,10 @@ public class StaffAccountsController {
@FXML @FXML
void btnRefreshClicked(ActionEvent event) { void btnRefreshClicked(ActionEvent event) {
txtSearch.clear();
TableViewSupport.clearSort(tvStaff);
refresh(); refresh();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
} }
@FXML @FXML
@@ -131,6 +142,10 @@ public class StaffAccountsController {
void btnEditAccountClicked(ActionEvent event) { void btnEditAccountClicked(ActionEvent event) {
lblError.setText(""); lblError.setText("");
StaffAccount selected = tvStaff.getSelectionModel().getSelectedItem(); StaffAccount selected = tvStaff.getSelectionModel().getSelectedItem();
openEditDialog(selected);
}
private void openEditDialog(StaffAccount selected) {
if (selected == null) { if (selected == null) {
lblError.setText("Select a staff account to edit."); lblError.setText("Select a staff account to edit.");
return; return;

View File

@@ -16,6 +16,7 @@ import org.example.petshopdesktop.api.endpoints.SupplierApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController; import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController;
import org.example.petshopdesktop.models.Supplier; import org.example.petshopdesktop.models.Supplier;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -36,6 +37,12 @@ public class SupplierController {
@FXML @FXML
private Button btnEdit; private Button btnEdit;
@FXML
private Button btnRefresh;
@FXML
private Label lblStatus;
@FXML @FXML
private TableColumn<Supplier, String> colContactPerson; private TableColumn<Supplier, String> colContactPerson;
@@ -78,6 +85,7 @@ public class SupplierController {
colSupplierPhone.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supPhone")); colSupplierPhone.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supPhone"));
displaySupplier(); displaySupplier();
TableViewSupport.installDoubleClickAction(tvSuppliers, selected -> openDialog(selected, "Edit"));
//EventListener to Enable buttons when a row is selected //EventListener to Enable buttons when a row is selected
tvSuppliers.getSelectionModel().selectedItemProperty().addListener( tvSuppliers.getSelectionModel().selectedItemProperty().addListener(
@@ -168,6 +176,14 @@ public class SupplierController {
* open a new dialog for adding a supplier * open a new dialog for adding a supplier
* @param event click event for button * @param event click event for button
*/ */
@FXML
void btnRefresh(ActionEvent event) {
txtSearch.clear();
tvSuppliers.getSortOrder().clear();
displaySupplier();
TableViewSupport.flashStatus(lblStatus, "Refreshed");
}
@FXML @FXML
void btnAddClicked(ActionEvent event) { void btnAddClicked(ActionEvent event) {
mode = "Add"; mode = "Add";

View File

@@ -265,6 +265,7 @@ public class AdoptionDialogController {
if (adoption != null) { if (adoption != null) {
selectedAdoption = adoption; selectedAdoption = adoption;
lblAdoptionId.setText("ID: " + adoption.getAdoptionId()); lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
ensureSelectedEmployeeOption(cbEmployee.getItems());
applySelectedPet(); applySelectedPet();
applySelectedCustomer(); applySelectedCustomer();
applySelectedEmployee(); applySelectedEmployee();

View File

@@ -49,7 +49,7 @@ public class AppointmentDialogController {
private ObservableList<String> statusList = private ObservableList<String> statusList =
FXCollections.observableArrayList( FXCollections.observableArrayList(
"Booked", "Completed", "Cancelled", "Missed" "Booked", "Completed", "Missed", "Cancelled"
); );
public void setMode(String mode) { public void setMode(String mode) {
@@ -83,6 +83,36 @@ public class AppointmentDialogController {
cbMinute.getItems().addAll(0, 15, 30, 45); cbMinute.getItems().addAll(0, 15, 30, 45);
cbHour.setCellFactory(param -> new ListCell<>() {
@Override
protected void updateItem(Integer option, boolean empty) {
super.updateItem(option, empty);
setText(empty || option == null ? null : String.valueOf(option));
}
});
cbHour.setButtonCell(new ListCell<>() {
@Override
protected void updateItem(Integer option, boolean empty) {
super.updateItem(option, empty);
setText(empty || option == null ? null : String.valueOf(option));
}
});
cbMinute.setCellFactory(param -> new ListCell<>() {
@Override
protected void updateItem(Integer option, boolean empty) {
super.updateItem(option, empty);
setText(empty || option == null ? null : String.format("%02d", option));
}
});
cbMinute.setButtonCell(new ListCell<>() {
@Override
protected void updateItem(Integer option, boolean empty) {
super.updateItem(option, empty);
setText(empty || option == null ? null : String.format("%02d", option));
}
});
cbService.setCellFactory(param -> new ListCell<>() { cbService.setCellFactory(param -> new ListCell<>() {
@Override @Override
protected void updateItem(DropdownOption option, boolean empty) { protected void updateItem(DropdownOption option, boolean empty) {
@@ -182,7 +212,7 @@ public class AppointmentDialogController {
"Parsing appointment date"); "Parsing appointment date");
} }
cbAppointmentStatus.setValue(appt.getAppointmentStatus()); cbAppointmentStatus.setValue(normalizeAppointmentStatus(appt.getAppointmentStatus()));
try { try {
LocalTime time = LocalTime.parse(appt.getAppointmentTime()); LocalTime time = LocalTime.parse(appt.getAppointmentTime());
@@ -230,7 +260,7 @@ public class AppointmentDialogController {
request.setEmployeeId(cbEmployee.getValue().getId()); request.setEmployeeId(cbEmployee.getValue().getId());
request.setAppointmentDate(dpAppointmentDate.getValue()); request.setAppointmentDate(dpAppointmentDate.getValue());
request.setAppointmentTime(appointmentTime); request.setAppointmentTime(appointmentTime);
request.setAppointmentStatus(cbAppointmentStatus.getValue()); request.setAppointmentStatus(normalizeAppointmentStatus(cbAppointmentStatus.getValue()));
new Thread(() -> { new Thread(() -> {
try { try {
@@ -451,4 +481,17 @@ public class AppointmentDialogController {
} }
}).start(); }).start();
} }
private String normalizeAppointmentStatus(String status) {
if (status == null) {
return "Booked";
}
return switch (status.trim().toLowerCase()) {
case "booked" -> "Booked";
case "completed" -> "Completed";
case "missed" -> "Missed";
case "cancelled", "canceled" -> "Cancelled";
default -> "Booked";
};
}
} }

View File

@@ -19,7 +19,9 @@ import org.example.petshopdesktop.api.endpoints.ProductSupplierApi;
import org.example.petshopdesktop.util.ActivityLogger; import org.example.petshopdesktop.util.ActivityLogger;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class ProductSupplierDialogController { public class ProductSupplierDialogController {
@@ -49,6 +51,10 @@ public class ProductSupplierDialogController {
private int selectedProdId = -1; private int selectedProdId = -1;
private Long pendingSupplierId = null; private Long pendingSupplierId = null;
private Long pendingProductId = null; private Long pendingProductId = null;
private boolean updatingChoices = false;
private ObservableList<DropdownOption> baseSuppliers = FXCollections.observableArrayList();
private ObservableList<DropdownOption> baseProducts = FXCollections.observableArrayList();
private List<ProductSupplierResponse> relations = List.of();
/** /**
* add event listeners to buttons and set up combobox * add event listeners to buttons and set up combobox
@@ -115,20 +121,39 @@ public class ProductSupplierDialogController {
} }
}); });
cbProduct.valueProperty().addListener((obs, oldValue, newValue) -> {
if (updatingChoices) {
return;
}
filterSuppliersByProduct(newValue != null ? newValue.getId() : null);
});
cbSupplier.valueProperty().addListener((obs, oldValue, newValue) -> {
if (updatingChoices) {
return;
}
filterProductsBySupplier(newValue != null ? newValue.getId() : null);
});
new Thread(() -> { new Thread(() -> {
try { try {
var productSupplierLinks = ProductSupplierApi.getInstance().listProductSuppliers(null);
var suppliers = DropdownApi.getInstance().getSuppliers(); var suppliers = DropdownApi.getInstance().getSuppliers();
var products = DropdownApi.getInstance().getProducts(); var products = DropdownApi.getInstance().getProducts();
Platform.runLater(() -> { Platform.runLater(() -> {
relations = productSupplierLinks != null ? productSupplierLinks : List.of();
if (suppliers != null) { if (suppliers != null) {
cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); baseSuppliers = FXCollections.observableArrayList(suppliers);
cbSupplier.setItems(FXCollections.observableArrayList(baseSuppliers));
applyPendingSupplierSelection(); applyPendingSupplierSelection();
} }
if (products != null) { if (products != null) {
cbProduct.setItems(FXCollections.observableArrayList(products)); baseProducts = FXCollections.observableArrayList(products);
cbProduct.setItems(FXCollections.observableArrayList(baseProducts));
applyPendingProductSelection(); applyPendingProductSelection();
} }
applyCurrentFilters();
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -271,7 +296,10 @@ public class ProductSupplierDialogController {
} }
DropdownOption product = findOptionById(cbProduct.getItems(), pendingProductId); DropdownOption product = findOptionById(cbProduct.getItems(), pendingProductId);
if (product != null) { if (product != null) {
updatingChoices = true;
cbProduct.getSelectionModel().select(product); cbProduct.getSelectionModel().select(product);
updatingChoices = false;
filterSuppliersByProduct(product.getId());
pendingProductId = null; pendingProductId = null;
} }
} }
@@ -282,11 +310,73 @@ public class ProductSupplierDialogController {
} }
DropdownOption supplier = findOptionById(cbSupplier.getItems(), pendingSupplierId); DropdownOption supplier = findOptionById(cbSupplier.getItems(), pendingSupplierId);
if (supplier != null) { if (supplier != null) {
updatingChoices = true;
cbSupplier.getSelectionModel().select(supplier); cbSupplier.getSelectionModel().select(supplier);
updatingChoices = false;
filterProductsBySupplier(supplier.getId());
pendingSupplierId = null; pendingSupplierId = null;
} }
} }
private void applyCurrentFilters() {
DropdownOption selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
DropdownOption selectedSupplier = cbSupplier.getSelectionModel().getSelectedItem();
filterSuppliersByProduct(selectedProduct != null ? selectedProduct.getId() : null);
filterProductsBySupplier(selectedSupplier != null ? selectedSupplier.getId() : null);
}
private void filterSuppliersByProduct(Long productId) {
updatingChoices = true;
try {
if (productId == null) {
cbSupplier.setItems(FXCollections.observableArrayList(baseSuppliers));
return;
}
Set<Long> allowedSupplierIds = new HashSet<>();
for (ProductSupplierResponse relation : relations) {
if (relation.getProductId() != null && relation.getProductId().equals(productId) && relation.getSupplierId() != null) {
allowedSupplierIds.add(relation.getSupplierId());
}
}
ObservableList<DropdownOption> filtered = FXCollections.observableArrayList(
baseSuppliers.stream().filter(option -> option.getId() != null && allowedSupplierIds.contains(option.getId())).toList()
);
cbSupplier.setItems(filtered);
DropdownOption selectedSupplier = cbSupplier.getSelectionModel().getSelectedItem();
if (selectedSupplier != null && !allowedSupplierIds.contains(selectedSupplier.getId())) {
cbSupplier.getSelectionModel().clearSelection();
}
} finally {
updatingChoices = false;
}
}
private void filterProductsBySupplier(Long supplierId) {
updatingChoices = true;
try {
if (supplierId == null) {
cbProduct.setItems(FXCollections.observableArrayList(baseProducts));
return;
}
Set<Long> allowedProductIds = new HashSet<>();
for (ProductSupplierResponse relation : relations) {
if (relation.getSupplierId() != null && relation.getSupplierId().equals(supplierId) && relation.getProductId() != null) {
allowedProductIds.add(relation.getProductId());
}
}
ObservableList<DropdownOption> filtered = FXCollections.observableArrayList(
baseProducts.stream().filter(option -> option.getId() != null && allowedProductIds.contains(option.getId())).toList()
);
cbProduct.setItems(filtered);
DropdownOption selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
if (selectedProduct != null && !allowedProductIds.contains(selectedProduct.getId())) {
cbProduct.getSelectionModel().clearSelection();
}
} finally {
updatingChoices = false;
}
}
private DropdownOption findOptionById(List<DropdownOption> options, Long id) { private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
if (options == null || id == null) { if (options == null || id == null) {
return null; return null;

View File

@@ -0,0 +1,40 @@
package org.example.petshopdesktop.controllers.dialogcontrollers;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
public class PurchaseOrderDetailsDialogController {
@FXML private Label lblOrderId;
@FXML private Label lblSupplier;
@FXML private Label lblOrderDate;
@FXML private Label lblStatus;
private Runnable closeAction;
public void displayPurchaseOrder(PurchaseOrderDTO order) {
if (order == null) {
return;
}
lblOrderId.setText(String.valueOf(order.getPurchaseOrderId()));
lblSupplier.setText(order.getSupplierName() != null ? order.getSupplierName() : "");
lblOrderDate.setText(order.getOrderDate() != null ? order.getOrderDate() : "");
lblStatus.setText(order.getStatus() != null ? order.getStatus() : "");
}
public void setCloseAction(Runnable closeAction) {
this.closeAction = closeAction;
}
@FXML
void btnCloseClicked() {
if (closeAction != null) {
closeAction.run();
return;
}
Stage stage = (Stage) lblOrderId.getScene().getWindow();
stage.close();
}
}

View File

@@ -2,11 +2,19 @@ package org.example.petshopdesktop.controllers.dialogcontrollers;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.example.petshopdesktop.models.SaleDetail; import org.example.petshopdesktop.models.SaleDetail;
import org.example.petshopdesktop.controllers.dialogcontrollers.RefundDialogController;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Modality;
import org.example.petshopdesktop.util.ActivityLogger;
import java.util.function.Consumer;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -19,6 +27,7 @@ public class SaleDetailDialogController {
@FXML private Label lblEmployee; @FXML private Label lblEmployee;
@FXML private Label lblPayment; @FXML private Label lblPayment;
@FXML private Label lblTotal; @FXML private Label lblTotal;
@FXML private Button btnRefund;
@FXML private TableView<SaleDetail.SaleDetailItem> tvItems; @FXML private TableView<SaleDetail.SaleDetailItem> tvItems;
@FXML private TableColumn<SaleDetail.SaleDetailItem, String> colProduct; @FXML private TableColumn<SaleDetail.SaleDetailItem, String> colProduct;
@FXML private TableColumn<SaleDetail.SaleDetailItem, Integer> colQuantity; @FXML private TableColumn<SaleDetail.SaleDetailItem, Integer> colQuantity;
@@ -27,6 +36,8 @@ public class SaleDetailDialogController {
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA); private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
private Long saleId;
private Consumer<Long> refundAction;
@FXML @FXML
public void initialize() { public void initialize() {
@@ -38,12 +49,48 @@ public class SaleDetailDialogController {
} }
public void displaySaleDetails(SaleDetail sale) { public void displaySaleDetails(SaleDetail sale) {
saleId = (long) sale.getSaleId();
lblSaleId.setText(String.valueOf(sale.getSaleId())); lblSaleId.setText(String.valueOf(sale.getSaleId()));
lblSaleDate.setText(sale.getSaleDate() != null ? sale.getSaleDate().format(DATE_FORMATTER) : ""); lblSaleDate.setText(sale.getSaleDate() != null ? sale.getSaleDate().format(DATE_FORMATTER) : "");
lblEmployee.setText(sale.getEmployeeName() != null ? sale.getEmployeeName() : ""); lblEmployee.setText(sale.getEmployeeName() != null ? sale.getEmployeeName() : "");
lblPayment.setText(sale.getPaymentMethod() != null ? sale.getPaymentMethod() : ""); lblPayment.setText(sale.getPaymentMethod() != null ? sale.getPaymentMethod() : "");
lblTotal.setText(currency.format(sale.getTotalAmount())); lblTotal.setText(currency.format(sale.getTotalAmount()));
tvItems.setItems(sale.getItems()); tvItems.setItems(sale.getItems());
if (btnRefund != null) {
btnRefund.setDisable(sale.isRefund());
}
}
public void setSaleId(Long saleId) {
this.saleId = saleId;
}
public void setRefundAction(Consumer<Long> refundAction) {
this.refundAction = refundAction;
}
@FXML
void btnRefundClicked() {
if (saleId == null) {
return;
}
if (refundAction != null) {
refundAction.accept(saleId);
return;
}
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/refund-dialog-view.fxml"));
Stage dialog = new Stage();
dialog.initOwner(tvItems.getScene().getWindow());
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.setTitle("Process Refund");
dialog.setScene(new Scene(loader.load()));
RefundDialogController controller = loader.getController();
controller.prefillSale(saleId);
dialog.showAndWait();
} catch (Exception e) {
ActivityLogger.getInstance().logException("SaleDetailDialogController.btnRefundClicked", e, "Opening refund dialog");
}
} }
@FXML @FXML

View File

@@ -9,14 +9,16 @@ public class SaleDetail {
private final double totalAmount; private final double totalAmount;
private final String paymentMethod; private final String paymentMethod;
private final String employeeName; private final String employeeName;
private final boolean refund;
private final ObservableList<SaleDetailItem> items; private final ObservableList<SaleDetailItem> items;
public SaleDetail(int saleId, LocalDateTime saleDate, double totalAmount, String paymentMethod, String employeeName, ObservableList<SaleDetailItem> items) { public SaleDetail(int saleId, LocalDateTime saleDate, double totalAmount, String paymentMethod, String employeeName, boolean refund, ObservableList<SaleDetailItem> items) {
this.saleId = saleId; this.saleId = saleId;
this.saleDate = saleDate; this.saleDate = saleDate;
this.totalAmount = totalAmount; this.totalAmount = totalAmount;
this.paymentMethod = paymentMethod; this.paymentMethod = paymentMethod;
this.employeeName = employeeName; this.employeeName = employeeName;
this.refund = refund;
this.items = items; this.items = items;
} }
@@ -40,6 +42,10 @@ public class SaleDetail {
return employeeName; return employeeName;
} }
public boolean isRefund() {
return refund;
}
public ObservableList<SaleDetailItem> getItems() { public ObservableList<SaleDetailItem> getItems() {
return items; return items;
} }

View File

@@ -0,0 +1,72 @@
package org.example.petshopdesktop.util;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.animation.PauseTransition;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.Label;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseButton;
import javafx.util.Duration;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.function.Consumer;
public final class TableViewSupport {
private TableViewSupport() {
}
public static <T> void bindSortedItems(TableView<T> tableView, FilteredList<T> filteredItems) {
SortedList<T> sortedItems = new SortedList<>(filteredItems);
sortedItems.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedItems);
}
public static void clearSort(TableView<?> tableView) {
tableView.getSortOrder().clear();
}
public static void flashStatus(Label label, String message) {
if (label == null) {
return;
}
label.setText(message);
label.setVisible(true);
PauseTransition delay = new PauseTransition(Duration.seconds(1.5));
delay.setOnFinished(event -> {
label.setVisible(false);
});
delay.playFromStart();
}
public static <S, T extends Number> void applyCurrencyColumn(TableColumn<S, T> column) {
if (column == null) {
return;
}
column.setCellFactory(col -> new TableCell<>() {
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
@Override
protected void updateItem(T value, boolean empty) {
super.updateItem(value, empty);
setText(empty || value == null ? null : currency.format(value.doubleValue()));
}
});
}
public static <T> void installDoubleClickAction(TableView<T> tableView, Consumer<T> action) {
tableView.setRowFactory(tv -> {
TableRow<T> row = new TableRow<>();
row.setOnMouseClicked(event -> {
if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2 && !row.isEmpty()) {
action.accept(row.getItem());
}
});
return row;
});
}
}

View File

@@ -12,9 +12,6 @@
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.HBox?>
<VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="523.0" prefWidth="790.0" <VBox minHeight="-Infinity" minWidth="-Infinity" prefHeight="523.0" prefWidth="790.0"
spacing="20.0" style="-fx-font-size: 14px;" spacing="20.0" style="-fx-font-size: 14px;"
xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1"
@@ -156,7 +153,7 @@
</font> </font>
</Label> </Label>
<HBox spacing="10"> <HBox spacing="10" alignment="CENTER_LEFT">
<!-- Hour --> <!-- Hour -->
<ComboBox fx:id="cbHour" <ComboBox fx:id="cbHour"
@@ -172,6 +169,12 @@
</padding> </padding>
</ComboBox> </ComboBox>
<Label text=":" textFill="#2c3e50">
<font>
<Font name="System Bold" size="18.0" />
</font>
</Label>
<!-- Minute --> <!-- Minute -->
<ComboBox fx:id="cbMinute" <ComboBox fx:id="cbMinute"
promptText="Minute" promptText="Minute"

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox prefHeight="260.0" prefWidth="480.0" spacing="18.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.PurchaseOrderDetailsDialogController">
<padding>
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
</padding>
<children>
<HBox alignment="CENTER_LEFT" spacing="12.0" style="-fx-background-color: #4ECDC4; -fx-background-radius: 12;">
<padding>
<Insets bottom="14.0" left="16.0" right="16.0" top="14.0" />
</padding>
<children>
<Label text="Purchase Order Details" textFill="WHITE">
<font>
<Font name="System Bold" size="22.0" />
</font>
</Label>
<Region HBox.hgrow="ALWAYS" />
<Button mnemonicParsing="false" onAction="#btnCloseClicked" style="-fx-background-color: white; -fx-text-fill: #2c3e50; -fx-background-radius: 8;" text="Close" />
</children>
</HBox>
<GridPane hgap="16.0" vgap="12.0" style="-fx-background-color: white; -fx-background-radius: 12; -fx-border-color: #e6e6e6; -fx-border-radius: 12; -fx-border-width: 1;">
<padding>
<Insets bottom="16.0" left="16.0" right="16.0" top="16.0" />
</padding>
<children>
<Label text="Order ID" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label fx:id="lblOrderId" GridPane.columnIndex="1" GridPane.rowIndex="0" />
<Label text="Supplier" GridPane.columnIndex="0" GridPane.rowIndex="1" />
<Label fx:id="lblSupplier" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Order Date" GridPane.columnIndex="0" GridPane.rowIndex="2" />
<Label fx:id="lblOrderDate" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="Status" GridPane.columnIndex="0" GridPane.rowIndex="3" />
<Label fx:id="lblStatus" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</children>
</GridPane>
</children>
</VBox>

View File

@@ -27,6 +27,7 @@
</font> </font>
</Label> </Label>
<Region HBox.hgrow="ALWAYS" /> <Region HBox.hgrow="ALWAYS" />
<Button fx:id="btnRefund" mnemonicParsing="false" onAction="#btnRefundClicked" style="-fx-background-color: white; -fx-text-fill: #2c3e50; -fx-background-radius: 8;" text="Refund" />
<Button mnemonicParsing="false" onAction="#btnCloseClicked" style="-fx-background-color: white; -fx-text-fill: #2c3e50; -fx-background-radius: 8;" text="Close" /> <Button mnemonicParsing="false" onAction="#btnCloseClicked" style="-fx-background-color: white; -fx-text-fill: #2c3e50; -fx-background-radius: 8;" text="Close" />
</children> </children>
</HBox> </HBox>

View File

@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,6 +73,12 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvAdoptions" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvAdoptions" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colAdoptionId" prefWidth="60.0" text="ID" /> <TableColumn fx:id="colAdoptionId" prefWidth="60.0" text="ID" />

View File

@@ -10,6 +10,7 @@
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?> <?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?> <?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
@@ -25,6 +26,7 @@
<Font name="System Bold" size="24.0" /> <Font name="System Bold" size="24.0" />
</font> </font>
</Label> </Label>
<Region HBox.hgrow="ALWAYS" />
<Button fx:id="btnRefresh" onAction="#handleRefresh" style="-fx-background-color: #4ECDC4; -fx-text-fill: white; -fx-background-radius: 5; -fx-cursor: hand;" text="Refresh"> <Button fx:id="btnRefresh" onAction="#handleRefresh" style="-fx-background-color: #4ECDC4; -fx-text-fill: white; -fx-background-radius: 5; -fx-cursor: hand;" text="Refresh">
<font> <font>
<Font size="13.0" /> <Font size="13.0" />
@@ -35,13 +37,19 @@
</Button> </Button>
</HBox> </HBox>
<Label fx:id="lblStatus" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<Label fx:id="lblError" textFill="#FF6B6B" visible="false"> <Label fx:id="lblError" textFill="#FF6B6B" visible="false">
<font> <font>
<Font size="13.0" /> <Font size="13.0" />
</font> </font>
</Label> </Label>
<TabPane styleClass="analytics-tabs" VBox.vgrow="ALWAYS"> <TabPane fx:id="tabPane" styleClass="analytics-tabs" VBox.vgrow="ALWAYS">
<Tab text="Overview" closable="false"> <Tab text="Overview" closable="false">
<VBox spacing="15.0"> <VBox spacing="15.0">
<padding> <padding>

View File

@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,6 +73,12 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvAppointments" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvAppointments" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colAppointmentId" prefWidth="53.14288330078125" text="ID" /> <TableColumn fx:id="colAppointmentId" prefWidth="53.14288330078125" text="ID" />

View File

@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,6 +73,12 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvInventory" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvInventory" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colInventoryId" prefWidth="94.28570556640625" text="ID" /> <TableColumn fx:id="colInventoryId" prefWidth="94.28570556640625" text="ID" />

View File

@@ -18,7 +18,7 @@
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding> </padding>
<children> <children>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0"> <HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0">
<children> <children>
<Label text="Pets" textFill="#2c3e50"> <Label text="Pets" textFill="#2c3e50">
<font> <font>
@@ -53,6 +53,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -69,19 +77,25 @@
<ComboBox fx:id="cbStatusFilter" prefWidth="150.0" promptText="Status" /> <ComboBox fx:id="cbStatusFilter" prefWidth="150.0" promptText="Status" />
</children> </children>
</HBox> </HBox>
<TableView fx:id="tvPets" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<columns> <font>
<TableColumn fx:id="colPetId" prefWidth="55.0" text="ID" /> <Font size="13.0" />
<TableColumn fx:id="colPetImage" prefWidth="80.0" text="Image" /> </font>
<TableColumn fx:id="colPetName" prefWidth="110.0" text="Name" /> </Label>
<TableColumn fx:id="colPetSpecies" prefWidth="105.0" text="Species" />
<TableColumn fx:id="colPetBreed" prefWidth="145.0" text="Breed" /> <TableView fx:id="tvPets" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<TableColumn fx:id="colPetAge" prefWidth="60.0" text="Age" /> <columns>
<TableColumn fx:id="colPetStatus" prefWidth="110.0" text="Status" /> <TableColumn fx:id="colPetId" prefWidth="55.0" text="ID" />
<TableColumn fx:id="colPetPrice" prefWidth="80.0" text="Price" /> <TableColumn fx:id="colPetImage" prefWidth="80.0" text="Image" />
<TableColumn fx:id="colCustomerName" prefWidth="130.0" text="Owner" /> <TableColumn fx:id="colPetName" prefWidth="110.0" text="Name" />
<TableColumn fx:id="colStoreName" prefWidth="130.0" text="Store" /> <TableColumn fx:id="colPetSpecies" prefWidth="105.0" text="Species" />
</columns> <TableColumn fx:id="colPetBreed" prefWidth="145.0" text="Breed" />
</TableView> <TableColumn fx:id="colPetAge" prefWidth="60.0" text="Age" />
<TableColumn fx:id="colPetStatus" prefWidth="110.0" text="Status" />
<TableColumn fx:id="colPetPrice" prefWidth="80.0" text="Price" />
<TableColumn fx:id="colCustomerName" prefWidth="130.0" text="Owner" />
<TableColumn fx:id="colStoreName" prefWidth="130.0" text="Store" />
</columns>
</TableView>
</children> </children>
</VBox> </VBox>

View File

@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,6 +73,12 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvProductSuppliers" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvProductSuppliers" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colProductId" prefWidth="91.4285888671875" text="Product ID" /> <TableColumn fx:id="colProductId" prefWidth="91.4285888671875" text="Product ID" />

View File

@@ -52,6 +52,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -67,6 +75,12 @@
<ComboBox fx:id="cbCategoryFilter" prefWidth="180.0" promptText="Category" /> <ComboBox fx:id="cbCategoryFilter" prefWidth="180.0" promptText="Category" />
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvProducts" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvProducts" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colProductId" prefWidth="55.0" text="ID" /> <TableColumn fx:id="colProductId" prefWidth="55.0" text="ID" />

View File

@@ -55,6 +55,12 @@
</HBox> </HBox>
<!-- TABLE --> <!-- TABLE -->
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvPurchaseOrders" <TableView fx:id="tvPurchaseOrders"
style="-fx-background-color:white; -fx-background-radius:12;" style="-fx-background-color:white; -fx-background-radius:12;"
VBox.vgrow="ALWAYS"> VBox.vgrow="ALWAYS">

View File

@@ -9,36 +9,47 @@
<?import javafx.scene.control.TableColumn?> <?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?> <?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?> <?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?> <?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<VBox minHeight="-Infinity" minWidth="-Infinity" spacing="20.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.SaleController"> <ScrollPane fitToHeight="true" fitToWidth="false" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" pannable="true" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.SaleController">
<padding> <content>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> <VBox minHeight="-Infinity" minWidth="-Infinity" prefWidth="1100.0" spacing="6.0" style="-fx-font-size: 14px;">
</padding> <padding>
<children> <Insets bottom="6.0" left="6.0" right="6.0" top="6.0" />
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0"> </padding>
<children>
<HBox alignment="CENTER_LEFT" prefHeight="50.0" spacing="8.0">
<children> <children>
<Label text="Sales" textFill="#2c3e50"> <Label text="Sales" textFill="#2c3e50">
<font> <font>
<Font name="System Bold" size="30.0" /> <Font name="System Bold" size="20.0" />
</font> </font>
<HBox.margin> <HBox.margin>
<Insets /> <Insets />
</HBox.margin> </HBox.margin>
</Label> </Label>
<Label fx:id="lblModeNote" text="" textFill="#7f8c8d"> <Label fx:id="lblModeNote" text="" textFill="#7f8c8d">
<font> <font>
<Font name="System Bold" size="16.0" /> <Font name="System Bold" size="11.0" />
</font> </font>
<padding> <padding>
<Insets top="10.0" /> <Insets top="4.0" />
</padding> </padding>
</Label> </Label>
<Region HBox.hgrow="ALWAYS" /> <Label fx:id="lblStatus" text="" textFill="#16a085" visible="false" managed="true">
<Button fx:id="btnRefund" mnemonicParsing="false" onAction="#btnRefund" prefHeight="44.0" style="-fx-background-color: #FF6b6b; -fx-cursor: hand; -fx-background-radius: 8;" text="Process Refund" textFill="WHITE"> <font>
<Font name="System Bold" size="11.0" />
</font>
<padding>
<Insets right="8.0" />
</padding>
</Label>
<Region HBox.hgrow="ALWAYS" />
<Button fx:id="btnRefund" mnemonicParsing="false" onAction="#btnRefund" prefHeight="32.0" style="-fx-background-color: #FF6b6b; -fx-cursor: hand; -fx-background-radius: 8;" text="Process Refund" textFill="WHITE">
<font> <font>
<Font name="System Bold" size="14.0" /> <Font name="System Bold" size="14.0" />
</font> </font>
@@ -46,7 +57,7 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" prefHeight="44.0" prefWidth="118.0" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE"> <Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" prefHeight="32.0" prefWidth="96.0" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font> <font>
<Font name="System Bold" size="14.0" /> <Font name="System Bold" size="14.0" />
</font> </font>
@@ -57,21 +68,21 @@
</children> </children>
</HBox> </HBox>
<VBox fx:id="vbCreateSale" spacing="12.0" style="-fx-background-color: #ffffff; -fx-background-radius: 12; -fx-border-color: #e6e6e6; -fx-border-radius: 12; -fx-border-width: 1;"> <VBox fx:id="vbCreateSale" spacing="2.0" style="-fx-background-color: #ffffff; -fx-background-radius: 12; -fx-border-color: #e6e6e6; -fx-border-radius: 12; -fx-border-width: 1;">
<padding> <padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" /> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" />
</padding> </padding>
<children> <children>
<Label text="Create Sale" textFill="#2c3e50"> <Label text="Create Sale" textFill="#2c3e50">
<font> <font>
<Font name="System Bold" size="18.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
</Label> </Label>
<HBox alignment="CENTER_LEFT" spacing="10.0"> <HBox alignment="CENTER_LEFT" spacing="6.0">
<children> <children>
<ComboBox fx:id="cbProduct" prefHeight="36.0" prefWidth="360.0" promptText="Select a product" /> <ComboBox fx:id="cbProduct" prefHeight="24.0" prefWidth="240.0" promptText="Select a product" />
<Spinner fx:id="spQuantity" prefHeight="36.0" prefWidth="110.0" /> <Spinner fx:id="spQuantity" prefHeight="24.0" prefWidth="70.0" />
<Button fx:id="btnAddToCart" mnemonicParsing="false" onAction="#btnAddToCart" prefHeight="36.0" style="-fx-background-color: #FF6b6b; -fx-cursor: hand; -fx-background-radius: 8;" text="Add" textFill="WHITE"> <Button fx:id="btnAddToCart" mnemonicParsing="false" onAction="#btnAddToCart" prefHeight="24.0" style="-fx-background-color: #FF6b6b; -fx-cursor: hand; -fx-background-radius: 8;" text="Add" textFill="WHITE">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
@@ -79,7 +90,7 @@
<Insets bottom="8.0" left="18.0" right="18.0" top="8.0" /> <Insets bottom="8.0" left="18.0" right="18.0" top="8.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRemoveSelected" mnemonicParsing="false" onAction="#btnRemoveSelected" prefHeight="36.0" style="-fx-background-color: #34495E; -fx-cursor: hand; -fx-background-radius: 8;" text="Remove Selected" textFill="WHITE"> <Button fx:id="btnRemoveSelected" mnemonicParsing="false" onAction="#btnRemoveSelected" prefHeight="24.0" style="-fx-background-color: #34495E; -fx-cursor: hand; -fx-background-radius: 8;" text="Remove Selected" textFill="WHITE">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
@@ -89,7 +100,7 @@
</Button> </Button>
</children> </children>
</HBox> </HBox>
<TableView fx:id="tvCart" prefHeight="170.0" style="-fx-background-color: white; -fx-background-radius: 10;" VBox.vgrow="NEVER"> <TableView fx:id="tvCart" prefHeight="72.0" style="-fx-background-color: white; -fx-background-radius: 10;" VBox.vgrow="NEVER">
<columns> <columns>
<TableColumn fx:id="colCartProduct" prefWidth="310.0" text="Product" /> <TableColumn fx:id="colCartProduct" prefWidth="310.0" text="Product" />
<TableColumn fx:id="colCartQty" prefWidth="90.0" text="Qty" /> <TableColumn fx:id="colCartQty" prefWidth="90.0" text="Qty" />
@@ -98,16 +109,16 @@
</columns> </columns>
</TableView> </TableView>
<Separator /> <Separator />
<HBox alignment="CENTER_LEFT" spacing="12.0"> <HBox alignment="CENTER_LEFT" spacing="12.0">
<children> <children>
<Label text="Payment" textFill="#2c3e50"> <Label text="Payment" textFill="#2c3e50">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
</Label> </Label>
<ComboBox fx:id="cbPaymentMethod" prefHeight="34.0" prefWidth="160.0" /> <ComboBox fx:id="cbPaymentMethod" prefHeight="34.0" prefWidth="160.0" />
<Region HBox.hgrow="ALWAYS" /> <Region HBox.hgrow="ALWAYS" />
<Label text="Total:" textFill="#2c3e50"> <Label text="Total:" textFill="#2c3e50">
<font> <font>
<Font name="System Bold" size="13.0" /> <Font name="System Bold" size="13.0" />
</font> </font>
@@ -139,29 +150,31 @@
</children> </children>
</VBox> </VBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 1; -fx-border-radius: 14; -fx-border-color: #e6e6e6;"> <HBox alignment="CENTER_LEFT" prefHeight="24.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 1; -fx-border-radius: 14; -fx-border-color: #e6e6e6;">
<padding> <padding>
<Insets bottom="10.0" left="15.0" right="15.0" top="10.0" /> <Insets bottom="10.0" left="15.0" right="15.0" top="10.0" />
</padding> </padding>
<children> <children>
<TextField fx:id="txtSearch" prefHeight="31.0" prefWidth="150.0" promptText="Search sales..." style="-fx-border-width: 0; -fx-background-color: transparent;" HBox.hgrow="ALWAYS"> <TextField fx:id="txtSearch" prefHeight="22.0" prefWidth="150.0" promptText="Search sales..." style="-fx-border-width: 0; -fx-background-color: transparent;" HBox.hgrow="ALWAYS">
<font> <font>
<Font size="15.0" /> <Font size="15.0" />
</font> </font>
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<TableView fx:id="tvSales" prefHeight="362.0" style="-fx-background-color: white; -fx-background-radius: 12; -fx-padding: 6;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvSales" prefHeight="270.0" prefWidth="1180.0" style="-fx-background-color: white; -fx-background-radius: 12; -fx-padding: 2;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colSaleId" minWidth="54.0" prefWidth="62.0" text="ID" /> <TableColumn fx:id="colSaleId" minWidth="50.0" prefWidth="60.0" text="ID" />
<TableColumn fx:id="colSaleDate" minWidth="145.0" prefWidth="165.0" text="Date" /> <TableColumn fx:id="colSaleDate" minWidth="150.0" prefWidth="170.0" text="Date" />
<TableColumn fx:id="colEmployeeName" minWidth="130.0" prefWidth="155.0" text="Employee" /> <TableColumn fx:id="colEmployeeName" minWidth="150.0" prefWidth="160.0" text="Employee" />
<TableColumn fx:id="colServiceProduct" minWidth="180.0" prefWidth="240.0" text="Product" /> <TableColumn fx:id="colServiceProduct" minWidth="260.0" prefWidth="320.0" text="Product" />
<TableColumn fx:id="colSaleQuantity" minWidth="62.0" prefWidth="72.0" text="Qty" /> <TableColumn fx:id="colSaleQuantity" minWidth="55.0" prefWidth="70.0" text="Qty" />
<TableColumn fx:id="colSaleUnitPrice" minWidth="95.0" prefWidth="115.0" text="Unit Price" /> <TableColumn fx:id="colSaleUnitPrice" minWidth="100.0" prefWidth="115.0" text="Unit Price" />
<TableColumn fx:id="colSaleTotal" minWidth="90.0" prefWidth="108.0" text="Total" /> <TableColumn fx:id="colSaleTotal" minWidth="100.0" prefWidth="120.0" text="Total" />
<TableColumn fx:id="colSalePaymentType" minWidth="88.0" prefWidth="100.0" text="Payment" /> <TableColumn fx:id="colSalePaymentType" minWidth="95.0" prefWidth="110.0" text="Payment" />
</columns> </columns>
</TableView> </TableView>
</children> </children>
</VBox> </VBox>
</content>
</ScrollPane>

View File

@@ -16,7 +16,7 @@
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" /> <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding> </padding>
<children> <children>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0"> <HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="20.0">
<children> <children>
<Label text="Services" textFill="#2c3e50"> <Label text="Services" textFill="#2c3e50">
<font> <font>
@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,14 +73,20 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<TableView fx:id="tvServices" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<columns> <font>
<TableColumn fx:id="colServiceId" prefWidth="60.0" text="ID" /> <Font size="13.0" />
<TableColumn fx:id="colServiceName" prefWidth="169.71432495117188" text="Name" /> </font>
<TableColumn fx:id="colServiceDesc" prefWidth="206.85711669921875" text="Description" /> </Label>
<TableColumn fx:id="colServiceDuration" prefWidth="185.71429443359375" text="Duration (min)" />
<TableColumn fx:id="colServicePrice" prefWidth="129.14288330078125" text="Price" /> <TableView fx:id="tvServices" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
</columns> <columns>
</TableView> <TableColumn fx:id="colServiceId" prefWidth="60.0" text="ID" />
<TableColumn fx:id="colServiceName" prefWidth="169.71432495117188" text="Name" />
<TableColumn fx:id="colServiceDesc" prefWidth="206.85711669921875" text="Description" />
<TableColumn fx:id="colServiceDuration" prefWidth="185.71429443359375" text="Duration (min)" />
<TableColumn fx:id="colServicePrice" prefWidth="129.14288330078125" text="Price" />
</columns>
</TableView>
</children> </children>
</VBox> </VBox>

View File

@@ -76,6 +76,12 @@
</columns> </columns>
</TableView> </TableView>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<Label fx:id="lblError" text="" textFill="#FF6B6B" wrapText="true" /> <Label fx:id="lblError" text="" textFill="#FF6B6B" wrapText="true" />
</children> </children>
</VBox> </VBox>

View File

@@ -51,6 +51,14 @@
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" /> <Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding> </padding>
</Button> </Button>
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefresh" style="-fx-background-color: #4ECDC4; -fx-cursor: hand; -fx-background-radius: 8;" text="Refresh" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font>
<padding>
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
</padding>
</Button>
</children> </children>
</HBox> </HBox>
<HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;"> <HBox alignment="CENTER_LEFT" prefHeight="37.0" prefWidth="727.0" spacing="10.0" style="-fx-background-color: white; -fx-background-radius: 14; -fx-border-width: 2; -fx-border-radius: 14;">
@@ -65,6 +73,12 @@
</TextField> </TextField>
</children> </children>
</HBox> </HBox>
<Label fx:id="lblStatus" text="" textFill="#64748b" visible="false" managed="true">
<font>
<Font size="13.0" />
</font>
</Label>
<TableView fx:id="tvSuppliers" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS"> <TableView fx:id="tvSuppliers" prefHeight="362.0" prefWidth="752.0" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="colSupplierId" prefWidth="60.0" text="ID" /> <TableColumn fx:id="colSupplierId" prefWidth="60.0" text="ID" />