fixed the issues with main
This commit is contained in:
@@ -190,8 +190,10 @@ public class MainLayoutController {
|
||||
btnPurchaseOrders.setVisible(isAdmin);
|
||||
btnPurchaseOrders.setManaged(isAdmin);
|
||||
|
||||
btnStaffAccounts.setVisible(isAdmin);
|
||||
btnStaffAccounts.setManaged(isAdmin);
|
||||
if (btnStaffAccounts != null) {
|
||||
btnStaffAccounts.setVisible(isAdmin);
|
||||
btnStaffAccounts.setManaged(isAdmin);
|
||||
}
|
||||
|
||||
btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.Stage;
|
||||
import org.example.petshopdesktop.database.UserDB;
|
||||
import org.example.petshopdesktop.util.ActivityLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class StaffRegisterDialogController {
|
||||
|
||||
@FXML
|
||||
private TextField txtFirstName;
|
||||
|
||||
@FXML
|
||||
private TextField txtLastName;
|
||||
|
||||
@FXML
|
||||
private TextField txtEmail;
|
||||
|
||||
@FXML
|
||||
private TextField txtPhone;
|
||||
|
||||
@FXML
|
||||
private TextField txtUsername;
|
||||
|
||||
@FXML
|
||||
private PasswordField txtPassword;
|
||||
|
||||
@FXML
|
||||
private PasswordField txtPasswordConfirm;
|
||||
|
||||
@FXML
|
||||
private Label lblError;
|
||||
|
||||
@FXML
|
||||
private Button btnCreate;
|
||||
|
||||
@FXML
|
||||
void btnCreateClicked(ActionEvent event) {
|
||||
lblError.setText("");
|
||||
|
||||
String firstName = value(txtFirstName);
|
||||
String lastName = value(txtLastName);
|
||||
String email = value(txtEmail);
|
||||
String phone = value(txtPhone);
|
||||
String username = value(txtUsername);
|
||||
String password = txtPassword.getText() == null ? "" : txtPassword.getText();
|
||||
String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText();
|
||||
|
||||
if (firstName.isBlank() || lastName.isBlank()) {
|
||||
lblError.setText("First name and last name are required.");
|
||||
return;
|
||||
}
|
||||
if (email.isBlank()) {
|
||||
lblError.setText("Email is required.");
|
||||
return;
|
||||
}
|
||||
if (phone.isBlank()) {
|
||||
lblError.setText("Phone is required.");
|
||||
return;
|
||||
}
|
||||
if (username.isBlank()) {
|
||||
lblError.setText("Username is required.");
|
||||
return;
|
||||
}
|
||||
if (password.isBlank()) {
|
||||
lblError.setText("Password is required.");
|
||||
return;
|
||||
}
|
||||
if (!password.equals(confirm)) {
|
||||
lblError.setText("Passwords do not match.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
UserDB.createStaffAccount(firstName, lastName, email, phone, username, password);
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("Staff Account");
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText("Staff account created. You can log in now.");
|
||||
alert.showAndWait();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
||||
String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage();
|
||||
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
||||
lblError.setText("Username already exists.");
|
||||
} else {
|
||||
lblError.setText(msg);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Database connection");
|
||||
lblError.setText("Database is not connected.");
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void btnCancelClicked(ActionEvent event) {
|
||||
close();
|
||||
}
|
||||
|
||||
private void close() {
|
||||
Stage stage = (Stage) btnCreate.getScene().getWindow();
|
||||
stage.close();
|
||||
}
|
||||
|
||||
private static String value(TextField tf) {
|
||||
return tf.getText() == null ? "" : tf.getText().trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package org.example.petshopdesktop.database;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class EmployeeDB {
|
||||
|
||||
public static int ensureDefaultEmployee(String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException {
|
||||
Integer existingId = findEmployeeIdByEmail(email);
|
||||
if (existingId != null) {
|
||||
return existingId;
|
||||
}
|
||||
|
||||
try (Connection conn = ConnectionDB.getConnection()) {
|
||||
conn.setAutoCommit(false);
|
||||
try {
|
||||
int storeId = getDefaultStoreId(conn);
|
||||
int employeeId = createEmployee(conn, firstName, lastName, email, phone, role, isActive);
|
||||
assignEmployeeToStore(conn, employeeId, storeId);
|
||||
conn.commit();
|
||||
return employeeId;
|
||||
} catch (SQLException e) {
|
||||
conn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer findEmployeeIdByEmail(String email) throws SQLException {
|
||||
String sql = "SELECT employeeId FROM employee WHERE email = ? LIMIT 1";
|
||||
try (Connection conn = ConnectionDB.getConnection();
|
||||
PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setString(1, email);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return rs.getInt("employeeId");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int createEmployee(Connection conn, String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException {
|
||||
String sql = "INSERT INTO employee (firstName, lastName, email, phone, role, isActive) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.setString(1, firstName);
|
||||
ps.setString(2, lastName);
|
||||
ps.setString(3, email);
|
||||
ps.setString(4, phone);
|
||||
ps.setString(5, role);
|
||||
ps.setBoolean(6, isActive);
|
||||
ps.executeUpdate();
|
||||
|
||||
try (ResultSet keys = ps.getGeneratedKeys()) {
|
||||
if (keys.next()) {
|
||||
return keys.getInt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new SQLException("Could not create employee.");
|
||||
}
|
||||
|
||||
public static void assignEmployeeToStore(Connection conn, int employeeId, int storeId) throws SQLException {
|
||||
String sql = "INSERT IGNORE INTO employeeStore (employeeId, storeId) VALUES (?, ?)";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setInt(1, employeeId);
|
||||
ps.setInt(2, storeId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDefaultStoreId() throws SQLException {
|
||||
try (Connection conn = ConnectionDB.getConnection()) {
|
||||
return getDefaultStoreId(conn);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDefaultStoreId(Connection conn) throws SQLException {
|
||||
Integer existing = firstStoreId(conn);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
String insert = "INSERT INTO storeLocation (storeName, address, phone, email) VALUES ('Main Store', 'N/A', '000-000-0000', 'main@petshop.com')";
|
||||
try (PreparedStatement ps = conn.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.executeUpdate();
|
||||
try (ResultSet keys = ps.getGeneratedKeys()) {
|
||||
if (keys.next()) {
|
||||
return keys.getInt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Integer after = firstStoreId(conn);
|
||||
if (after != null) {
|
||||
return after;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static Integer getPrimaryStoreId(int employeeId) throws SQLException {
|
||||
String sql = "SELECT storeId FROM employeeStore WHERE employeeId = ? ORDER BY storeId ASC LIMIT 1";
|
||||
try (Connection conn = ConnectionDB.getConnection();
|
||||
PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setInt(1, employeeId);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return rs.getInt("storeId");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Integer firstStoreId(Connection conn) throws SQLException {
|
||||
String sql = "SELECT storeId FROM storeLocation ORDER BY storeId ASC LIMIT 1";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql);
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return rs.getInt("storeId");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.example.petshopdesktop.models;
|
||||
|
||||
public class SaleCartItem {
|
||||
private final int prodId;
|
||||
private final String prodName;
|
||||
private int quantity;
|
||||
private final double unitPrice;
|
||||
|
||||
public SaleCartItem(int prodId, String prodName, int quantity, double unitPrice) {
|
||||
this.prodId = prodId;
|
||||
this.prodName = prodName;
|
||||
this.quantity = quantity;
|
||||
this.unitPrice = unitPrice;
|
||||
}
|
||||
|
||||
public int getProdId() {
|
||||
return prodId;
|
||||
}
|
||||
|
||||
public String getProdName() {
|
||||
return prodName;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(int quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public double getUnitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return unitPrice * quantity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.example.petshopdesktop.models;
|
||||
|
||||
public class SaleLineItem {
|
||||
private final int saleId;
|
||||
private final String saleDate;
|
||||
private final String employeeName;
|
||||
private final String itemName;
|
||||
private final int quantity;
|
||||
private final double unitPrice;
|
||||
private final double total;
|
||||
private final String paymentMethod;
|
||||
|
||||
public SaleLineItem(int saleId, String saleDate, String employeeName, String itemName, int quantity, double unitPrice, double total, String paymentMethod) {
|
||||
this.saleId = saleId;
|
||||
this.saleDate = saleDate;
|
||||
this.employeeName = employeeName;
|
||||
this.itemName = itemName;
|
||||
this.quantity = quantity;
|
||||
this.unitPrice = unitPrice;
|
||||
this.total = total;
|
||||
this.paymentMethod = paymentMethod;
|
||||
}
|
||||
|
||||
public int getSaleId() {
|
||||
return saleId;
|
||||
}
|
||||
|
||||
public String getSaleDate() {
|
||||
return saleDate;
|
||||
}
|
||||
|
||||
public String getEmployeeName() {
|
||||
return employeeName;
|
||||
}
|
||||
|
||||
public String getItemName() {
|
||||
return itemName;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public double getUnitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public String getPaymentMethod() {
|
||||
return paymentMethod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.example.petshopdesktop.models;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public class StaffAccount {
|
||||
private final int userId;
|
||||
private final int employeeId;
|
||||
private final String username;
|
||||
private final String firstName;
|
||||
private final String lastName;
|
||||
private final String email;
|
||||
private final String phone;
|
||||
private final boolean active;
|
||||
private final Timestamp createdAt;
|
||||
|
||||
public StaffAccount(int userId, int employeeId, String username, String firstName, String lastName, String email, String phone, boolean active, Timestamp createdAt) {
|
||||
this.userId = userId;
|
||||
this.employeeId = employeeId;
|
||||
this.username = username;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
this.active = active;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public int getEmployeeId() {
|
||||
return employeeId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
String fn = firstName == null ? "" : firstName.trim();
|
||||
String ln = lastName == null ? "" : lastName.trim();
|
||||
return (fn + " " + ln).trim();
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public Timestamp getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return active ? "Active" : "Inactive";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.example.petshopdesktop.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public final class ActivityLogger {
|
||||
|
||||
private static final ActivityLogger INSTANCE = new ActivityLogger();
|
||||
|
||||
private static final String LOG_FILE_NAME = "log.txt";
|
||||
private static final DateTimeFormatter TS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final Path logFilePath;
|
||||
|
||||
private ActivityLogger() {
|
||||
this.logFilePath = resolveProjectRoot().resolve(LOG_FILE_NAME);
|
||||
}
|
||||
|
||||
public static ActivityLogger getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void logInsert(String tableName, String recordId, String details) {
|
||||
write("INSERT", String.format("DB_INSERT | Table: %s | ID: %s | Details: %s", tableName, recordId, details));
|
||||
}
|
||||
|
||||
public void logUpdate(String tableName, String recordId, String details) {
|
||||
write("UPDATE", String.format("DB_UPDATE | Table: %s | ID: %s | Details: %s", tableName, recordId, details));
|
||||
}
|
||||
|
||||
public void logDelete(String tableName, String recordId, String details) {
|
||||
write("DELETE", String.format("DB_DELETE | Table: %s | ID: %s | Details: %s", tableName, recordId, details));
|
||||
}
|
||||
|
||||
public void logException(String location, Exception exception, String context) {
|
||||
write("ERROR", String.format(
|
||||
"EXCEPTION | Location: %s | Type: %s | Message: %s | Context: %s",
|
||||
location,
|
||||
exception.getClass().getSimpleName(),
|
||||
String.valueOf(exception.getMessage()),
|
||||
context
|
||||
));
|
||||
}
|
||||
|
||||
public void logInfo(String category, String message) {
|
||||
write(category, message);
|
||||
}
|
||||
|
||||
public Path getLogFilePath() {
|
||||
return logFilePath;
|
||||
}
|
||||
|
||||
private static Path resolveProjectRoot() {
|
||||
Path start = Paths.get(System.getProperty("user.dir")).toAbsolutePath();
|
||||
Path current = start;
|
||||
|
||||
for (int i = 0; i < 6 && current != null; i++) {
|
||||
if (Files.exists(current.resolve("pom.xml"))
|
||||
|| Files.exists(current.resolve("mvnw"))
|
||||
|| Files.exists(current.resolve("connectionpetstore.properties.example"))) {
|
||||
return current;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private synchronized void write(String level, String message) {
|
||||
String timestamp = LocalDateTime.now().format(TS);
|
||||
String logEntry = String.format("[%s] [%s] %s%n", timestamp, level, message);
|
||||
|
||||
try {
|
||||
Files.writeString(
|
||||
logFilePath,
|
||||
logEntry,
|
||||
StandardCharsets.UTF_8,
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.APPEND
|
||||
);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to write log entry: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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.PasswordField?>
|
||||
<?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="14.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.StaffRegisterDialogController">
|
||||
<padding>
|
||||
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<Label text="Create Staff Account" textFill="#2C3E50">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
|
||||
<Label fx:id="lblError" text="" textFill="#FF6B6B" wrapText="true" />
|
||||
|
||||
<HBox spacing="10.0">
|
||||
<children>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="First Name" />
|
||||
<TextField fx:id="txtFirstName" promptText="First name" />
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Last Name" />
|
||||
<TextField fx:id="txtLastName" promptText="Last name" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox spacing="10.0">
|
||||
<children>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Email" />
|
||||
<TextField fx:id="txtEmail" promptText="name@petshop.com" />
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Phone" />
|
||||
<TextField fx:id="txtPhone" promptText="123-456-7890" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox spacing="10.0">
|
||||
<children>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Username" />
|
||||
<TextField fx:id="txtUsername" promptText="username" />
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Password" />
|
||||
<PasswordField fx:id="txtPassword" promptText="password" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox spacing="10.0">
|
||||
<children>
|
||||
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text="Confirm Password" />
|
||||
<PasswordField fx:id="txtPasswordConfirm" promptText="confirm password" />
|
||||
</children>
|
||||
</VBox>
|
||||
<Region HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
||||
<children>
|
||||
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
||||
<Button fx:id="btnCreate" mnemonicParsing="false" onAction="#btnCreateClicked" style="-fx-background-color: #4ECDC4; -fx-text-fill: white; -fx-cursor: hand;" text="Create" />
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -134,6 +134,15 @@
|
||||
</padding>
|
||||
</Button>
|
||||
|
||||
<Button fx:id="btnStaffAccounts" alignment="CENTER_LEFT" mnemonicParsing="false" onAction="#btnStaffAccountsClicked" prefWidth="250.0" style="-fx-background-color: transparent; -fx-background-radius: 10; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Staff Accounts" textFill="#cbd5e1">
|
||||
<font>
|
||||
<Font name="System" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="14.0" right="14.0" top="10.0" />
|
||||
</padding>
|
||||
</Button>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" />
|
||||
|
||||
<Button fx:id="btnLogout" alignment="CENTER_LEFT" mnemonicParsing="false" onAction="#btnLogoutClicked" prefWidth="250.0" style="-fx-background-color: rgba(255,255,255,0.08); -fx-background-radius: 10; -fx-cursor: hand; -fx-focus-color: transparent; -fx-faint-focus-color: transparent;" text="Logout" textFill="#e2e8f0">
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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="20.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.StaffAccountsController">
|
||||
<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="Staff Accounts" 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>
|
||||
|
||||
<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="txtSearch" promptText="Search staff..." style="-fx-border-width: 0; -fx-background-color: transparent;" HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font size="15.0" />
|
||||
</font>
|
||||
</TextField>
|
||||
</children>
|
||||
</HBox>
|
||||
|
||||
<TableView fx:id="tvStaff" style="-fx-background-color: white; -fx-background-radius: 12;" VBox.vgrow="ALWAYS">
|
||||
<columns>
|
||||
<TableColumn fx:id="colUsername" prefWidth="160.0" text="Username" />
|
||||
<TableColumn fx:id="colName" prefWidth="190.0" text="Name" />
|
||||
<TableColumn fx:id="colEmail" prefWidth="230.0" text="Email" />
|
||||
<TableColumn fx:id="colPhone" prefWidth="140.0" text="Phone" />
|
||||
<TableColumn fx:id="colStatus" prefWidth="90.0" text="Status" />
|
||||
<TableColumn fx:id="colCreated" prefWidth="160.0" text="Created" />
|
||||
</columns>
|
||||
</TableView>
|
||||
|
||||
<Label fx:id="lblError" text="" textFill="#FF6B6B" wrapText="true" />
|
||||
</children>
|
||||
</VBox>
|
||||
Reference in New Issue
Block a user