seperated staff and customer on desktop
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
package org.example.petshopdesktop.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.transformation.FilteredList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.CustomerApi;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
import org.example.petshopdesktop.util.TableViewSupport;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CustomerAccountsController {
|
||||
|
||||
@FXML
|
||||
private TableView<UserResponse> tvCustomers;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerUsername;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerName;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerEmail;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerPhone;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, Object> colCustomerLoyaltyPoints;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerStatus;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, Object> colCustomerCreated;
|
||||
|
||||
@FXML
|
||||
private TextField txtSearchCustomer;
|
||||
|
||||
@FXML
|
||||
private Button btnEditCustomer;
|
||||
|
||||
@FXML
|
||||
private Button btnRefresh;
|
||||
|
||||
@FXML
|
||||
private Label lblError;
|
||||
|
||||
@FXML
|
||||
private Label lblStatus;
|
||||
|
||||
private final ObservableList<UserResponse> customerAccounts = FXCollections.observableArrayList();
|
||||
private FilteredList<UserResponse> filteredCustomers;
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
colCustomerUsername.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getUsername()));
|
||||
colCustomerName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
|
||||
colCustomerEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
|
||||
colCustomerPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
|
||||
colCustomerLoyaltyPoints.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getLoyaltyPoints()));
|
||||
colCustomerStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getActive() != null && data.getValue().getActive() ? "Active" : "Inactive"));
|
||||
colCustomerCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));
|
||||
|
||||
filteredCustomers = new FilteredList<>(customerAccounts, a -> true);
|
||||
TableViewSupport.bindSortedItems(tvCustomers, filteredCustomers);
|
||||
TableViewSupport.installDoubleClickAction(tvCustomers, this::openEditDialog);
|
||||
|
||||
tvCustomers.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) ->
|
||||
btnEditCustomer.setDisable(newVal == null));
|
||||
btnEditCustomer.setDisable(true);
|
||||
|
||||
txtSearchCustomer.textProperty().addListener((obs, o, n) -> applyCustomerFilter(n));
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnRefreshClicked(ActionEvent event) {
|
||||
txtSearchCustomer.clear();
|
||||
TableViewSupport.clearSort(tvCustomers);
|
||||
refresh();
|
||||
TableViewSupport.flashStatus(lblStatus, "Refreshed");
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnEditCustomerClicked(ActionEvent event) {
|
||||
lblError.setText("");
|
||||
openEditDialog(tvCustomers.getSelectionModel().getSelectedItem());
|
||||
}
|
||||
|
||||
private void openEditDialog(UserResponse selected) {
|
||||
if (selected == null) {
|
||||
lblError.setText("Select a customer to edit.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/staff-edit-dialog-view.fxml"));
|
||||
Stage dialog = new Stage();
|
||||
dialog.initOwner(tvCustomers.getScene().getWindow());
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setTitle("Edit Customer Account");
|
||||
dialog.setScene(new Scene(loader.load()));
|
||||
dialog.setResizable(false);
|
||||
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
|
||||
controller.setUser(selected);
|
||||
dialog.showAndWait();
|
||||
refresh();
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("CustomerAccountsController.openEditDialog", e, "Opening customer edit dialog");
|
||||
lblError.setText("Could not open customer account editor.");
|
||||
}
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
lblError.setText("");
|
||||
tvCustomers.setDisable(true);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Comparator<UserResponse> byCreated = Comparator.comparing(
|
||||
UserResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||
|
||||
List<UserResponse> customers = CustomerApi.getInstance().listCustomers(null).stream()
|
||||
.sorted(byCreated)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
customerAccounts.setAll(customers);
|
||||
tvCustomers.setDisable(false);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("CustomerAccountsController.refresh", e, "Loading customer accounts");
|
||||
Platform.runLater(() -> {
|
||||
lblError.setText("Could not load customer accounts.");
|
||||
tvCustomers.setDisable(false);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyCustomerFilter(String text) {
|
||||
String q = text == null ? "" : text.trim().toLowerCase();
|
||||
if (q.isEmpty()) {
|
||||
filteredCustomers.setPredicate(a -> true);
|
||||
return;
|
||||
}
|
||||
filteredCustomers.setPredicate(a ->
|
||||
safe(a.getUsername()).contains(q)
|
||||
|| safe(a.getFullName()).contains(q)
|
||||
|| safe(a.getEmail()).contains(q)
|
||||
|| safe(a.getPhone()).contains(q)
|
||||
);
|
||||
}
|
||||
|
||||
private static String safe(String v) {
|
||||
return v == null ? "" : v.toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,9 @@ public class MainLayoutController {
|
||||
@FXML
|
||||
private Button btnStaffAccounts;
|
||||
|
||||
@FXML
|
||||
private Button btnCustomers;
|
||||
|
||||
@FXML
|
||||
private Button btnAnalytics;
|
||||
|
||||
@@ -179,6 +182,12 @@ public class MainLayoutController {
|
||||
updateButtons(btnStaffAccounts);
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnCustomersClicked(ActionEvent event) {
|
||||
loadView("customer-accounts-view.fxml");
|
||||
updateButtons(btnCustomers);
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnAnalyticsClicked(ActionEvent event) {
|
||||
loadView("analytics-view.fxml");
|
||||
@@ -415,8 +424,13 @@ public class MainLayoutController {
|
||||
btnPurchaseOrders.setManaged(isAdmin);
|
||||
|
||||
if (btnStaffAccounts != null) {
|
||||
btnStaffAccounts.setVisible(true);
|
||||
btnStaffAccounts.setManaged(true);
|
||||
btnStaffAccounts.setVisible(isAdmin);
|
||||
btnStaffAccounts.setManaged(isAdmin);
|
||||
}
|
||||
|
||||
if (btnCustomers != null) {
|
||||
btnCustomers.setVisible(true);
|
||||
btnCustomers.setManaged(true);
|
||||
}
|
||||
|
||||
if (lblAdminSection != null) {
|
||||
@@ -493,6 +507,7 @@ public class MainLayoutController {
|
||||
btnProducts,
|
||||
btnPurchaseOrders,
|
||||
btnStaffAccounts,
|
||||
btnCustomers,
|
||||
btnAnalytics,
|
||||
btnActivityLogs,
|
||||
btnCoupons,
|
||||
|
||||
@@ -255,6 +255,8 @@ public class SaleController {
|
||||
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||
vbCreateSale.setVisible(!isAdmin);
|
||||
vbCreateSale.setManaged(!isAdmin);
|
||||
btnRefund.setVisible(!isAdmin);
|
||||
btnRefund.setManaged(!isAdmin);
|
||||
lblModeNote.setText(isAdmin ? "(View only)" : "(Staff can create sales)");
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,11 @@ import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
||||
import org.example.petshopdesktop.api.endpoints.CustomerApi;
|
||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
@@ -32,36 +27,6 @@ public class StaffAccountsController {
|
||||
@FXML
|
||||
private VBox staffSection;
|
||||
|
||||
@FXML
|
||||
private TableView<UserResponse> tvCustomers;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerUsername;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerName;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerEmail;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerPhone;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, Object> colCustomerLoyaltyPoints;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, String> colCustomerStatus;
|
||||
|
||||
@FXML
|
||||
private TableColumn<UserResponse, Object> colCustomerCreated;
|
||||
|
||||
@FXML
|
||||
private TextField txtSearchCustomer;
|
||||
|
||||
@FXML
|
||||
private Button btnEditCustomer;
|
||||
|
||||
@FXML
|
||||
private TableView<UserResponse> tvStaff;
|
||||
|
||||
@@ -104,32 +69,11 @@ public class StaffAccountsController {
|
||||
@FXML
|
||||
private Label lblStatus;
|
||||
|
||||
private final ObservableList<UserResponse> customerAccounts = FXCollections.observableArrayList();
|
||||
private FilteredList<UserResponse> filteredCustomers;
|
||||
|
||||
private final ObservableList<UserResponse> staffAccounts = FXCollections.observableArrayList();
|
||||
private FilteredList<UserResponse> filteredStaff;
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
colCustomerUsername.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getUsername()));
|
||||
colCustomerName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
|
||||
colCustomerEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
|
||||
colCustomerPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
|
||||
colCustomerLoyaltyPoints.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getLoyaltyPoints()));
|
||||
colCustomerStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getActive() != null && data.getValue().getActive() ? "Active" : "Inactive"));
|
||||
colCustomerCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));
|
||||
|
||||
filteredCustomers = new FilteredList<>(customerAccounts, a -> true);
|
||||
TableViewSupport.bindSortedItems(tvCustomers, filteredCustomers);
|
||||
TableViewSupport.installDoubleClickAction(tvCustomers, this::openEditDialog);
|
||||
|
||||
tvCustomers.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) ->
|
||||
btnEditCustomer.setDisable(newVal == null));
|
||||
btnEditCustomer.setDisable(true);
|
||||
|
||||
txtSearchCustomer.textProperty().addListener((obs, o, n) -> applyCustomerFilter(n));
|
||||
|
||||
colUsername.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getUsername()));
|
||||
colName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
|
||||
colEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
|
||||
@@ -148,29 +92,17 @@ public class StaffAccountsController {
|
||||
|
||||
txtSearch.textProperty().addListener((obs, o, n) -> applyStaffFilter(n));
|
||||
|
||||
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||
staffSection.setVisible(isAdmin);
|
||||
staffSection.setManaged(isAdmin);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnRefreshClicked(ActionEvent event) {
|
||||
txtSearchCustomer.clear();
|
||||
txtSearch.clear();
|
||||
TableViewSupport.clearSort(tvCustomers);
|
||||
TableViewSupport.clearSort(tvStaff);
|
||||
refresh();
|
||||
TableViewSupport.flashStatus(lblStatus, "Refreshed");
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnEditCustomerClicked(ActionEvent event) {
|
||||
lblError.setText("");
|
||||
openEditDialog(tvCustomers.getSelectionModel().getSelectedItem());
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnCreateAccountClicked(ActionEvent event) {
|
||||
lblError.setText("");
|
||||
@@ -214,10 +146,9 @@ public class StaffAccountsController {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/staff-edit-dialog-view.fxml"));
|
||||
Stage dialog = new Stage();
|
||||
Stage owner = (tvStaff.getScene() != null) ? (Stage) tvStaff.getScene().getWindow() : (Stage) tvCustomers.getScene().getWindow();
|
||||
dialog.initOwner(owner);
|
||||
dialog.initOwner(tvStaff.getScene().getWindow());
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setTitle("Edit User Account");
|
||||
dialog.setTitle("Edit Staff Account");
|
||||
dialog.setScene(new Scene(loader.load()));
|
||||
dialog.setResizable(false);
|
||||
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
|
||||
@@ -232,7 +163,6 @@ public class StaffAccountsController {
|
||||
|
||||
private void refresh() {
|
||||
lblError.setText("");
|
||||
tvCustomers.setDisable(true);
|
||||
tvStaff.setDisable(true);
|
||||
|
||||
new Thread(() -> {
|
||||
@@ -240,60 +170,25 @@ public class StaffAccountsController {
|
||||
Comparator<UserResponse> byCreated = Comparator.comparing(
|
||||
UserResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||
|
||||
final List<UserResponse> customers;
|
||||
final List<UserResponse> staff;
|
||||
|
||||
if (UserSession.getInstance().isAdmin()) {
|
||||
List<UserResponse> allUsers = UserApi.getInstance().listUsers(null);
|
||||
customers = allUsers.stream()
|
||||
.filter(u -> "CUSTOMER".equalsIgnoreCase(u.getRole()))
|
||||
.sorted(byCreated)
|
||||
.collect(Collectors.toList());
|
||||
staff = allUsers.stream()
|
||||
.filter(u -> !"CUSTOMER".equalsIgnoreCase(u.getRole()))
|
||||
.sorted(byCreated)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
customers = CustomerApi.getInstance().listCustomers(null).stream()
|
||||
.sorted(byCreated)
|
||||
.collect(Collectors.toList());
|
||||
staff = List.of();
|
||||
}
|
||||
List<UserResponse> staff = UserApi.getInstance().listUsers(null).stream()
|
||||
.filter(u -> !"CUSTOMER".equalsIgnoreCase(u.getRole()))
|
||||
.sorted(byCreated)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
customerAccounts.setAll(customers);
|
||||
staffAccounts.setAll(staff);
|
||||
tvCustomers.setDisable(false);
|
||||
tvStaff.setDisable(false);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading user accounts");
|
||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts");
|
||||
Platform.runLater(() -> {
|
||||
String message = e.getMessage();
|
||||
lblError.setText(message == null || message.isBlank()
|
||||
? "Could not load user accounts."
|
||||
: "Could not load user accounts: " + message);
|
||||
tvCustomers.setDisable(false);
|
||||
lblError.setText("Could not load staff accounts.");
|
||||
tvStaff.setDisable(false);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyCustomerFilter(String text) {
|
||||
String q = text == null ? "" : text.trim().toLowerCase();
|
||||
if (q.isEmpty()) {
|
||||
filteredCustomers.setPredicate(a -> true);
|
||||
return;
|
||||
}
|
||||
filteredCustomers.setPredicate(a ->
|
||||
safe(a.getUsername()).contains(q)
|
||||
|| safe(a.getFullName()).contains(q)
|
||||
|| safe(a.getEmail()).contains(q)
|
||||
|| safe(a.getPhone()).contains(q)
|
||||
);
|
||||
}
|
||||
|
||||
private void applyStaffFilter(String text) {
|
||||
String q = text == null ? "" : text.trim().toLowerCase();
|
||||
if (q.isEmpty()) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
import org.example.petshopdesktop.auth.UserSession;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -46,6 +47,12 @@ public class SaleDetailDialogController {
|
||||
colQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
||||
colUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
||||
colLineTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
|
||||
|
||||
if (btnRefund != null) {
|
||||
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||
btnRefund.setVisible(!isAdmin);
|
||||
btnRefund.setManaged(!isAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
public void displaySaleDetails(SaleDetail sale) {
|
||||
@@ -57,7 +64,10 @@ public class SaleDetailDialogController {
|
||||
lblTotal.setText(currency.format(sale.getTotalAmount()));
|
||||
tvItems.setItems(sale.getItems());
|
||||
if (btnRefund != null) {
|
||||
btnRefund.setDisable(sale.isRefund());
|
||||
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||
if (!isAdmin) {
|
||||
btnRefund.setDisable(sale.isRefund());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user