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()
|
||||
List<UserResponse> staff = UserApi.getInstance().listUsers(null).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();
|
||||
}
|
||||
|
||||
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,9 +64,12 @@ public class SaleDetailDialogController {
|
||||
lblTotal.setText(currency.format(sale.getTotalAmount()));
|
||||
tvItems.setItems(sale.getItems());
|
||||
if (btnRefund != null) {
|
||||
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||
if (!isAdmin) {
|
||||
btnRefund.setDisable(sale.isRefund());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSaleId(Long saleId) {
|
||||
this.saleId = saleId;
|
||||
|
||||
@@ -176,6 +176,14 @@
|
||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
<Button fx:id="btnCustomers" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnCustomersClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Customers" textFill="#cbd5e1">
|
||||
<font>
|
||||
<Font name="System" size="12.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
|
||||
<Separator fx:id="separatorAdmin" prefWidth="200.0" style="-fx-background-color: #444444; -fx-opacity: 0.35;" />
|
||||
|
||||
@@ -220,7 +228,7 @@
|
||||
<Insets bottom="8.0" left="10.0" right="10.0" top="8.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
<Button fx:id="btnStaffAccounts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnStaffAccountsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="User Accounts" textFill="#cbd5e1">
|
||||
<Button fx:id="btnStaffAccounts" alignment="CENTER_LEFT" maxWidth="Infinity" mnemonicParsing="false" onAction="#btnStaffAccountsClicked" style="-fx-background-color: transparent; -fx-background-radius: 8; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Staff Accounts" textFill="#cbd5e1">
|
||||
<font>
|
||||
<Font name="System" size="12.0" />
|
||||
</font>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?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.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<VBox spacing="16.0" style="-fx-font-size: 14px;" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.CustomerAccountsController">
|
||||
<padding>
|
||||
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
|
||||
</padding>
|
||||
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="20.0">
|
||||
<children>
|
||||
<Label text="Customers" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="30.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="btnRefresh" mnemonicParsing="false" onAction="#btnRefreshClicked" prefHeight="44.0" prefWidth="118.0" 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>
|
||||
</HBox>
|
||||
|
||||
<VBox spacing="10.0" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="12.0">
|
||||
<children>
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="btnEditCustomer" mnemonicParsing="false" onAction="#btnEditCustomerClicked" prefHeight="40.0" style="-fx-background-color: #F4A261; -fx-cursor: hand; -fx-background-radius: 8;" text="Edit Customer" textFill="WHITE">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox alignment="CENTER_LEFT" 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>
|
||||
<Insets bottom="10.0" left="15.0" right="15.0" top="10.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<TextField fx:id="txtSearchCustomer" promptText="Search customers..." style="-fx-border-width: 0; -fx-background-color: transparent;" HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font size="15.0" />
|
||||
</font>
|
||||
</TextField>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<TableView fx:id="tvCustomers" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="colCustomerUsername" prefWidth="130.0" text="Username" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="160.0" text="Name" />
|
||||
<TableColumn fx:id="colCustomerEmail" prefWidth="200.0" text="Email" />
|
||||
<TableColumn fx:id="colCustomerPhone" prefWidth="130.0" text="Phone" />
|
||||
<TableColumn fx:id="colCustomerLoyaltyPoints" prefWidth="120.0" text="Loyalty Points" />
|
||||
<TableColumn fx:id="colCustomerStatus" prefWidth="90.0" text="Status" />
|
||||
<TableColumn fx:id="colCustomerCreated" prefWidth="150.0" text="Created" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
<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" />
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -48,7 +48,7 @@
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
<FlowPane hgap="8.0" maxWidth="Infinity" prefWrapLength="260.0" vgap="8.0">
|
||||
<HBox alignment="CENTER_RIGHT" spacing="8.0">
|
||||
<children>
|
||||
<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>
|
||||
@@ -67,7 +67,7 @@
|
||||
</padding>
|
||||
</Button>
|
||||
</children>
|
||||
</FlowPane>
|
||||
</HBox>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="20.0">
|
||||
<children>
|
||||
<Label text="User Accounts" textFill="#2c3e50">
|
||||
<Label text="Staff Accounts" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="30.0" />
|
||||
</font>
|
||||
@@ -36,65 +36,10 @@
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<!-- Customers Section -->
|
||||
<VBox spacing="10.0" VBox.vgrow="ALWAYS">
|
||||
<VBox fx:id="staffSection" spacing="10.0" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="12.0">
|
||||
<children>
|
||||
<Label text="Customers" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="20.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="btnEditCustomer" mnemonicParsing="false" onAction="#btnEditCustomerClicked" prefHeight="40.0" style="-fx-background-color: #F4A261; -fx-cursor: hand; -fx-background-radius: 8;" text="Edit Customer" textFill="WHITE">
|
||||
<font>
|
||||
<Font name="System Bold" size="14.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox alignment="CENTER_LEFT" 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>
|
||||
<Insets bottom="10.0" left="15.0" right="15.0" top="10.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<TextField fx:id="txtSearchCustomer" promptText="Search customers..." style="-fx-border-width: 0; -fx-background-color: transparent;" HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font size="15.0" />
|
||||
</font>
|
||||
</TextField>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<TableView fx:id="tvCustomers" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="colCustomerUsername" prefWidth="130.0" text="Username" />
|
||||
<TableColumn fx:id="colCustomerName" prefWidth="160.0" text="Name" />
|
||||
<TableColumn fx:id="colCustomerEmail" prefWidth="200.0" text="Email" />
|
||||
<TableColumn fx:id="colCustomerPhone" prefWidth="130.0" text="Phone" />
|
||||
<TableColumn fx:id="colCustomerLoyaltyPoints" prefWidth="120.0" text="Loyalty Points" />
|
||||
<TableColumn fx:id="colCustomerStatus" prefWidth="90.0" text="Status" />
|
||||
<TableColumn fx:id="colCustomerCreated" prefWidth="150.0" text="Created" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
<!-- Staff Section (admin only) -->
|
||||
<VBox fx:id="staffSection" spacing="10.0" managed="false" visible="false" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<HBox alignment="CENTER_LEFT" spacing="12.0">
|
||||
<children>
|
||||
<Label text="Staff" textFill="#2c3e50">
|
||||
<font>
|
||||
<Font name="System Bold" size="20.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="btnCreateAccount" mnemonicParsing="false" onAction="#btnCreateAccountClicked" prefHeight="40.0" style="-fx-background-color: #FF6B6B; -fx-cursor: hand; -fx-background-radius: 8;" text="Create Account" textFill="WHITE">
|
||||
<font>
|
||||
|
||||
Reference in New Issue
Block a user