fixes to desktop part 1
This commit is contained in:
@@ -194,7 +194,7 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupStatusFilter() {
|
private void setupStatusFilter() {
|
||||||
String[] statuses = {"All Statuses", "Completed", "Pending", "Cancelled"};
|
String[] statuses = {"All Statuses", "Completed", "Pending", "Missed", "Cancelled"};
|
||||||
SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusAdoption, statuses, this::loadAdoptions);
|
SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusAdoption, statuses, this::loadAdoptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public class AppointmentDTO {
|
|||||||
private SimpleStringProperty appointmentTime;
|
private SimpleStringProperty appointmentTime;
|
||||||
private SimpleStringProperty appointmentStatus;
|
private SimpleStringProperty appointmentStatus;
|
||||||
private SimpleStringProperty storeName;
|
private SimpleStringProperty storeName;
|
||||||
|
private Long storeId;
|
||||||
|
|
||||||
public AppointmentDTO(int appointmentId,
|
public AppointmentDTO(int appointmentId,
|
||||||
int customerId, String customerName,
|
int customerId, String customerName,
|
||||||
@@ -32,7 +33,8 @@ public class AppointmentDTO {
|
|||||||
String appointmentDate,
|
String appointmentDate,
|
||||||
String appointmentTime,
|
String appointmentTime,
|
||||||
String appointmentStatus,
|
String appointmentStatus,
|
||||||
String storeName) {
|
String storeName,
|
||||||
|
Long storeId) {
|
||||||
|
|
||||||
this.appointmentId = new SimpleIntegerProperty(appointmentId);
|
this.appointmentId = new SimpleIntegerProperty(appointmentId);
|
||||||
this.customerId = new SimpleIntegerProperty(customerId);
|
this.customerId = new SimpleIntegerProperty(customerId);
|
||||||
@@ -47,6 +49,7 @@ public class AppointmentDTO {
|
|||||||
this.appointmentTime = new SimpleStringProperty(appointmentTime);
|
this.appointmentTime = new SimpleStringProperty(appointmentTime);
|
||||||
this.appointmentStatus = new SimpleStringProperty(appointmentStatus);
|
this.appointmentStatus = new SimpleStringProperty(appointmentStatus);
|
||||||
this.storeName = new SimpleStringProperty(storeName != null ? storeName : "");
|
this.storeName = new SimpleStringProperty(storeName != null ? storeName : "");
|
||||||
|
this.storeId = storeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAppointmentId() { return appointmentId.get(); }
|
public int getAppointmentId() { return appointmentId.get(); }
|
||||||
@@ -66,4 +69,6 @@ public class AppointmentDTO {
|
|||||||
public String getAppointmentTime() { return appointmentTime.get(); }
|
public String getAppointmentTime() { return appointmentTime.get(); }
|
||||||
public String getAppointmentStatus() { return appointmentStatus.get(); }
|
public String getAppointmentStatus() { return appointmentStatus.get(); }
|
||||||
public String getStoreName() { return storeName.get(); }
|
public String getStoreName() { return storeName.get(); }
|
||||||
|
|
||||||
|
public Long getStoreId() { return storeId; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.api.dto.adoption;
|
package org.example.petshopdesktop.api.dto.adoption;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
public class AdoptionRequest {
|
public class AdoptionRequest {
|
||||||
@@ -9,7 +10,7 @@ public class AdoptionRequest {
|
|||||||
private Long sourceStoreId;
|
private Long sourceStoreId;
|
||||||
private LocalDate adoptionDate;
|
private LocalDate adoptionDate;
|
||||||
private String adoptionStatus;
|
private String adoptionStatus;
|
||||||
private String paymentMethod;
|
private BigDecimal adoptionFee;
|
||||||
|
|
||||||
public AdoptionRequest() {
|
public AdoptionRequest() {
|
||||||
}
|
}
|
||||||
@@ -62,11 +63,11 @@ public class AdoptionRequest {
|
|||||||
this.adoptionStatus = adoptionStatus;
|
this.adoptionStatus = adoptionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPaymentMethod() {
|
public BigDecimal getAdoptionFee() {
|
||||||
return paymentMethod;
|
return adoptionFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaymentMethod(String paymentMethod) {
|
public void setAdoptionFee(BigDecimal adoptionFee) {
|
||||||
this.paymentMethod = paymentMethod;
|
this.adoptionFee = adoptionFee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public class AdoptionResponse {
|
|||||||
private LocalDate adoptionDate;
|
private LocalDate adoptionDate;
|
||||||
private java.math.BigDecimal adoptionFee;
|
private java.math.BigDecimal adoptionFee;
|
||||||
private String adoptionStatus;
|
private String adoptionStatus;
|
||||||
|
private Long sourceStoreId;
|
||||||
private String sourceStoreName;
|
private String sourceStoreName;
|
||||||
|
|
||||||
public AdoptionResponse() {
|
public AdoptionResponse() {
|
||||||
@@ -98,6 +99,14 @@ public class AdoptionResponse {
|
|||||||
this.adoptionStatus = adoptionStatus;
|
this.adoptionStatus = adoptionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getSourceStoreId() {
|
||||||
|
return sourceStoreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceStoreId(Long sourceStoreId) {
|
||||||
|
this.sourceStoreId = sourceStoreId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSourceStoreName() {
|
public String getSourceStoreName() {
|
||||||
return sourceStoreName;
|
return sourceStoreName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class UserRequest {
|
|||||||
private String phone;
|
private String phone;
|
||||||
private String role;
|
private String role;
|
||||||
private Boolean active;
|
private Boolean active;
|
||||||
|
private Integer loyaltyPoints;
|
||||||
|
|
||||||
public UserRequest() {
|
public UserRequest() {
|
||||||
}
|
}
|
||||||
@@ -67,4 +68,12 @@ public class UserRequest {
|
|||||||
public void setActive(Boolean active) {
|
public void setActive(Boolean active) {
|
||||||
this.active = active;
|
this.active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getLoyaltyPoints() {
|
||||||
|
return loyaltyPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoyaltyPoints(Integer loyaltyPoints) {
|
||||||
|
this.loyaltyPoints = loyaltyPoints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class AppointmentApi {
|
|||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AppointmentResponse> listAppointments(String query, Long storeId) throws Exception {
|
public List<AppointmentResponse> listAppointments(String query, Long storeId, Long employeeId) throws Exception {
|
||||||
String path = "/api/v1/appointments?page=0&size=1000";
|
String path = "/api/v1/appointments?page=0&size=1000";
|
||||||
if (query != null && !query.isEmpty()) {
|
if (query != null && !query.isEmpty()) {
|
||||||
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
@@ -31,6 +31,9 @@ public class AppointmentApi {
|
|||||||
if (storeId != null) {
|
if (storeId != null) {
|
||||||
path += "&storeId=" + storeId;
|
path += "&storeId=" + storeId;
|
||||||
}
|
}
|
||||||
|
if (employeeId != null) {
|
||||||
|
path += "&employeeId=" + employeeId;
|
||||||
|
}
|
||||||
String response = apiClient.getRawResponse(path);
|
String response = apiClient.getRawResponse(path);
|
||||||
PageResponse<AppointmentResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
PageResponse<AppointmentResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
response,
|
response,
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ public class PetApi {
|
|||||||
return listPets(query, null, null, null);
|
return listPets(query, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PetResponse getPetById(Long id) throws Exception {
|
||||||
|
return apiClient.get("/api/v1/pets/" + id, PetResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
public PetResponse createPet(PetRequest request) throws Exception {
|
public PetResponse createPet(PetRequest request) throws Exception {
|
||||||
return apiClient.post("/api/v1/pets", request, PetResponse.class);
|
return apiClient.post("/api/v1/pets", request, PetResponse.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,7 +284,8 @@ public class AdoptionController {
|
|||||||
response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "",
|
response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "",
|
||||||
response.getAdoptionFee() != null ? response.getAdoptionFee().doubleValue() : 0.0,
|
response.getAdoptionFee() != null ? response.getAdoptionFee().doubleValue() : 0.0,
|
||||||
response.getAdoptionStatus(),
|
response.getAdoptionStatus(),
|
||||||
response.getSourceStoreName()
|
response.getSourceStoreName(),
|
||||||
|
response.getSourceStoreId()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public class AppointmentController {
|
|||||||
@FXML private Button btnEdit;
|
@FXML private Button btnEdit;
|
||||||
@FXML private Button btnDelete;
|
@FXML private Button btnDelete;
|
||||||
@FXML private Button btnRefresh;
|
@FXML private Button btnRefresh;
|
||||||
|
@FXML private javafx.scene.control.ToggleButton btnMyAppointments;
|
||||||
|
|
||||||
@FXML private Label lblStatus;
|
@FXML private Label lblStatus;
|
||||||
|
|
||||||
@@ -71,6 +72,11 @@ public class AppointmentController {
|
|||||||
TableViewSupport.bindSortedItems(tvAppointments, filtered);
|
TableViewSupport.bindSortedItems(tvAppointments, filtered);
|
||||||
TableViewSupport.installDoubleClickAction(tvAppointments, selected -> openDialog(selected, "Edit"));
|
TableViewSupport.installDoubleClickAction(tvAppointments, selected -> openDialog(selected, "Edit"));
|
||||||
|
|
||||||
|
if (UserSession.getInstance().isStaff()) {
|
||||||
|
btnMyAppointments.setVisible(true);
|
||||||
|
btnMyAppointments.setManaged(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (txtSearch != null) {
|
if (txtSearch != null) {
|
||||||
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
|
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
|
||||||
}
|
}
|
||||||
@@ -92,11 +98,17 @@ public class AppointmentController {
|
|||||||
loadAppointments();
|
loadAppointments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void btnMyAppointmentsToggled(javafx.event.ActionEvent event) {
|
||||||
|
loadAppointments();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadAppointments(){
|
private void loadAppointments(){
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try{
|
try{
|
||||||
Long storeId = UserSession.getInstance().isAdmin() ? null : UserSession.getInstance().getStoreId();
|
Long storeId = UserSession.getInstance().isAdmin() ? null : UserSession.getInstance().getStoreId();
|
||||||
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(null, storeId);
|
Long employeeId = btnMyAppointments.isSelected() ? UserSession.getInstance().getEmployeeId() : null;
|
||||||
|
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(null, storeId, employeeId);
|
||||||
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||||
.map(this::mapToAppointmentDTO)
|
.map(this::mapToAppointmentDTO)
|
||||||
.sorted(Comparator.comparing((AppointmentDTO a) -> a.getAppointmentDate() + "T" + a.getAppointmentTime()).reversed())
|
.sorted(Comparator.comparing((AppointmentDTO a) -> a.getAppointmentDate() + "T" + a.getAppointmentTime()).reversed())
|
||||||
@@ -122,7 +134,8 @@ public class AppointmentController {
|
|||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Long storeId = UserSession.getInstance().isAdmin() ? null : UserSession.getInstance().getStoreId();
|
Long storeId = UserSession.getInstance().isAdmin() ? null : UserSession.getInstance().getStoreId();
|
||||||
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(query, storeId);
|
Long employeeId = btnMyAppointments.isSelected() ? UserSession.getInstance().getEmployeeId() : null;
|
||||||
|
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(query, storeId, employeeId);
|
||||||
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||||
.map(this::mapToAppointmentDTO)
|
.map(this::mapToAppointmentDTO)
|
||||||
.sorted(Comparator.comparing((AppointmentDTO a) -> a.getAppointmentDate() + "T" + a.getAppointmentTime()).reversed())
|
.sorted(Comparator.comparing((AppointmentDTO a) -> a.getAppointmentDate() + "T" + a.getAppointmentTime()).reversed())
|
||||||
@@ -269,7 +282,8 @@ public class AppointmentController {
|
|||||||
response.getAppointmentDate() != null ? response.getAppointmentDate().toString() : "",
|
response.getAppointmentDate() != null ? response.getAppointmentDate().toString() : "",
|
||||||
response.getAppointmentTime() != null ? response.getAppointmentTime().toString() : "",
|
response.getAppointmentTime() != null ? response.getAppointmentTime().toString() : "",
|
||||||
normalizeAppointmentStatus(response.getAppointmentStatus()),
|
normalizeAppointmentStatus(response.getAppointmentStatus()),
|
||||||
response.getStoreName()
|
response.getStoreName(),
|
||||||
|
response.getStoreId()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,15 +108,15 @@ public class CustomerAccountsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/staff-edit-dialog-view.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/customer-edit-dialog-view.fxml"));
|
||||||
Stage dialog = new Stage();
|
Stage dialog = new Stage();
|
||||||
dialog.initOwner(tvCustomers.getScene().getWindow());
|
dialog.initOwner(tvCustomers.getScene().getWindow());
|
||||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||||
dialog.setTitle("Edit Customer Account");
|
dialog.setTitle("Edit Customer Account");
|
||||||
dialog.setScene(new Scene(loader.load()));
|
dialog.setScene(new Scene(loader.load()));
|
||||||
dialog.setResizable(false);
|
dialog.setResizable(false);
|
||||||
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
|
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.CustomerEditDialogController) loader.getController();
|
||||||
controller.setUser(selected);
|
controller.setCustomer(selected);
|
||||||
dialog.showAndWait();
|
dialog.showAndWait();
|
||||||
refresh();
|
refresh();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
import org.example.petshopdesktop.api.dto.employee.EmployeeResponse;
|
||||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
import org.example.petshopdesktop.api.endpoints.EmployeeApi;
|
||||||
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 org.example.petshopdesktop.util.TableViewSupport;
|
||||||
@@ -24,53 +24,24 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public class StaffAccountsController {
|
public class StaffAccountsController {
|
||||||
|
|
||||||
@FXML
|
@FXML private VBox staffSection;
|
||||||
private VBox staffSection;
|
@FXML private TableView<EmployeeResponse> tvStaff;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colUsername;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colName;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colEmail;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colPhone;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colRole;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, String> colStatus;
|
||||||
|
@FXML private TableColumn<EmployeeResponse, Object> colCreated;
|
||||||
|
@FXML private TextField txtSearch;
|
||||||
|
@FXML private Button btnRefresh;
|
||||||
|
@FXML private Button btnCreateAccount;
|
||||||
|
@FXML private Button btnEditAccount;
|
||||||
|
@FXML private Label lblError;
|
||||||
|
@FXML private Label lblStatus;
|
||||||
|
|
||||||
@FXML
|
private final ObservableList<EmployeeResponse> staffAccounts = FXCollections.observableArrayList();
|
||||||
private TableView<UserResponse> tvStaff;
|
private FilteredList<EmployeeResponse> filteredStaff;
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colUsername;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colName;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colEmail;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colPhone;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colRole;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, String> colStatus;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TableColumn<UserResponse, Object> colCreated;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TextField txtSearch;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button btnRefresh;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button btnCreateAccount;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button btnEditAccount;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblError;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblStatus;
|
|
||||||
|
|
||||||
private final ObservableList<UserResponse> staffAccounts = FXCollections.observableArrayList();
|
|
||||||
private FilteredList<UserResponse> filteredStaff;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
@@ -78,8 +49,13 @@ public class StaffAccountsController {
|
|||||||
colName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
|
colName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
|
||||||
colEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
|
colEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
|
||||||
colPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
|
colPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
|
||||||
colRole.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getRole()));
|
colRole.setCellValueFactory(data -> {
|
||||||
colStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getActive() != null && data.getValue().getActive() ? "Active" : "Inactive"));
|
String role = data.getValue().getRole() != null ? data.getValue().getRole() : "";
|
||||||
|
String staffRole = data.getValue().getStaffRole() != null ? " (" + data.getValue().getStaffRole() + ")" : "";
|
||||||
|
return new javafx.beans.property.SimpleStringProperty(role + staffRole);
|
||||||
|
});
|
||||||
|
colStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(
|
||||||
|
Boolean.TRUE.equals(data.getValue().getActive()) ? "Active" : "Inactive"));
|
||||||
colCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));
|
colCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));
|
||||||
|
|
||||||
filteredStaff = new FilteredList<>(staffAccounts, a -> true);
|
filteredStaff = new FilteredList<>(staffAccounts, a -> true);
|
||||||
@@ -128,7 +104,7 @@ public class StaffAccountsController {
|
|||||||
openEditDialog(tvStaff.getSelectionModel().getSelectedItem());
|
openEditDialog(tvStaff.getSelectionModel().getSelectedItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openEditDialog(UserResponse selected) {
|
private void openEditDialog(EmployeeResponse selected) {
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
lblError.setText("Select a user account to edit.");
|
lblError.setText("Select a user account to edit.");
|
||||||
return;
|
return;
|
||||||
@@ -152,12 +128,12 @@ public class StaffAccountsController {
|
|||||||
dialog.setScene(new Scene(loader.load()));
|
dialog.setScene(new Scene(loader.load()));
|
||||||
dialog.setResizable(false);
|
dialog.setResizable(false);
|
||||||
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
|
var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
|
||||||
controller.setUser(selected);
|
controller.setEmployee(selected);
|
||||||
dialog.showAndWait();
|
dialog.showAndWait();
|
||||||
refresh();
|
refresh();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("StaffAccountsController.openEditDialog", e, "Opening user edit dialog");
|
ActivityLogger.getInstance().logException("StaffAccountsController.openEditDialog", e, "Opening employee edit dialog");
|
||||||
lblError.setText("Could not open user account editor.");
|
lblError.setText("Could not open employee account editor.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,11 +143,10 @@ public class StaffAccountsController {
|
|||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Comparator<UserResponse> byCreated = Comparator.comparing(
|
Comparator<EmployeeResponse> byCreated = Comparator.comparing(
|
||||||
UserResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder()));
|
EmployeeResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder()));
|
||||||
|
|
||||||
List<UserResponse> staff = UserApi.getInstance().listUsers(null).stream()
|
List<EmployeeResponse> staff = EmployeeApi.getInstance().listEmployees(null).stream()
|
||||||
.filter(u -> !"CUSTOMER".equalsIgnoreCase(u.getRole()))
|
|
||||||
.sorted(byCreated)
|
.sorted(byCreated)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
@@ -180,7 +155,7 @@ public class StaffAccountsController {
|
|||||||
tvStaff.setDisable(false);
|
tvStaff.setDisable(false);
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts");
|
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading employee accounts");
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
lblError.setText("Could not load staff accounts.");
|
lblError.setText("Could not load staff accounts.");
|
||||||
tvStaff.setDisable(false);
|
tvStaff.setDisable(false);
|
||||||
@@ -201,6 +176,7 @@ public class StaffAccountsController {
|
|||||||
|| safe(a.getEmail()).contains(q)
|
|| safe(a.getEmail()).contains(q)
|
||||||
|| safe(a.getPhone()).contains(q)
|
|| safe(a.getPhone()).contains(q)
|
||||||
|| safe(a.getRole()).contains(q)
|
|| safe(a.getRole()).contains(q)
|
||||||
|
|| safe(a.getStaffRole()).contains(q)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,164 +8,92 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ChoiceDialog;
|
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.DatePicker;
|
import javafx.scene.control.DatePicker;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
|
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
|
||||||
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
|
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
|
||||||
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.PetApi;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
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 java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class AdoptionDialogController {
|
public class AdoptionDialogController {
|
||||||
|
|
||||||
@FXML
|
@FXML private Button btnCancel;
|
||||||
private Button btnCancel;
|
@FXML private Button btnSave;
|
||||||
|
@FXML private ComboBox<String> cbAdoptionStatus;
|
||||||
@FXML
|
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||||
private Button btnSave;
|
@FXML private ComboBox<DropdownOption> cbEmployee;
|
||||||
|
@FXML private ComboBox<DropdownOption> cbPet;
|
||||||
@FXML
|
@FXML private ComboBox<DropdownOption> cbStore;
|
||||||
private ComboBox<String> cbAdoptionStatus;
|
@FXML private VBox vbStore;
|
||||||
|
@FXML private DatePicker dpAdoptionDate;
|
||||||
@FXML
|
@FXML private TextField txtAdoptionFee;
|
||||||
private ComboBox<DropdownOption> cbCustomer;
|
@FXML private Label lblAdoptionId;
|
||||||
|
@FXML private Label lblMode;
|
||||||
@FXML
|
|
||||||
private ComboBox<DropdownOption> cbEmployee;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private ComboBox<DropdownOption> cbPet;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private DatePicker dpAdoptionDate;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblAdoptionId;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblMode;
|
|
||||||
|
|
||||||
private String mode = null;
|
private String mode = null;
|
||||||
private Adoption selectedAdoption = null;
|
private Adoption selectedAdoption = null;
|
||||||
private String selectedPaymentMethod = null;
|
private boolean suppressStatusListener = false;
|
||||||
private boolean suppressPaymentDialog = false;
|
private Long pendingStoreId = null;
|
||||||
|
|
||||||
private ObservableList<String> statusList = FXCollections.observableArrayList(
|
private final ObservableList<String> statusList = FXCollections.observableArrayList(
|
||||||
"Pending", "Completed", "Missed", "Cancelled"
|
"Pending", "Completed", "Missed", "Cancelled"
|
||||||
);
|
);
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
|
|
||||||
cbAdoptionStatus.setItems(statusList);
|
cbAdoptionStatus.setItems(statusList);
|
||||||
cbAdoptionStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
cbAdoptionStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
if ("Completed".equals(newVal) && !"Completed".equals(oldVal) && !suppressPaymentDialog) {
|
if (!suppressStatusListener && newVal != null) {
|
||||||
ChoiceDialog<String> dialog = new ChoiceDialog<>("Cash", "Cash", "Credit Card", "Debit Card", "E-Transfer");
|
applyStatusFieldRules(newVal);
|
||||||
dialog.setTitle("Payment Method");
|
|
||||||
dialog.setHeaderText("Confirm payment received");
|
|
||||||
dialog.setContentText("Select payment method:");
|
|
||||||
dialog.showAndWait().ifPresentOrElse(
|
|
||||||
method -> selectedPaymentMethod = method,
|
|
||||||
() -> {
|
|
||||||
selectedPaymentMethod = null;
|
|
||||||
cbAdoptionStatus.setValue(oldVal);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else if (!"Completed".equals(newVal)) {
|
|
||||||
selectedPaymentMethod = null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cbEmployee.setPromptText("Select an employee");
|
cbEmployee.setPromptText("Select an employee");
|
||||||
|
txtAdoptionFee.setDisable(true);
|
||||||
|
|
||||||
new Thread(() -> {
|
LocalDate today = LocalDate.now();
|
||||||
try {
|
dpAdoptionDate.setDayCellFactory(picker -> new javafx.scene.control.DateCell() {
|
||||||
List<DropdownOption> pets = DropdownApi.getInstance().getAdoptionPets();
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
if (pets != null) {
|
|
||||||
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
|
|
||||||
ensureSelectedPetOption(petsObs);
|
|
||||||
cbPet.setItems(petsObs);
|
|
||||||
applySelectedPet();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
ActivityLogger.getInstance().logException(
|
|
||||||
"AdoptionDialogController.initialize",
|
|
||||||
e,
|
|
||||||
"Loading pets for combo box");
|
|
||||||
System.out.println("Error loading pets: " + e.getMessage());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
new Thread(() -> {
|
|
||||||
try {
|
|
||||||
List<DropdownOption> employees = DropdownApi.getInstance().getEmployees();
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
ObservableList<DropdownOption> employeesObs = FXCollections.observableArrayList(employees);
|
|
||||||
ensureSelectedEmployeeOption(employeesObs);
|
|
||||||
cbEmployee.setItems(employeesObs);
|
|
||||||
applySelectedEmployee();
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
ActivityLogger.getInstance().logException(
|
|
||||||
"AdoptionDialogController.initialize",
|
|
||||||
e,
|
|
||||||
"Loading employees for combo box");
|
|
||||||
cbEmployee.setDisable(true);
|
|
||||||
cbEmployee.setPromptText("Unable to load employees");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
cbEmployee.setCellFactory(param -> new ListCell<>() {
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(DropdownOption option, boolean empty) {
|
public void updateItem(LocalDate item, boolean empty) {
|
||||||
super.updateItem(option, empty);
|
super.updateItem(item, empty);
|
||||||
setText(empty || option == null ? null : option.getLabel());
|
setDisable(empty || item.isBefore(today));
|
||||||
}
|
|
||||||
});
|
|
||||||
cbEmployee.setButtonCell(new ListCell<>() {
|
|
||||||
@Override
|
|
||||||
protected void updateItem(DropdownOption option, boolean empty) {
|
|
||||||
super.updateItem(option, empty);
|
|
||||||
setText(empty || option == null ? null : option.getLabel());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new Thread(() -> {
|
setupDropdownCellFactory(cbEmployee);
|
||||||
try {
|
setupDropdownCellFactory(cbPet);
|
||||||
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
setupDropdownCellFactory(cbCustomer);
|
||||||
Platform.runLater(() -> {
|
setupDropdownCellFactory(cbStore);
|
||||||
if (customers != null) {
|
|
||||||
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
|
cbPet.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
cbCustomer.setItems(customersObs);
|
if (newVal != null) {
|
||||||
applySelectedCustomer();
|
loadPetPrice(newVal.getId());
|
||||||
}
|
} else {
|
||||||
});
|
txtAdoptionFee.setText("0");
|
||||||
} catch (Exception e) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
ActivityLogger.getInstance().logException(
|
|
||||||
"AdoptionDialogController.initialize",
|
|
||||||
e,
|
|
||||||
"Loading customers for combo box");
|
|
||||||
System.out.println("Error loading customers: " + e.getMessage());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}).start();
|
});
|
||||||
|
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
vbStore.setVisible(true);
|
||||||
|
vbStore.setManaged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDropdownsAsync();
|
||||||
|
|
||||||
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -182,32 +110,146 @@ public class AdoptionDialogController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupDropdownCellFactory(ComboBox<DropdownOption> cb) {
|
||||||
|
cb.setCellFactory(param -> new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb.setButtonCell(new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadDropdownsAsync() {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> pets = DropdownApi.getInstance().getAdoptionPets();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (pets != null) {
|
||||||
|
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
|
||||||
|
ensureSelectedPetOption(petsObs);
|
||||||
|
cbPet.setItems(petsObs);
|
||||||
|
applySelectedPet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.loadDropdownsAsync", e, "Loading pets"));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> employees = DropdownApi.getInstance().getEmployees();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ObservableList<DropdownOption> employeesObs = FXCollections.observableArrayList(employees);
|
||||||
|
ensureSelectedEmployeeOption(employeesObs);
|
||||||
|
cbEmployee.setItems(employeesObs);
|
||||||
|
applySelectedEmployee();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.loadDropdownsAsync", e, "Loading employees");
|
||||||
|
cbEmployee.setDisable(true);
|
||||||
|
cbEmployee.setPromptText("Unable to load employees");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (customers != null) {
|
||||||
|
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
|
||||||
|
cbCustomer.setItems(customersObs);
|
||||||
|
applySelectedCustomer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.loadDropdownsAsync", e, "Loading customers"));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (stores != null) {
|
||||||
|
cbStore.setItems(FXCollections.observableArrayList(stores));
|
||||||
|
if (pendingStoreId != null) {
|
||||||
|
for (DropdownOption store : cbStore.getItems()) {
|
||||||
|
if (pendingStoreId.equals(store.getId())) {
|
||||||
|
cbStore.setValue(store);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingStoreId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.loadDropdownsAsync", e, "Loading stores"));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyStatusFieldRules(String status) {
|
||||||
|
if ("Cancelled".equalsIgnoreCase(status) || "Completed".equalsIgnoreCase(status) || "Missed".equalsIgnoreCase(status)) {
|
||||||
|
cbEmployee.setDisable(true);
|
||||||
|
dpAdoptionDate.setDisable(true);
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
} else {
|
||||||
|
cbEmployee.setDisable(false);
|
||||||
|
dpAdoptionDate.setDisable(false);
|
||||||
|
if (UserSession.getInstance().isAdmin()) cbStore.setDisable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
String errorMsg = "";
|
String errorMsg = "";
|
||||||
|
|
||||||
if (cbPet.getSelectionModel().getSelectedItem() == null) {
|
if (cbPet.getSelectionModel().getSelectedItem() == null) errorMsg += "Pet is required.\n";
|
||||||
errorMsg += "Pet is required.\n";
|
if (cbCustomer.getSelectionModel().getSelectedItem() == null) errorMsg += "Customer is required.\n";
|
||||||
}
|
if (cbEmployee.getSelectionModel().getSelectedItem() == null) errorMsg += "Employee is required.\n";
|
||||||
|
if (dpAdoptionDate.getValue() == null) errorMsg += "Adoption Date is required.\n";
|
||||||
|
if (cbAdoptionStatus.getSelectionModel().getSelectedItem() == null) errorMsg += "Status is required.\n";
|
||||||
|
|
||||||
if (cbCustomer.getSelectionModel().getSelectedItem() == null) {
|
BigDecimal adoptionFee = BigDecimal.ZERO;
|
||||||
errorMsg += "Customer is required.\n";
|
String feeText = txtAdoptionFee.getText() == null ? "" : txtAdoptionFee.getText().trim();
|
||||||
}
|
if (!feeText.isEmpty()) {
|
||||||
|
try {
|
||||||
if (cbEmployee.getSelectionModel().getSelectedItem() == null) {
|
adoptionFee = new BigDecimal(feeText);
|
||||||
errorMsg += "Employee is required.\n";
|
} catch (NumberFormatException e) {
|
||||||
}
|
adoptionFee = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
if (dpAdoptionDate.getValue() == null) {
|
|
||||||
errorMsg += "Adoption Date is required.\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbAdoptionStatus.getSelectionModel().getSelectedItem() == null) {
|
|
||||||
errorMsg += "Status is required.\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorMsg.isEmpty()) {
|
if (errorMsg.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Long storeId = UserSession.getInstance().getStoreId();
|
Long storeId;
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
if (cbStore.getSelectionModel().getSelectedItem() == null) {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setHeaderText("Input Error");
|
||||||
|
alert.setContentText("Store is required.");
|
||||||
|
alert.showAndWait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
storeId = cbStore.getSelectionModel().getSelectedItem().getId();
|
||||||
|
} else {
|
||||||
|
storeId = UserSession.getInstance().getStoreId();
|
||||||
|
}
|
||||||
if (storeId == null || storeId <= 0) {
|
if (storeId == null || storeId <= 0) {
|
||||||
throw new IllegalStateException("Store is not set for this account");
|
throw new IllegalStateException("Store is not set for this account");
|
||||||
}
|
}
|
||||||
@@ -219,15 +261,13 @@ public class AdoptionDialogController {
|
|||||||
request.setSourceStoreId(storeId);
|
request.setSourceStoreId(storeId);
|
||||||
request.setAdoptionDate(dpAdoptionDate.getValue());
|
request.setAdoptionDate(dpAdoptionDate.getValue());
|
||||||
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
request.setAdoptionStatus(cbAdoptionStatus.getValue());
|
||||||
request.setPaymentMethod(selectedPaymentMethod);
|
request.setAdoptionFee(adoptionFee);
|
||||||
|
|
||||||
if (mode.equals("Add")) {
|
if (mode.equals("Add")) {
|
||||||
AdoptionApi.getInstance().createAdoption(request);
|
AdoptionApi.getInstance().createAdoption(request);
|
||||||
} else {
|
} else {
|
||||||
String[] parts = lblAdoptionId.getText().split(": ");
|
String[] parts = lblAdoptionId.getText().split(": ");
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) throw new IllegalStateException("Invalid adoption ID format");
|
||||||
throw new IllegalStateException("Invalid adoption ID format");
|
|
||||||
}
|
|
||||||
Long adoptionId = Long.parseLong(parts[1]);
|
Long adoptionId = Long.parseLong(parts[1]);
|
||||||
AdoptionApi.getInstance().updateAdoption(adoptionId, request);
|
AdoptionApi.getInstance().updateAdoption(adoptionId, request);
|
||||||
}
|
}
|
||||||
@@ -239,9 +279,7 @@ public class AdoptionDialogController {
|
|||||||
closeStage(mouseEvent);
|
closeStage(mouseEvent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionDialogController.buttonSaveClicked",
|
"AdoptionDialogController.buttonSaveClicked", e, mode + " adoption");
|
||||||
e,
|
|
||||||
mode + " adoption");
|
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
alert.setHeaderText("Database Operation Error");
|
alert.setHeaderText("Database Operation Error");
|
||||||
alert.setContentText(e.getMessage());
|
alert.setContentText(e.getMessage());
|
||||||
@@ -262,36 +300,37 @@ public class AdoptionDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void displayAdoptionDetails(Adoption adoption) {
|
public void displayAdoptionDetails(Adoption adoption) {
|
||||||
if (adoption != null) {
|
if (adoption == null) return;
|
||||||
selectedAdoption = adoption;
|
selectedAdoption = adoption;
|
||||||
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
|
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
|
||||||
ensureSelectedEmployeeOption(cbEmployee.getItems());
|
pendingStoreId = adoption.getStoreId();
|
||||||
applySelectedPet();
|
ensureSelectedEmployeeOption(cbEmployee.getItems());
|
||||||
applySelectedCustomer();
|
applySelectedPet();
|
||||||
applySelectedEmployee();
|
applySelectedCustomer();
|
||||||
|
applySelectedEmployee();
|
||||||
|
|
||||||
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
||||||
try {
|
try {
|
||||||
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionDialogController.displayAdoptionDetails",
|
"AdoptionDialogController.displayAdoptionDetails", e, "Parsing adoption date");
|
||||||
e,
|
|
||||||
"Parsing adoption date");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suppressPaymentDialog = true;
|
|
||||||
cbAdoptionStatus.setItems(statusList);
|
|
||||||
for (String status : cbAdoptionStatus.getItems()) {
|
|
||||||
if (status.equals(adoption.getAdoptionStatus())) {
|
|
||||||
cbAdoptionStatus.getSelectionModel().select(status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suppressPaymentDialog = false;
|
|
||||||
applyEditModeLock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txtAdoptionFee.setText(adoption.getAdoptionFee() > 0
|
||||||
|
? String.format("%.2f", adoption.getAdoptionFee()) : "0.00");
|
||||||
|
|
||||||
|
suppressStatusListener = true;
|
||||||
|
cbAdoptionStatus.setItems(statusList);
|
||||||
|
for (String status : cbAdoptionStatus.getItems()) {
|
||||||
|
if (status.equals(adoption.getAdoptionStatus())) {
|
||||||
|
cbAdoptionStatus.getSelectionModel().select(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suppressStatusListener = false;
|
||||||
|
applyEditModeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyEditModeLock() {
|
private void applyEditModeLock() {
|
||||||
@@ -304,6 +343,7 @@ public class AdoptionDialogController {
|
|||||||
dpAdoptionDate.setDisable(true);
|
dpAdoptionDate.setDisable(true);
|
||||||
cbAdoptionStatus.setDisable(true);
|
cbAdoptionStatus.setDisable(true);
|
||||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
||||||
|
cbStore.setDisable(true);
|
||||||
btnSave.setDisable(true);
|
btnSave.setDisable(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -311,23 +351,33 @@ public class AdoptionDialogController {
|
|||||||
LocalDate adoptionDate = dpAdoptionDate.getValue();
|
LocalDate adoptionDate = dpAdoptionDate.getValue();
|
||||||
boolean isPast = adoptionDate != null && adoptionDate.isBefore(LocalDate.now());
|
boolean isPast = adoptionDate != null && adoptionDate.isBefore(LocalDate.now());
|
||||||
|
|
||||||
cbPet.setDisable(true);
|
|
||||||
cbCustomer.setDisable(true);
|
|
||||||
dpAdoptionDate.setDisable(false);
|
|
||||||
cbEmployee.setDisable(false);
|
|
||||||
cbAdoptionStatus.setDisable(false);
|
|
||||||
|
|
||||||
suppressPaymentDialog = true;
|
|
||||||
if (isPast) {
|
if (isPast) {
|
||||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
cbPet.setDisable(true);
|
||||||
|
cbCustomer.setDisable(true);
|
||||||
|
cbEmployee.setDisable(true);
|
||||||
dpAdoptionDate.setDisable(true);
|
dpAdoptionDate.setDisable(true);
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
cbAdoptionStatus.setDisable(false);
|
||||||
|
suppressStatusListener = true;
|
||||||
|
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
||||||
|
if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
|
||||||
|
cbAdoptionStatus.getSelectionModel().selectFirst();
|
||||||
|
}
|
||||||
|
suppressStatusListener = false;
|
||||||
} else {
|
} else {
|
||||||
|
cbPet.setDisable(true);
|
||||||
|
cbCustomer.setDisable(true);
|
||||||
|
dpAdoptionDate.setDisable(false);
|
||||||
|
cbEmployee.setDisable(false);
|
||||||
|
cbAdoptionStatus.setDisable(false);
|
||||||
|
if (UserSession.getInstance().isAdmin()) cbStore.setDisable(false);
|
||||||
|
suppressStatusListener = true;
|
||||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending", "Cancelled"));
|
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending", "Cancelled"));
|
||||||
|
if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
|
||||||
|
cbAdoptionStatus.getSelectionModel().selectFirst();
|
||||||
|
}
|
||||||
|
suppressStatusListener = false;
|
||||||
}
|
}
|
||||||
if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
|
|
||||||
cbAdoptionStatus.getSelectionModel().selectFirst();
|
|
||||||
}
|
|
||||||
suppressPaymentDialog = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMode(String mode) {
|
public void setMode(String mode) {
|
||||||
@@ -335,60 +385,64 @@ public class AdoptionDialogController {
|
|||||||
lblMode.setText(mode + " Adoption");
|
lblMode.setText(mode + " Adoption");
|
||||||
lblAdoptionId.setVisible(mode.equals("Edit"));
|
lblAdoptionId.setVisible(mode.equals("Edit"));
|
||||||
if (mode.equals("Add")) {
|
if (mode.equals("Add")) {
|
||||||
suppressPaymentDialog = true;
|
suppressStatusListener = true;
|
||||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending"));
|
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending"));
|
||||||
cbAdoptionStatus.setValue("Pending");
|
cbAdoptionStatus.setValue("Pending");
|
||||||
cbAdoptionStatus.setDisable(true);
|
cbAdoptionStatus.setDisable(true);
|
||||||
suppressPaymentDialog = false;
|
suppressStatusListener = false;
|
||||||
|
txtAdoptionFee.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySelectedPet() {
|
private void applySelectedPet() {
|
||||||
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0) {
|
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
DropdownOption selected = findOptionById(cbPet.getItems(), (long) selectedAdoption.getPetId());
|
DropdownOption selected = findOptionById(cbPet.getItems(), (long) selectedAdoption.getPetId());
|
||||||
if (selected != null && !Objects.equals(cbPet.getValue(), selected)) {
|
if (selected != null && !Objects.equals(cbPet.getValue(), selected)) cbPet.setValue(selected);
|
||||||
cbPet.setValue(selected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySelectedCustomer() {
|
private void applySelectedCustomer() {
|
||||||
if (selectedAdoption == null || selectedAdoption.getCustomerId() <= 0) {
|
if (selectedAdoption == null || selectedAdoption.getCustomerId() <= 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
DropdownOption selected = findOptionById(cbCustomer.getItems(), (long) selectedAdoption.getCustomerId());
|
DropdownOption selected = findOptionById(cbCustomer.getItems(), (long) selectedAdoption.getCustomerId());
|
||||||
if (selected != null && !Objects.equals(cbCustomer.getValue(), selected)) {
|
if (selected != null && !Objects.equals(cbCustomer.getValue(), selected)) cbCustomer.setValue(selected);
|
||||||
cbCustomer.setValue(selected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySelectedEmployee() {
|
private void applySelectedEmployee() {
|
||||||
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0) {
|
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
DropdownOption selected = findOptionById(cbEmployee.getItems(), (long) selectedAdoption.getEmployeeId());
|
DropdownOption selected = findOptionById(cbEmployee.getItems(), (long) selectedAdoption.getEmployeeId());
|
||||||
if (selected != null && !Objects.equals(cbEmployee.getValue(), selected)) {
|
if (selected != null && !Objects.equals(cbEmployee.getValue(), selected)) cbEmployee.setValue(selected);
|
||||||
cbEmployee.setValue(selected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
|
private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
|
||||||
if (id == null || options == null) {
|
if (id == null || options == null) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (DropdownOption option : options) {
|
for (DropdownOption option : options) {
|
||||||
if (option.getId() != null && option.getId().equals(id)) {
|
if (option.getId() != null && option.getId().equals(id)) return option;
|
||||||
return option;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadPetPrice(Long petId) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
var pet = PetApi.getInstance().getPetById(petId);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (pet != null && pet.getPetPrice() != null) {
|
||||||
|
txtAdoptionFee.setText(String.format("%.2f", pet.getPetPrice()));
|
||||||
|
} else {
|
||||||
|
txtAdoptionFee.setText("0.00");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
txtAdoptionFee.setText("0.00");
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.loadPetPrice", e, "Loading pet price");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
private void ensureSelectedEmployeeOption(ObservableList<DropdownOption> options) {
|
private void ensureSelectedEmployeeOption(ObservableList<DropdownOption> options) {
|
||||||
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0 || options == null) {
|
if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0 || options == null) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
DropdownOption existing = findOptionById(options, (long) selectedAdoption.getEmployeeId());
|
DropdownOption existing = findOptionById(options, (long) selectedAdoption.getEmployeeId());
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
DropdownOption option = new DropdownOption();
|
DropdownOption option = new DropdownOption();
|
||||||
@@ -399,9 +453,7 @@ public class AdoptionDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ensureSelectedPetOption(ObservableList<DropdownOption> options) {
|
private void ensureSelectedPetOption(ObservableList<DropdownOption> options) {
|
||||||
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0 || options == null) {
|
if (selectedAdoption == null || selectedAdoption.getPetId() <= 0 || options == null) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
DropdownOption existing = findOptionById(options, (long) selectedAdoption.getPetId());
|
DropdownOption existing = findOptionById(options, (long) selectedAdoption.getPetId());
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
DropdownOption option = new DropdownOption();
|
DropdownOption option = new DropdownOption();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
|
||||||
@@ -18,7 +19,6 @@ import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
|||||||
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 java.time.DayOfWeek;
|
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -33,6 +33,8 @@ public class AppointmentDialogController {
|
|||||||
@FXML private ComboBox<DropdownOption> cbCustomer;
|
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||||
@FXML private ComboBox<DropdownOption> cbPet;
|
@FXML private ComboBox<DropdownOption> cbPet;
|
||||||
@FXML private ComboBox<DropdownOption> cbEmployee;
|
@FXML private ComboBox<DropdownOption> cbEmployee;
|
||||||
|
@FXML private ComboBox<DropdownOption> cbStore;
|
||||||
|
@FXML private VBox vbStore;
|
||||||
|
|
||||||
@FXML private ComboBox<Integer> cbHour;
|
@FXML private ComboBox<Integer> cbHour;
|
||||||
@FXML private ComboBox<Integer> cbMinute;
|
@FXML private ComboBox<Integer> cbMinute;
|
||||||
@@ -46,6 +48,7 @@ public class AppointmentDialogController {
|
|||||||
private String mode = null;
|
private String mode = null;
|
||||||
private AppointmentDTO selectedAppointment = null;
|
private AppointmentDTO selectedAppointment = null;
|
||||||
private Long pendingPetSelectionId = null;
|
private Long pendingPetSelectionId = null;
|
||||||
|
private Long pendingStoreId = null;
|
||||||
private boolean isOriginallyCancel = false;
|
private boolean isOriginallyCancel = false;
|
||||||
private boolean isOriginallyCompletedOrMissed = false;
|
private boolean isOriginallyCompletedOrMissed = false;
|
||||||
|
|
||||||
@@ -63,18 +66,39 @@ public class AppointmentDialogController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Booked", "Completed", "Missed", "Cancelled"));
|
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Booked", "Completed", "Missed", "Cancelled"));
|
||||||
|
cbAppointmentStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
|
if (newVal == null) return;
|
||||||
|
boolean lockAll = "Cancelled".equalsIgnoreCase(newVal)
|
||||||
|
|| "Completed".equalsIgnoreCase(newVal)
|
||||||
|
|| "Missed".equalsIgnoreCase(newVal);
|
||||||
|
if (lockAll) {
|
||||||
|
cbEmployee.setDisable(true);
|
||||||
|
cbHour.setDisable(true);
|
||||||
|
cbMinute.setDisable(true);
|
||||||
|
dpAppointmentDate.setDisable(true);
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
} else {
|
||||||
|
if (!isOriginallyCancel && !isOriginallyCompletedOrMissed) {
|
||||||
|
cbEmployee.setDisable(false);
|
||||||
|
cbHour.setDisable(false);
|
||||||
|
cbMinute.setDisable(false);
|
||||||
|
dpAppointmentDate.setDisable(false);
|
||||||
|
if (UserSession.getInstance().isAdmin()) cbStore.setDisable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
cbPet.setDisable(true);
|
cbPet.setDisable(true);
|
||||||
cbEmployee.setPromptText("Select an employee");
|
cbEmployee.setPromptText("Select an employee");
|
||||||
cbPet.setPromptText("Select a customer first");
|
cbPet.setPromptText("Select a customer first");
|
||||||
cbCustomer.setPromptText("Select a customer");
|
cbCustomer.setPromptText("Select a customer");
|
||||||
cbService.setPromptText("Select a service");
|
cbService.setPromptText("Select a service");
|
||||||
LocalDate minDate = minAppointmentDate();
|
LocalDate today = LocalDate.now();
|
||||||
dpAppointmentDate.setValue(minDate);
|
dpAppointmentDate.setValue(today);
|
||||||
dpAppointmentDate.setDayCellFactory(picker -> new javafx.scene.control.DateCell() {
|
dpAppointmentDate.setDayCellFactory(picker -> new javafx.scene.control.DateCell() {
|
||||||
@Override
|
@Override
|
||||||
public void updateItem(LocalDate item, boolean empty) {
|
public void updateItem(LocalDate item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
setDisable(empty || item.isBefore(minDate));
|
setDisable(empty || item.isBefore(today));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cbAppointmentStatus.setValue("Booked");
|
cbAppointmentStatus.setValue("Booked");
|
||||||
@@ -179,7 +203,7 @@ public class AppointmentDialogController {
|
|||||||
Long customerId = newValue != null ? newValue.getId() : null;
|
Long customerId = newValue != null ? newValue.getId() : null;
|
||||||
cbPet.setValue(null);
|
cbPet.setValue(null);
|
||||||
cbPet.setItems(FXCollections.observableArrayList());
|
cbPet.setItems(FXCollections.observableArrayList());
|
||||||
cbPet.setDisable(customerId == null);
|
cbPet.setDisable(customerId == null || isOriginallyCancel || isOriginallyCompletedOrMissed);
|
||||||
if (customerId != null) {
|
if (customerId != null) {
|
||||||
cbPet.setPromptText("Loading customer pets...");
|
cbPet.setPromptText("Loading customer pets...");
|
||||||
loadCustomerPets(customerId);
|
loadCustomerPets(customerId);
|
||||||
@@ -189,12 +213,36 @@ public class AppointmentDialogController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cbStore.setCellFactory(param -> new ListCell<>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(DropdownOption option, boolean empty) {
|
||||||
|
super.updateItem(option, empty);
|
||||||
|
setText(empty || option == null ? null : option.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cbStore.setButtonCell(new ListCell<>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(DropdownOption option, boolean empty) {
|
||||||
|
super.updateItem(option, empty);
|
||||||
|
setText(empty || option == null ? null : option.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
vbStore.setVisible(true);
|
||||||
|
vbStore.setManaged(true);
|
||||||
|
}
|
||||||
|
|
||||||
btnSave.setOnMouseClicked(this::buttonSaveClicked);
|
btnSave.setOnMouseClicked(this::buttonSaveClicked);
|
||||||
btnCancel.setOnMouseClicked(this::closeStage);
|
btnCancel.setOnMouseClicked(this::closeStage);
|
||||||
|
|
||||||
loadServices();
|
loadServices();
|
||||||
loadAppointmentCustomers();
|
loadAppointmentCustomers();
|
||||||
loadEmployees();
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
loadStores();
|
||||||
|
} else {
|
||||||
|
loadEmployees();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void displayAppointmentDetails(AppointmentDTO appt) {
|
public void displayAppointmentDetails(AppointmentDTO appt) {
|
||||||
@@ -202,6 +250,7 @@ public class AppointmentDialogController {
|
|||||||
selectedAppointment = appt;
|
selectedAppointment = appt;
|
||||||
lblAppointmentId.setText("ID: " + appt.getAppointmentId());
|
lblAppointmentId.setText("ID: " + appt.getAppointmentId());
|
||||||
pendingPetSelectionId = appt.getPetId() > 0 ? (long) appt.getPetId() : null;
|
pendingPetSelectionId = appt.getPetId() > 0 ? (long) appt.getPetId() : null;
|
||||||
|
pendingStoreId = appt.getStoreId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dpAppointmentDate.setValue(
|
dpAppointmentDate.setValue(
|
||||||
@@ -248,6 +297,7 @@ public class AppointmentDialogController {
|
|||||||
dpAppointmentDate.setDisable(true);
|
dpAppointmentDate.setDisable(true);
|
||||||
cbAppointmentStatus.setDisable(true);
|
cbAppointmentStatus.setDisable(true);
|
||||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
||||||
|
cbStore.setDisable(true);
|
||||||
btnSave.setDisable(true);
|
btnSave.setDisable(true);
|
||||||
} else if (isOriginallyCompletedOrMissed) {
|
} else if (isOriginallyCompletedOrMissed) {
|
||||||
cbService.setDisable(true);
|
cbService.setDisable(true);
|
||||||
@@ -257,6 +307,7 @@ public class AppointmentDialogController {
|
|||||||
cbHour.setDisable(true);
|
cbHour.setDisable(true);
|
||||||
cbMinute.setDisable(true);
|
cbMinute.setDisable(true);
|
||||||
dpAppointmentDate.setDisable(true);
|
dpAppointmentDate.setDisable(true);
|
||||||
|
cbStore.setDisable(true);
|
||||||
cbAppointmentStatus.setDisable(false);
|
cbAppointmentStatus.setDisable(false);
|
||||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
||||||
} else {
|
} else {
|
||||||
@@ -288,7 +339,16 @@ public class AppointmentDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LocalTime appointmentTime = LocalTime.of(cbHour.getValue(), cbMinute.getValue());
|
LocalTime appointmentTime = LocalTime.of(cbHour.getValue(), cbMinute.getValue());
|
||||||
Long storeId = UserSession.getInstance().getStoreId();
|
Long storeId;
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
if (cbStore.getSelectionModel().getSelectedItem() == null) {
|
||||||
|
showError("Store is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
storeId = cbStore.getSelectionModel().getSelectedItem().getId();
|
||||||
|
} else {
|
||||||
|
storeId = UserSession.getInstance().getStoreId();
|
||||||
|
}
|
||||||
if (storeId == null || storeId <= 0) {
|
if (storeId == null || storeId <= 0) {
|
||||||
showError("Store is not set for this account");
|
showError("Store is not set for this account");
|
||||||
return;
|
return;
|
||||||
@@ -408,7 +468,7 @@ public class AppointmentDialogController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cbPet.setItems(petOptions);
|
cbPet.setItems(petOptions);
|
||||||
cbPet.setDisable(petOptions.isEmpty());
|
cbPet.setDisable(petOptions.isEmpty() || isOriginallyCancel || isOriginallyCompletedOrMissed);
|
||||||
cbPet.setPromptText(petOptions.isEmpty() ? "No pets for selected customer" : "Select a pet");
|
cbPet.setPromptText(petOptions.isEmpty() ? "No pets for selected customer" : "Select a pet");
|
||||||
if (pendingPetSelectionId != null) {
|
if (pendingPetSelectionId != null) {
|
||||||
for (DropdownOption pet : cbPet.getItems()) {
|
for (DropdownOption pet : cbPet.getItems()) {
|
||||||
@@ -462,7 +522,7 @@ public class AppointmentDialogController {
|
|||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
cbCustomer.setItems(FXCollections.observableArrayList(customers));
|
cbCustomer.setItems(FXCollections.observableArrayList(customers));
|
||||||
boolean hasCustomers = customers != null && !customers.isEmpty();
|
boolean hasCustomers = customers != null && !customers.isEmpty();
|
||||||
cbCustomer.setDisable(!hasCustomers);
|
cbCustomer.setDisable(!hasCustomers || isOriginallyCancel || isOriginallyCompletedOrMissed);
|
||||||
cbPet.setDisable(true);
|
cbPet.setDisable(true);
|
||||||
cbPet.setItems(FXCollections.observableArrayList());
|
cbPet.setItems(FXCollections.observableArrayList());
|
||||||
cbCustomer.setPromptText(hasCustomers ? "Select a customer" : "No customers with pets yet");
|
cbCustomer.setPromptText(hasCustomers ? "Select a customer" : "No customers with pets yet");
|
||||||
@@ -484,17 +544,61 @@ public class AppointmentDialogController {
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate minAppointmentDate() {
|
|
||||||
LocalDate date = LocalDate.now();
|
private void loadStores() {
|
||||||
int businessDaysAdded = 0;
|
new Thread(() -> {
|
||||||
while (businessDaysAdded < 2) {
|
try {
|
||||||
date = date.plusDays(1);
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
DayOfWeek dow = date.getDayOfWeek();
|
Platform.runLater(() -> {
|
||||||
if (dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY) {
|
if (stores != null) {
|
||||||
businessDaysAdded++;
|
cbStore.setItems(FXCollections.observableArrayList(stores));
|
||||||
|
cbStore.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||||
|
Long sid = newVal != null ? newVal.getId() : null;
|
||||||
|
cbEmployee.setValue(null);
|
||||||
|
cbEmployee.setItems(FXCollections.observableArrayList());
|
||||||
|
if (sid != null) {
|
||||||
|
loadEmployeesForStore(sid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (pendingStoreId != null) {
|
||||||
|
for (DropdownOption store : cbStore.getItems()) {
|
||||||
|
if (pendingStoreId.equals(store.getId())) {
|
||||||
|
cbStore.setValue(store);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingStoreId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> ActivityLogger.getInstance().logException(
|
||||||
|
"AppointmentDialogController.loadStores",
|
||||||
|
e,
|
||||||
|
"Loading stores for appointment dialog"));
|
||||||
}
|
}
|
||||||
}
|
}).start();
|
||||||
return date;
|
}
|
||||||
|
|
||||||
|
private void loadEmployeesForStore(Long storeId) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> employees = DropdownApi.getInstance().getStoreEmployees(storeId);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbEmployee.setItems(FXCollections.observableArrayList(employees));
|
||||||
|
applySelectedEmployee();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AppointmentDialogController.loadEmployeesForStore",
|
||||||
|
e,
|
||||||
|
"Loading employees for store");
|
||||||
|
cbEmployee.setDisable(true);
|
||||||
|
cbEmployee.setPromptText("Unable to load employees");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadEmployees() {
|
private void loadEmployees() {
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.PasswordField;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.example.petshopdesktop.Validator;
|
||||||
|
import org.example.petshopdesktop.api.dto.user.UserRequest;
|
||||||
|
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.CustomerApi;
|
||||||
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
import org.example.petshopdesktop.util.TextFieldFormatSupport;
|
||||||
|
|
||||||
|
public class CustomerEditDialogController {
|
||||||
|
|
||||||
|
@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 ComboBox<String> cbActive;
|
||||||
|
@FXML private TextField txtLoyaltyPoints;
|
||||||
|
@FXML private Label lblError;
|
||||||
|
@FXML private Button btnSave;
|
||||||
|
|
||||||
|
private UserResponse customer;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void initialize() {
|
||||||
|
TextFieldFormatSupport.applyPhoneNumberFormat(txtPhone);
|
||||||
|
cbActive.setItems(FXCollections.observableArrayList("Active", "Inactive"));
|
||||||
|
|
||||||
|
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||||
|
txtLoyaltyPoints.setDisable(!isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomer(UserResponse user) {
|
||||||
|
this.customer = user;
|
||||||
|
String fullName = user.getFullName() == null ? "" : user.getFullName();
|
||||||
|
String[] names = splitFullName(fullName);
|
||||||
|
txtFirstName.setText(names[0]);
|
||||||
|
txtLastName.setText(names[1]);
|
||||||
|
txtEmail.setText(user.getEmail());
|
||||||
|
txtPhone.setText(user.getPhone());
|
||||||
|
txtUsername.setText(user.getUsername());
|
||||||
|
cbActive.setValue(Boolean.TRUE.equals(user.getActive()) ? "Active" : "Inactive");
|
||||||
|
int pts = user.getLoyaltyPoints() != null ? user.getLoyaltyPoints() : 0;
|
||||||
|
txtLoyaltyPoints.setText(String.valueOf(pts));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] splitFullName(String fullName) {
|
||||||
|
if (fullName == null || fullName.trim().isEmpty()) return new String[]{"", ""};
|
||||||
|
String[] parts = fullName.trim().split("\\s+", 2);
|
||||||
|
return new String[]{parts.length > 0 ? parts[0] : "", parts.length > 1 ? parts[1] : ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void btnSaveClicked(ActionEvent event) {
|
||||||
|
lblError.setText("");
|
||||||
|
if (customer == null) {
|
||||||
|
lblError.setText("No customer selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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().trim();
|
||||||
|
String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText().trim();
|
||||||
|
String loyaltyPointsText = value(txtLoyaltyPoints);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
String phoneError = Validator.isValidPhoneNumber(phone, "Phone");
|
||||||
|
if (!phoneError.isEmpty()) {
|
||||||
|
lblError.setText(phoneError.trim());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (username.isBlank()) {
|
||||||
|
lblError.setText("Username is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!password.isEmpty() && password.length() < 6) {
|
||||||
|
lblError.setText("Password must be at least 6 characters.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!password.equals(confirm)) {
|
||||||
|
lblError.setText("Passwords do not match.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer loyaltyPoints = null;
|
||||||
|
if (UserSession.getInstance().isAdmin()) {
|
||||||
|
if (loyaltyPointsText.isBlank()) {
|
||||||
|
lblError.setText("Loyalty points is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
loyaltyPoints = Integer.parseInt(loyaltyPointsText);
|
||||||
|
if (loyaltyPoints < 0) {
|
||||||
|
lblError.setText("Loyalty points cannot be negative.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
lblError.setText("Loyalty points must be a valid integer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btnSave.setDisable(true);
|
||||||
|
|
||||||
|
boolean active = "Active".equals(cbActive.getValue());
|
||||||
|
Integer finalLoyaltyPoints = loyaltyPoints;
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
UserRequest request = new UserRequest();
|
||||||
|
request.setUsername(username);
|
||||||
|
request.setPassword(password.isEmpty() ? null : password);
|
||||||
|
request.setFullName(firstName + " " + lastName);
|
||||||
|
request.setEmail(email);
|
||||||
|
request.setPhone(phone);
|
||||||
|
request.setRole(customer.getRole());
|
||||||
|
request.setActive(active);
|
||||||
|
if (finalLoyaltyPoints != null) request.setLoyaltyPoints(finalLoyaltyPoints);
|
||||||
|
|
||||||
|
CustomerApi.getInstance().updateCustomer(customer.getId(), request);
|
||||||
|
|
||||||
|
Platform.runLater(this::close);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException("CustomerEditDialogController.btnSaveClicked", e, "Updating customer");
|
||||||
|
String msg = e.getMessage() == null ? "Could not update customer." : e.getMessage();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
lblError.setText(msg);
|
||||||
|
btnSave.setDisable(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void btnCancelClicked(ActionEvent event) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close() {
|
||||||
|
Stage stage = (Stage) btnSave.getScene().getWindow();
|
||||||
|
stage.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String value(TextField tf) {
|
||||||
|
return tf.getText() == null ? "" : tf.getText().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
@@ -9,66 +10,65 @@ import javafx.scene.control.Alert;
|
|||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import org.example.petshopdesktop.models.Inventory;
|
import org.example.petshopdesktop.models.Inventory;
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.api.dto.inventory.InventoryRequest;
|
import org.example.petshopdesktop.api.dto.inventory.InventoryRequest;
|
||||||
import org.example.petshopdesktop.api.dto.inventory.InventoryResponse;
|
|
||||||
import org.example.petshopdesktop.api.dto.product.ProductResponse;
|
import org.example.petshopdesktop.api.dto.product.ProductResponse;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
import org.example.petshopdesktop.api.endpoints.InventoryApi;
|
import org.example.petshopdesktop.api.endpoints.InventoryApi;
|
||||||
import org.example.petshopdesktop.api.endpoints.ProductApi;
|
import org.example.petshopdesktop.api.endpoints.ProductApi;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
import org.example.petshopdesktop.models.Product;
|
import org.example.petshopdesktop.models.Product;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class InventoryDialogController {
|
public class InventoryDialogController {
|
||||||
|
|
||||||
//FXML elements
|
@FXML private Button btnCancel;
|
||||||
@FXML
|
@FXML private Button btnSave;
|
||||||
private Button btnCancel;
|
@FXML private ComboBox<Product> cbProduct;
|
||||||
|
@FXML private ComboBox<DropdownOption> cbStore;
|
||||||
|
@FXML private VBox vbStoreField;
|
||||||
|
@FXML private Label lblInventoryId;
|
||||||
|
@FXML private Label lblMode;
|
||||||
|
@FXML private TextField txtQuantity;
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button btnSave;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private ComboBox<Product> cbProduct;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblInventoryId;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblMode;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private TextField txtQuantity;
|
|
||||||
|
|
||||||
//Determines if the mode is add or edit
|
|
||||||
private String mode = null;
|
private String mode = null;
|
||||||
|
private Long pendingStoreId = null;
|
||||||
|
|
||||||
//Loads upon .FXML boot
|
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
cbProduct.setConverter(new StringConverter<Product>() {
|
cbProduct.setConverter(new StringConverter<Product>() {
|
||||||
|
|
||||||
//Displays product in combobox (prodID + name)
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(Product product) {
|
public String toString(Product product) {
|
||||||
return product == null ? "" : product.getProdId() + ": " + product.getProdName();
|
return product == null ? "" : product.getProdId() + ": " + product.getProdName();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Not needed
|
|
||||||
@Override
|
@Override
|
||||||
public Product fromString(String string) { return null; }
|
public Product fromString(String string) { return null; }
|
||||||
});
|
});
|
||||||
|
|
||||||
//Load product list from API into combobox
|
cbStore.setCellFactory(param -> new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cbStore.setButtonCell(new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
|
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
|
||||||
if (productResponses != null) {
|
if (productResponses != null) {
|
||||||
@@ -89,10 +89,16 @@ public class InventoryDialogController {
|
|||||||
"InventoryDialogController.initialize",
|
"InventoryDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading products for combo box");
|
"Loading products for combo box");
|
||||||
System.out.println("Error loading products: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save button handler
|
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||||
|
if (isAdmin) {
|
||||||
|
loadStores();
|
||||||
|
} else {
|
||||||
|
vbStoreField.setManaged(false);
|
||||||
|
vbStoreField.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent mouseEvent) {
|
public void handle(MouseEvent mouseEvent) {
|
||||||
@@ -100,7 +106,6 @@ public class InventoryDialogController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Cancel button handler
|
|
||||||
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent mouseEvent) {
|
public void handle(MouseEvent mouseEvent) {
|
||||||
@@ -109,29 +114,66 @@ public class InventoryDialogController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handles save button click event
|
private void loadStores() {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbStore.setItems(FXCollections.observableArrayList(stores));
|
||||||
|
applyPendingStore();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException("InventoryDialogController.loadStores", e, "Loading stores");
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
cbStore.setPromptText("Unable to load stores");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyPendingStore() {
|
||||||
|
if (pendingStoreId == null) return;
|
||||||
|
for (DropdownOption opt : cbStore.getItems()) {
|
||||||
|
if (opt.getId() != null && opt.getId().equals(pendingStoreId)) {
|
||||||
|
cbStore.setValue(opt);
|
||||||
|
pendingStoreId = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
int numRow = 0;
|
|
||||||
String errorMsg = "";
|
String errorMsg = "";
|
||||||
|
|
||||||
if (cbProduct.getSelectionModel().getSelectedItem() == null) {
|
if (cbProduct.getSelectionModel().getSelectedItem() == null) {
|
||||||
errorMsg += "Product is required.\n";
|
errorMsg += "Product is required.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Validate inputs
|
|
||||||
errorMsg += Validator.isPresent(txtQuantity.getText(), "Quantity");
|
errorMsg += Validator.isPresent(txtQuantity.getText(), "Quantity");
|
||||||
errorMsg += Validator.isLessThanVarChars(txtQuantity.getText(), "Quantity", 11);
|
errorMsg += Validator.isLessThanVarChars(txtQuantity.getText(), "Quantity", 11);
|
||||||
errorMsg += Validator.isPositiveInteger(txtQuantity.getText(), "Quantity");
|
errorMsg += Validator.isPositiveInteger(txtQuantity.getText(), "Quantity");
|
||||||
|
|
||||||
//Operation only occurs if there are no errors
|
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||||
|
Long storeId;
|
||||||
|
if (isAdmin) {
|
||||||
|
if (cbStore.getValue() == null) {
|
||||||
|
errorMsg += "Store is required.\n";
|
||||||
|
storeId = null;
|
||||||
|
} else {
|
||||||
|
storeId = cbStore.getValue().getId();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
storeId = UserSession.getInstance().getStoreId();
|
||||||
|
if (storeId == null || storeId <= 0) {
|
||||||
|
errorMsg += "Store is not set for this account.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (errorMsg.isEmpty()) {
|
if (errorMsg.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
InventoryRequest request = new InventoryRequest();
|
InventoryRequest request = new InventoryRequest();
|
||||||
Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
|
Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
|
||||||
Long storeId = UserSession.getInstance().getStoreId();
|
|
||||||
if (storeId == null || storeId <= 0) {
|
|
||||||
throw new IllegalStateException("Store is not set for this account");
|
|
||||||
}
|
|
||||||
request.setProdId((long) selectedProduct.getProdId());
|
request.setProdId((long) selectedProduct.getProdId());
|
||||||
int quantity;
|
int quantity;
|
||||||
try {
|
try {
|
||||||
@@ -168,10 +210,7 @@ public class InventoryDialogController {
|
|||||||
alert.setContentText(e.getMessage());
|
alert.setContentText(e.getMessage());
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
//Displays validation errors
|
|
||||||
else {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
alert.setHeaderText("Input Error");
|
alert.setHeaderText("Input Error");
|
||||||
alert.setContentText(errorMsg);
|
alert.setContentText(errorMsg);
|
||||||
@@ -179,22 +218,16 @@ public class InventoryDialogController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Close dialog view
|
|
||||||
private void closeStage(MouseEvent mouseEvent) {
|
private void closeStage(MouseEvent mouseEvent) {
|
||||||
Node node = (Node) mouseEvent.getSource();
|
Node node = (Node) mouseEvent.getSource();
|
||||||
Stage stage = (Stage) node.getScene().getWindow();
|
Stage stage = (Stage) node.getScene().getWindow();
|
||||||
stage.close();
|
stage.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Editing
|
|
||||||
//Displays fields with existing inventory data
|
|
||||||
public void displayInventoryDetails(Inventory inventory) {
|
public void displayInventoryDetails(Inventory inventory) {
|
||||||
if (inventory != null) {
|
if (inventory != null) {
|
||||||
|
|
||||||
//Displays inventory ID
|
|
||||||
lblInventoryId.setText("ID: " + inventory.getInventoryId());
|
lblInventoryId.setText("ID: " + inventory.getInventoryId());
|
||||||
|
|
||||||
//Selecting matching product in combobox
|
|
||||||
for (Product product : cbProduct.getItems()) {
|
for (Product product : cbProduct.getItems()) {
|
||||||
if (product.getProdId() == inventory.getProdId()) {
|
if (product.getProdId() == inventory.getProdId()) {
|
||||||
cbProduct.getSelectionModel().select(product);
|
cbProduct.getSelectionModel().select(product);
|
||||||
@@ -203,10 +236,15 @@ public class InventoryDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
txtQuantity.setText(String.valueOf(inventory.getQuantity()));
|
txtQuantity.setText(String.valueOf(inventory.getQuantity()));
|
||||||
|
|
||||||
|
boolean isAdmin = UserSession.getInstance().isAdmin();
|
||||||
|
if (isAdmin && inventory.getStoreId() > 0) {
|
||||||
|
pendingStoreId = (long) inventory.getStoreId();
|
||||||
|
applyPendingStore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sets dialog view to add/edit. Updates UI labels
|
|
||||||
public void setMode(String mode) {
|
public void setMode(String mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
lblMode.setText(mode + " Inventory");
|
lblMode.setText(mode + " Inventory");
|
||||||
|
|||||||
@@ -1,84 +1,132 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.control.PasswordField;
|
import javafx.scene.control.PasswordField;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
import org.example.petshopdesktop.api.dto.user.UserRequest;
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.api.dto.user.UserResponse;
|
import org.example.petshopdesktop.api.dto.employee.EmployeeRequest;
|
||||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
import org.example.petshopdesktop.api.dto.employee.EmployeeResponse;
|
||||||
import org.example.petshopdesktop.api.endpoints.CustomerApi;
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.api.endpoints.EmployeeApi;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
import org.example.petshopdesktop.util.TextFieldFormatSupport;
|
import org.example.petshopdesktop.util.TextFieldFormatSupport;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class StaffEditDialogController {
|
public class StaffEditDialogController {
|
||||||
|
|
||||||
@FXML
|
@FXML private TextField txtFirstName;
|
||||||
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 ComboBox<String> cbRole;
|
||||||
|
@FXML private ComboBox<String> cbStaffRole;
|
||||||
|
@FXML private ComboBox<String> cbActive;
|
||||||
|
@FXML private ComboBox<DropdownOption> cbStore;
|
||||||
|
@FXML private Label lblError;
|
||||||
|
@FXML private Button btnSave;
|
||||||
|
|
||||||
@FXML
|
private EmployeeResponse employee;
|
||||||
private TextField txtLastName;
|
private Long pendingStoreId = null;
|
||||||
|
|
||||||
@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 btnSave;
|
|
||||||
|
|
||||||
private UserResponse user;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
TextFieldFormatSupport.applyPhoneNumberFormat(txtPhone);
|
TextFieldFormatSupport.applyPhoneNumberFormat(txtPhone);
|
||||||
|
|
||||||
|
cbRole.setItems(FXCollections.observableArrayList("STAFF", "ADMIN"));
|
||||||
|
cbStaffRole.setItems(FXCollections.observableArrayList(
|
||||||
|
"STORE_MANAGER", "SALES_ASSOCIATE", "GROOMER", "VETERINARIAN"));
|
||||||
|
cbActive.setItems(FXCollections.observableArrayList("Active", "Inactive"));
|
||||||
|
|
||||||
|
cbStore.setCellFactory(param -> new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cbStore.setButtonCell(new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadStores();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUser(UserResponse user) {
|
private void loadStores() {
|
||||||
this.user = user;
|
new Thread(() -> {
|
||||||
String fullName = user.getFullName() == null ? "" : user.getFullName();
|
try {
|
||||||
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbStore.setItems(FXCollections.observableArrayList(stores));
|
||||||
|
applyPendingStore();
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException("StaffEditDialogController.loadStores", e, "Loading stores");
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
cbStore.setPromptText("Unable to load stores");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyPendingStore() {
|
||||||
|
if (pendingStoreId == null) return;
|
||||||
|
for (DropdownOption opt : cbStore.getItems()) {
|
||||||
|
if (opt.getId() != null && opt.getId().equals(pendingStoreId)) {
|
||||||
|
cbStore.setValue(opt);
|
||||||
|
pendingStoreId = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmployee(EmployeeResponse emp) {
|
||||||
|
this.employee = emp;
|
||||||
|
String fullName = emp.getFullName() != null ? emp.getFullName() : "";
|
||||||
|
if (fullName.isEmpty() && emp.getFirstName() != null) {
|
||||||
|
fullName = emp.getFirstName() + (emp.getLastName() != null ? " " + emp.getLastName() : "");
|
||||||
|
}
|
||||||
String[] names = splitFullName(fullName);
|
String[] names = splitFullName(fullName);
|
||||||
txtFirstName.setText(names[0]);
|
txtFirstName.setText(names[0]);
|
||||||
txtLastName.setText(names[1]);
|
txtLastName.setText(names[1]);
|
||||||
txtEmail.setText(user.getEmail());
|
txtEmail.setText(emp.getEmail());
|
||||||
txtPhone.setText(user.getPhone());
|
txtPhone.setText(emp.getPhone());
|
||||||
txtUsername.setText(user.getUsername());
|
txtUsername.setText(emp.getUsername());
|
||||||
|
|
||||||
|
if (emp.getRole() != null) cbRole.setValue(emp.getRole());
|
||||||
|
if (emp.getStaffRole() != null) cbStaffRole.setValue(emp.getStaffRole());
|
||||||
|
cbActive.setValue(Boolean.TRUE.equals(emp.getActive()) ? "Active" : "Inactive");
|
||||||
|
|
||||||
|
pendingStoreId = emp.getPrimaryStoreId();
|
||||||
|
applyPendingStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] splitFullName(String fullName) {
|
private String[] splitFullName(String fullName) {
|
||||||
if (fullName == null || fullName.trim().isEmpty()) {
|
if (fullName == null || fullName.trim().isEmpty()) return new String[]{"", ""};
|
||||||
return new String[]{"", ""};
|
|
||||||
}
|
|
||||||
String[] parts = fullName.trim().split("\\s+", 2);
|
String[] parts = fullName.trim().split("\\s+", 2);
|
||||||
String firstName = parts.length > 0 ? parts[0] : "";
|
return new String[]{parts.length > 0 ? parts[0] : "", parts.length > 1 ? parts[1] : ""};
|
||||||
String lastName = parts.length > 1 ? parts[1] : "";
|
|
||||||
return new String[]{firstName, lastName};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnSaveClicked(ActionEvent event) {
|
void btnSaveClicked(ActionEvent event) {
|
||||||
lblError.setText("");
|
lblError.setText("");
|
||||||
if (user == null) {
|
if (employee == null) {
|
||||||
lblError.setText("No user selected.");
|
lblError.setText("No employee selected.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,31 +167,47 @@ public class StaffEditDialogController {
|
|||||||
lblError.setText("Passwords do not match.");
|
lblError.setText("Passwords do not match.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (cbRole.getValue() == null) {
|
||||||
|
lblError.setText("Role is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cbStaffRole.getValue() == null) {
|
||||||
|
lblError.setText("Staff role is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cbStore.getValue() == null) {
|
||||||
|
lblError.setText("Primary store is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
btnSave.setDisable(true);
|
btnSave.setDisable(true);
|
||||||
|
|
||||||
|
String role = cbRole.getValue();
|
||||||
|
String staffRole = cbStaffRole.getValue();
|
||||||
|
boolean active = "Active".equals(cbActive.getValue());
|
||||||
|
Long storeId = cbStore.getValue().getId();
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
UserRequest request = new UserRequest();
|
EmployeeRequest request = new EmployeeRequest();
|
||||||
request.setUsername(username);
|
request.setUsername(username);
|
||||||
request.setPassword(password.isEmpty() ? null : password);
|
request.setPassword(password.isEmpty() ? null : password);
|
||||||
|
request.setFirstName(firstName);
|
||||||
|
request.setLastName(lastName);
|
||||||
request.setFullName(firstName + " " + lastName);
|
request.setFullName(firstName + " " + lastName);
|
||||||
request.setEmail(email);
|
request.setEmail(email);
|
||||||
request.setPhone(phone);
|
request.setPhone(phone);
|
||||||
request.setRole(user.getRole());
|
request.setRole(role);
|
||||||
request.setActive(user.getActive());
|
request.setStaffRole(staffRole);
|
||||||
|
request.setActive(active);
|
||||||
|
request.setPrimaryStoreId(storeId);
|
||||||
|
|
||||||
UserSession session = UserSession.getInstance();
|
EmployeeApi.getInstance().updateEmployee(employee.getId(), request);
|
||||||
if (session.isAdmin()) {
|
|
||||||
UserApi.getInstance().updateUser(user.getId(), request);
|
|
||||||
} else {
|
|
||||||
CustomerApi.getInstance().updateCustomer(user.getId(), request);
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.runLater(this::close);
|
Platform.runLater(this::close);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("StaffEditDialogController.btnSaveClicked", e, "Updating user");
|
ActivityLogger.getInstance().logException("StaffEditDialogController.btnSaveClicked", e, "Updating employee");
|
||||||
String msg = e.getMessage() == null ? "Could not update user." : e.getMessage();
|
String msg = e.getMessage() == null ? "Could not update employee." : e.getMessage();
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
lblError.setText(msg);
|
lblError.setText(msg);
|
||||||
btnSave.setDisable(false);
|
btnSave.setDisable(false);
|
||||||
|
|||||||
@@ -1,54 +1,86 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.control.PasswordField;
|
import javafx.scene.control.PasswordField;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.api.dto.user.UserRequest;
|
|
||||||
import org.example.petshopdesktop.api.endpoints.UserApi;
|
|
||||||
import org.example.petshopdesktop.api.endpoints.CustomerApi;
|
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
|
import org.example.petshopdesktop.api.dto.employee.EmployeeRequest;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.EmployeeApi;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
import org.example.petshopdesktop.util.TextFieldFormatSupport;
|
import org.example.petshopdesktop.util.TextFieldFormatSupport;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class StaffRegisterDialogController {
|
public class StaffRegisterDialogController {
|
||||||
|
|
||||||
@FXML
|
@FXML private TextField txtFirstName;
|
||||||
private TextField txtFirstName;
|
@FXML private TextField txtLastName;
|
||||||
|
@FXML private TextField txtEmail;
|
||||||
@FXML
|
@FXML private TextField txtPhone;
|
||||||
private TextField txtLastName;
|
@FXML private TextField txtUsername;
|
||||||
|
@FXML private PasswordField txtPassword;
|
||||||
@FXML
|
@FXML private PasswordField txtPasswordConfirm;
|
||||||
private TextField txtEmail;
|
@FXML private ComboBox<String> cbRole;
|
||||||
|
@FXML private ComboBox<String> cbStaffRole;
|
||||||
@FXML
|
@FXML private ComboBox<String> cbActive;
|
||||||
private TextField txtPhone;
|
@FXML private ComboBox<DropdownOption> cbStore;
|
||||||
|
@FXML private Label lblError;
|
||||||
@FXML
|
@FXML private Button btnCreate;
|
||||||
private TextField txtUsername;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private PasswordField txtPassword;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private PasswordField txtPasswordConfirm;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Label lblError;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Button btnCreate;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
TextFieldFormatSupport.applyPhoneNumberFormat(txtPhone);
|
TextFieldFormatSupport.applyPhoneNumberFormat(txtPhone);
|
||||||
|
|
||||||
|
cbRole.setItems(FXCollections.observableArrayList("STAFF", "ADMIN"));
|
||||||
|
cbRole.getSelectionModel().select("STAFF");
|
||||||
|
|
||||||
|
cbStaffRole.setItems(FXCollections.observableArrayList(
|
||||||
|
"STORE_MANAGER", "SALES_ASSOCIATE", "GROOMER", "VETERINARIAN"));
|
||||||
|
cbStaffRole.getSelectionModel().selectFirst();
|
||||||
|
|
||||||
|
cbActive.setItems(FXCollections.observableArrayList("Active", "Inactive"));
|
||||||
|
cbActive.getSelectionModel().select("Active");
|
||||||
|
|
||||||
|
cbStore.setCellFactory(param -> new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cbStore.setButtonCell(new ListCell<>() {
|
||||||
|
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||||
|
super.updateItem(o, empty);
|
||||||
|
setText(empty || o == null ? null : o.getLabel());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadStores();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadStores() {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
|
Platform.runLater(() -> cbStore.setItems(FXCollections.observableArrayList(stores)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException("StaffRegisterDialogController.loadStores", e, "Loading stores");
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
cbStore.setDisable(true);
|
||||||
|
cbStore.setPromptText("Unable to load stores");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -96,38 +128,53 @@ public class StaffRegisterDialogController {
|
|||||||
lblError.setText("Passwords do not match.");
|
lblError.setText("Passwords do not match.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (cbRole.getValue() == null) {
|
||||||
|
lblError.setText("Role is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cbStaffRole.getValue() == null) {
|
||||||
|
lblError.setText("Staff role is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cbStore.getValue() == null) {
|
||||||
|
lblError.setText("Primary store is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
btnCreate.setDisable(true);
|
btnCreate.setDisable(true);
|
||||||
|
|
||||||
|
String role = cbRole.getValue();
|
||||||
|
String staffRole = cbStaffRole.getValue();
|
||||||
|
boolean active = "Active".equals(cbActive.getValue());
|
||||||
|
Long storeId = cbStore.getValue().getId();
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
UserSession session = UserSession.getInstance();
|
EmployeeRequest request = new EmployeeRequest();
|
||||||
UserRequest request = new UserRequest();
|
|
||||||
request.setUsername(username);
|
request.setUsername(username);
|
||||||
request.setPassword(password);
|
request.setPassword(password);
|
||||||
|
request.setFirstName(firstName);
|
||||||
|
request.setLastName(lastName);
|
||||||
request.setFullName(firstName + " " + lastName);
|
request.setFullName(firstName + " " + lastName);
|
||||||
request.setEmail(email);
|
request.setEmail(email);
|
||||||
request.setPhone(phone);
|
request.setPhone(phone);
|
||||||
request.setActive(true);
|
request.setRole(role);
|
||||||
|
request.setStaffRole(staffRole);
|
||||||
|
request.setActive(active);
|
||||||
|
request.setPrimaryStoreId(storeId);
|
||||||
|
|
||||||
if (session.isAdmin()) {
|
EmployeeApi.getInstance().createEmployee(request);
|
||||||
request.setRole("STAFF");
|
|
||||||
UserApi.getInstance().createUser(request);
|
|
||||||
} else {
|
|
||||||
request.setRole("CUSTOMER");
|
|
||||||
CustomerApi.getInstance().createCustomer(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setTitle("Account Created");
|
alert.setTitle("Account Created");
|
||||||
alert.setHeaderText(null);
|
alert.setHeaderText(null);
|
||||||
alert.setContentText("Account created successfully.");
|
alert.setContentText("Staff account created successfully.");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
close();
|
close();
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating account");
|
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
||||||
String msg = e.getMessage() == null ? "Could not create account." : e.getMessage();
|
String msg = e.getMessage() == null ? "Could not create account." : e.getMessage();
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ public class Adoption {
|
|||||||
private SimpleDoubleProperty adoptionFee;
|
private SimpleDoubleProperty adoptionFee;
|
||||||
private SimpleStringProperty adoptionStatus;
|
private SimpleStringProperty adoptionStatus;
|
||||||
private SimpleStringProperty storeName;
|
private SimpleStringProperty storeName;
|
||||||
|
private Long storeId;
|
||||||
|
|
||||||
public Adoption(int adoptionId, int petId, int customerId, int employeeId, String petName, String customerName, String employeeName, String adoptionDate, double adoptionFee, String adoptionStatus, String storeName) {
|
public Adoption(int adoptionId, int petId, int customerId, int employeeId, String petName, String customerName, String employeeName, String adoptionDate, double adoptionFee, String adoptionStatus, String storeName, Long storeId) {
|
||||||
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
||||||
this.petId = new SimpleIntegerProperty(petId);
|
this.petId = new SimpleIntegerProperty(petId);
|
||||||
this.customerId = new SimpleIntegerProperty(customerId);
|
this.customerId = new SimpleIntegerProperty(customerId);
|
||||||
@@ -29,6 +30,7 @@ public class Adoption {
|
|||||||
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
||||||
this.adoptionStatus = new SimpleStringProperty(adoptionStatus);
|
this.adoptionStatus = new SimpleStringProperty(adoptionStatus);
|
||||||
this.storeName = new SimpleStringProperty(storeName != null ? storeName : "");
|
this.storeName = new SimpleStringProperty(storeName != null ? storeName : "");
|
||||||
|
this.storeId = storeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAdoptionId() { return adoptionId.get(); }
|
public int getAdoptionId() { return adoptionId.get(); }
|
||||||
@@ -96,4 +98,8 @@ public class Adoption {
|
|||||||
public void setStoreName(String storeName) { this.storeName.set(storeName); }
|
public void setStoreName(String storeName) { this.storeName.set(storeName); }
|
||||||
|
|
||||||
public SimpleStringProperty storeNameProperty() { return storeName; }
|
public SimpleStringProperty storeNameProperty() { return storeName; }
|
||||||
|
|
||||||
|
public Long getStoreId() { return storeId; }
|
||||||
|
|
||||||
|
public void setStoreId(Long storeId) { this.storeId = storeId; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<?import javafx.scene.control.ComboBox?>
|
<?import javafx.scene.control.ComboBox?>
|
||||||
<?import javafx.scene.control.DatePicker?>
|
<?import javafx.scene.control.DatePicker?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
@@ -146,6 +147,34 @@
|
|||||||
</ComboBox>
|
</ComboBox>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
<VBox fx:id="vbStore" prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="3" visible="false" managed="false">
|
||||||
|
<children>
|
||||||
|
<Label text="Store:" textFill="#2c3e50">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="16.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<ComboBox fx:id="cbStore" prefHeight="29.0" prefWidth="336.0" promptText="Select Store" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||||
|
</padding>
|
||||||
|
</ComboBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||||
|
<children>
|
||||||
|
<Label text="Adoption Fee:" textFill="#2c3e50">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="16.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<TextField fx:id="txtAdoptionFee" promptText="0.00" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="7.0" left="10.0" right="10.0" top="7.0" />
|
||||||
|
</padding>
|
||||||
|
</TextField>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
</children>
|
</children>
|
||||||
<VBox.margin>
|
<VBox.margin>
|
||||||
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
|
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
|
||||||
|
|||||||
@@ -208,6 +208,20 @@
|
|||||||
</ComboBox>
|
</ComboBox>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
<VBox fx:id="vbStore" prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="3" visible="false" managed="false">
|
||||||
|
<children>
|
||||||
|
<Label text="Store:" textFill="#2c3e50">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="16.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<ComboBox fx:id="cbStore" prefHeight="29.0" prefWidth="336.0" promptText="Select Store" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||||
|
</padding>
|
||||||
|
</ComboBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||||
<children>
|
<children>
|
||||||
<Label text="Employee:" textFill="#2c3e50">
|
<Label text="Employee:" textFill="#2c3e50">
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ComboBox?>
|
||||||
|
<?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 prefWidth="480.0" spacing="14.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.CustomerEditDialogController">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
||||||
|
</padding>
|
||||||
|
<children>
|
||||||
|
<Label text="Edit Customer" 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="New Password" />
|
||||||
|
<PasswordField fx:id="txtPassword" promptText="leave blank to keep current" />
|
||||||
|
</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 new password" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<Region HBox.hgrow="ALWAYS" />
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<HBox spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Status" />
|
||||||
|
<ComboBox fx:id="cbActive" maxWidth="1.7976931348623157E308" promptText="Select Status" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Loyalty Points" />
|
||||||
|
<TextField fx:id="txtLoyaltyPoints" promptText="0" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
||||||
|
<Button fx:id="btnSave" mnemonicParsing="false" onAction="#btnSaveClicked" style="-fx-background-color: #4ECDC4; -fx-text-fill: white; -fx-cursor: hand;" text="Save" />
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
@@ -103,6 +103,20 @@
|
|||||||
</TextField>
|
</TextField>
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
<VBox fx:id="vbStoreField" prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="1">
|
||||||
|
<children>
|
||||||
|
<Label text="Store:" textFill="#2c3e50">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="16.0" />
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<ComboBox fx:id="cbStore" prefHeight="29.0" prefWidth="336.0" promptText="Select Store" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||||
|
</padding>
|
||||||
|
</ComboBox>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2" />
|
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.rowIndex="2" />
|
||||||
</children>
|
</children>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ComboBox?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.PasswordField?>
|
<?import javafx.scene.control.PasswordField?>
|
||||||
<?import javafx.scene.control.TextField?>
|
<?import javafx.scene.control.TextField?>
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?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.StaffEditDialogController">
|
<VBox prefWidth="480.0" spacing="14.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
||||||
</padding>
|
</padding>
|
||||||
@@ -86,6 +87,40 @@
|
|||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
|
<HBox spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Role" />
|
||||||
|
<ComboBox fx:id="cbRole" maxWidth="1.7976931348623157E308" promptText="Select Role" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Staff Role" />
|
||||||
|
<ComboBox fx:id="cbStaffRole" maxWidth="1.7976931348623157E308" promptText="Select Staff Role" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<HBox spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Status" />
|
||||||
|
<ComboBox fx:id="cbActive" maxWidth="1.7976931348623157E308" promptText="Select Status" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Primary Store" />
|
||||||
|
<ComboBox fx:id="cbStore" maxWidth="1.7976931348623157E308" promptText="Select Store" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
||||||
<children>
|
<children>
|
||||||
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ComboBox?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.PasswordField?>
|
<?import javafx.scene.control.PasswordField?>
|
||||||
<?import javafx.scene.control.TextField?>
|
<?import javafx.scene.control.TextField?>
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?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">
|
<VBox prefWidth="480.0" 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>
|
<padding>
|
||||||
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
<Insets bottom="18.0" left="18.0" right="18.0" top="18.0" />
|
||||||
</padding>
|
</padding>
|
||||||
@@ -86,6 +87,40 @@
|
|||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
|
<HBox spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Role" />
|
||||||
|
<ComboBox fx:id="cbRole" maxWidth="1.7976931348623157E308" promptText="Select Role" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Staff Role" />
|
||||||
|
<ComboBox fx:id="cbStaffRole" maxWidth="1.7976931348623157E308" promptText="Select Staff Role" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
|
<HBox spacing="10.0">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Status" />
|
||||||
|
<ComboBox fx:id="cbActive" maxWidth="1.7976931348623157E308" promptText="Select Status" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
<VBox spacing="6.0" HBox.hgrow="ALWAYS">
|
||||||
|
<children>
|
||||||
|
<Label text="Primary Store" />
|
||||||
|
<ComboBox fx:id="cbStore" maxWidth="1.7976931348623157E308" promptText="Select Store" />
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
|
||||||
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
<HBox alignment="CENTER_RIGHT" spacing="10.0">
|
||||||
<children>
|
<children>
|
||||||
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
<Button mnemonicParsing="false" onAction="#btnCancelClicked" text="Cancel" />
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.ToggleButton?>
|
||||||
<?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?>
|
||||||
@@ -59,6 +60,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>
|
||||||
|
<ToggleButton fx:id="btnMyAppointments" mnemonicParsing="false" onAction="#btnMyAppointmentsToggled" style="-fx-background-color: #8e44ad; -fx-cursor: hand; -fx-background-radius: 8;" text="My Appointments" textFill="WHITE" visible="false" managed="false">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="14.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="12.0" left="24.0" right="24.0" top="12.0" />
|
||||||
|
</padding>
|
||||||
|
</ToggleButton>
|
||||||
</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;">
|
||||||
|
|||||||
Reference in New Issue
Block a user