diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java index 45b2978d..16805d34 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java @@ -31,62 +31,30 @@ import java.util.Optional; public class PetDialogController { - @FXML - private Button btnCancel; + private static final String STATUS_AVAILABLE = "Available"; + private static final String STATUS_ADOPTED = "Adopted"; + private static final String STATUS_OWNED = "Owned"; + private static final String STATUS_PENDING = "Pending"; - @FXML - private Button btnSave; - - @FXML - private Button btnChangeImage; - - @FXML - private Button btnRemoveImage; - - @FXML - private ComboBox cbPetStatus; - - @FXML - private ComboBox cbCustomer; - - @FXML - private ComboBox cbStore; - - @FXML - private VBox vbCustomerField; - - @FXML - private VBox vbStoreField; - - @FXML - private VBox vbPriceField; - - @FXML - private Label lblMode; - - @FXML - private Label lblPetId; - - @FXML - private Label lblImageStatus; - - @FXML - private ImageView imgPetPreview; - - @FXML - private TextField txtPetAge; - - @FXML - private TextField txtPetBreed; - - @FXML - private TextField txtPetName; - - @FXML - private TextField txtPetPrice; - - @FXML - private ComboBox cbPetSpecies; + @FXML private Button btnCancel; + @FXML private Button btnSave; + @FXML private Button btnChangeImage; + @FXML private Button btnRemoveImage; + @FXML private ComboBox cbPetStatus; + @FXML private ComboBox cbCustomer; + @FXML private ComboBox cbStore; + @FXML private VBox vbCustomerField; + @FXML private VBox vbStoreField; + @FXML private VBox vbPriceField; + @FXML private Label lblMode; + @FXML private Label lblPetId; + @FXML private Label lblImageStatus; + @FXML private ImageView imgPetPreview; + @FXML private TextField txtPetAge; + @FXML private TextField txtPetBreed; + @FXML private TextField txtPetName; + @FXML private TextField txtPetPrice; + @FXML private ComboBox cbPetSpecies; private String mode = null; private File selectedImageFile; @@ -96,14 +64,14 @@ public class PetDialogController { private Long pendingCustomerId = null; private Long pendingStoreId = null; private Long originalCustomerId = null; + private boolean isOriginallyOwnedOrAdopted = false; - private ObservableList statusList = FXCollections.observableArrayList( - "Available", "Adopted", "Owned", "Pending" + private final ObservableList statusList = FXCollections.observableArrayList( + STATUS_AVAILABLE, STATUS_ADOPTED, STATUS_OWNED, STATUS_PENDING ); @FXML void initialize() { - cbPetStatus.setItems(statusList); cbCustomer.setCellFactory(param -> new ListCell<>() { @@ -132,12 +100,14 @@ public class PetDialogController { } }); - updateStatusFieldVisibility(null); + applyStatusRules(STATUS_AVAILABLE, false); loadSpecies(); + loadCustomers(); + loadStores(); cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> { - updateStatusFieldVisibility(newVal); + if (newVal != null) applyStatusRules(newVal, true); }); btnSave.setOnMouseClicked(new EventHandler() { @@ -157,48 +127,57 @@ public class PetDialogController { btnChangeImage.setOnMouseClicked(mouseEvent -> handleChangeImage()); btnRemoveImage.setOnMouseClicked(mouseEvent -> handleRemoveImage()); refreshImagePreview(); + } - loadCustomers(); - loadStores(); + private void applyStatusRules(String status, boolean clearInvalidSelections) { + if (STATUS_AVAILABLE.equalsIgnoreCase(status)) { + vbCustomerField.setDisable(true); + vbStoreField.setDisable(false); + if (clearInvalidSelections) cbCustomer.setValue(null); + return; + } + if (STATUS_OWNED.equalsIgnoreCase(status)) { + vbCustomerField.setDisable(false); + vbStoreField.setDisable(true); + if (clearInvalidSelections) cbStore.setValue(null); + return; + } + vbCustomerField.setDisable(false); + vbStoreField.setDisable(false); } private void buttonSaveClicked(MouseEvent mouseEvent) { String errorMsg = ""; - //Check validation (input required) errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name"); errorMsg += Validator.isPresent(txtPetAge.getText(), "Age"); errorMsg += Validator.isPresent(txtPetBreed.getText(), "Breed"); String speciesValue = cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : ""; if (speciesValue.isEmpty()) errorMsg += "Species is required\n"; - String selectedStatus = cbPetStatus.getValue(); + if (cbPetStatus.getSelectionModel().getSelectedItem() == null) errorMsg += "Status is required\n"; errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price"); - if (cbPetStatus.getSelectionModel().getSelectedItem() == null){ - errorMsg += "Status is required"; + + String selectedStatus = cbPetStatus.getValue(); + if (STATUS_AVAILABLE.equalsIgnoreCase(selectedStatus) && cbStore.getValue() == null) { + errorMsg += "Store is required for Available status\n"; } - boolean needsCustomer = "Owned".equalsIgnoreCase(selectedStatus) - || "Adopted".equalsIgnoreCase(selectedStatus) - || "Pending".equalsIgnoreCase(selectedStatus); - boolean needsStore = requiresStore(selectedStatus); - if (needsCustomer && cbCustomer.getValue() == null && UserSession.getInstance().isAdmin()) { - errorMsg += "Customer is required for " + selectedStatus + " status\n"; + if (STATUS_OWNED.equalsIgnoreCase(selectedStatus) && cbCustomer.getValue() == null) { + errorMsg += "Customer is required for Owned status\n"; } - if (needsStore && cbStore.getValue() == null) { - errorMsg += "Store is required for " + selectedStatus + " status\n"; + if (STATUS_ADOPTED.equalsIgnoreCase(selectedStatus)) { + if (cbCustomer.getValue() == null) errorMsg += "Customer is required for Adopted status\n"; + if (cbStore.getValue() == null) errorMsg += "Store is required for Adopted status\n"; } - //Check validation (length size) errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50); errorMsg += Validator.isLessThanVarChars(speciesValue, "Species", 50); errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50); errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12); errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11); - - //Check validation (format) errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price"); errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age"); - if(errorMsg.isEmpty()){ + if (errorMsg.isEmpty()) { if ("Edit".equals(mode) && UserSession.getInstance().isAdmin()) { Long newCustomerId = cbCustomer.getValue() != null ? cbCustomer.getValue().getId() : null; if (!Objects.equals(originalCustomerId, newCustomerId)) { @@ -206,44 +185,34 @@ public class PetDialogController { confirm.setHeaderText("Confirm Owner Change"); confirm.setContentText("Are you sure you want to reassign this pet to a different owner?"); Optional result = confirm.showAndWait(); - if (result.isEmpty() || result.get() != ButtonType.OK) { - return; - } + if (result.isEmpty() || result.get() != ButtonType.OK) return; } } PetRequest request = buildPetRequest(); try { - if(mode.equals("Add")) { + if (mode.equals("Add")) { PetResponse response = PetApi.getInstance().createPet(request); applyImageChanges(response.getPetId()); } else { String[] parts = lblPetId.getText().split(": "); - if (parts.length < 2) { - throw new IllegalStateException("Invalid pet ID format"); - } + if (parts.length < 2) throw new IllegalStateException("Invalid pet ID format"); Long petId = Long.parseLong(parts[1]); PetApi.getInstance().updatePet(petId, request); applyImageChanges(petId); } - - //tell the user operation was successful Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); } catch (Exception e) { - ActivityLogger.getInstance().logException( - "PetDialogController.buttonSaveClicked", - e, - mode + " pet record"); + ActivityLogger.getInstance().logException("PetDialogController.buttonSaveClicked", e, mode + " pet record"); Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("Operation Error"); alert.setContentText(mode + " failed: " + e.getMessage()); alert.showAndWait(); } - } - else{ + } else { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("Input Error"); alert.setContentText(errorMsg); @@ -257,6 +226,7 @@ public class PetDialogController { request.setPetSpecies(cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : ""); request.setPetBreed(txtPetBreed.getText()); request.setPetStatus(cbPetStatus.getValue()); + if (txtPetPrice.getText() != null && !txtPetPrice.getText().isBlank()) { try { request.setPetPrice(new BigDecimal(txtPetPrice.getText())); @@ -265,24 +235,14 @@ public class PetDialogController { } } - int age; try { - age = Integer.parseInt(txtPetAge.getText()); + request.setPetAge(Integer.parseInt(txtPetAge.getText())); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid age format"); } - request.setPetAge(age); - String status = cbPetStatus.getValue(); - boolean customerApplicable = "Owned".equalsIgnoreCase(status) - || "Adopted".equalsIgnoreCase(status) - || "Pending".equalsIgnoreCase(status); - if (customerApplicable && cbCustomer.getValue() != null) { - request.setCustomerId(cbCustomer.getValue().getId()); - } - if (requiresStore(status) && cbStore.getValue() != null) { - request.setStoreId(cbStore.getValue().getId()); - } + if (cbCustomer.getValue() != null) request.setCustomerId(cbCustomer.getValue().getId()); + if (cbStore.getValue() != null) request.setStoreId(cbStore.getValue().getId()); return request; } @@ -297,9 +257,7 @@ public class PetDialogController { Platform.runLater(() -> { String current = cbPetSpecies.getValue(); cbPetSpecies.setItems(FXCollections.observableArrayList(species)); - if (current != null && !current.isBlank()) { - cbPetSpecies.setValue(current); - } + if (current != null && !current.isBlank()) cbPetSpecies.setValue(current); }); } catch (Exception e) { Platform.runLater(() -> ActivityLogger.getInstance().logException( @@ -318,8 +276,7 @@ public class PetDialogController { }); } catch (Exception e) { Platform.runLater(() -> { - ActivityLogger.getInstance().logException( - "PetDialogController.loadCustomers", e, "Loading customers"); + ActivityLogger.getInstance().logException("PetDialogController.loadCustomers", e, "Loading customers"); cbCustomer.setDisable(true); cbCustomer.setPromptText("Unable to load customers"); }); @@ -337,8 +294,7 @@ public class PetDialogController { }); } catch (Exception e) { Platform.runLater(() -> { - ActivityLogger.getInstance().logException( - "PetDialogController.loadStores", e, "Loading stores"); + ActivityLogger.getInstance().logException("PetDialogController.loadStores", e, "Loading stores"); cbStore.setDisable(true); cbStore.setPromptText("Unable to load stores"); }); @@ -378,63 +334,74 @@ public class PetDialogController { stage.close(); } - public void displayPetDetails(Pet pet){ - if (pet!=null){ - lblPetId.setText("ID: " + pet.getPetId()); - txtPetName.setText(pet.getPetName()); - cbPetSpecies.setValue(pet.getPetSpecies()); - txtPetBreed.setText(pet.getPetBreed()); - txtPetAge.setText(pet.getPetAge() + ""); - txtPetPrice.setText(pet.getPetPrice() + ""); - currentImageUrl = pet.getImageUrl(); - selectedImageFile = null; - removeImageRequested = false; - refreshImagePreview(); + public void displayPetDetails(Pet pet) { + if (pet == null) return; - pendingCustomerId = pet.getCustomerId() > 0 ? pet.getCustomerId() : null; - originalCustomerId = pendingCustomerId; - pendingStoreId = pet.getStoreId() > 0 ? pet.getStoreId() : null; + lblPetId.setText("ID: " + pet.getPetId()); + txtPetName.setText(pet.getPetName()); + cbPetSpecies.setValue(pet.getPetSpecies()); + txtPetBreed.setText(pet.getPetBreed()); + txtPetAge.setText(String.valueOf(pet.getPetAge())); + txtPetPrice.setText(String.valueOf(pet.getPetPrice())); + currentImageUrl = pet.getImageUrl(); + selectedImageFile = null; + removeImageRequested = false; + refreshImagePreview(); - for (String status : cbPetStatus.getItems()) { - if(status.equals(pet.getPetStatus())){ - cbPetStatus.getSelectionModel().select(status); - break; - } + pendingCustomerId = pet.getCustomerId() > 0 ? pet.getCustomerId() : null; + originalCustomerId = pendingCustomerId; + pendingStoreId = pet.getStoreId() > 0 ? pet.getStoreId() : null; + + isOriginallyOwnedOrAdopted = STATUS_OWNED.equalsIgnoreCase(pet.getPetStatus()) + || STATUS_ADOPTED.equalsIgnoreCase(pet.getPetStatus()); + + for (String status : cbPetStatus.getItems()) { + if (status.equals(pet.getPetStatus())) { + cbPetStatus.getSelectionModel().select(status); + break; } - updateStatusFieldVisibility(cbPetStatus.getValue()); - applyStatusLock(); } + + applyStatusRules(cbPetStatus.getValue(), false); + applyEditModeLock(); } - private void applyStatusLock() { - String status = cbPetStatus.getValue(); - boolean isRestricted = "Adopted".equalsIgnoreCase(status) || "Owned".equalsIgnoreCase(status); + private void applyEditModeLock() { + cbPetSpecies.setDisable(true); + txtPetBreed.setDisable(true); + boolean isStaff = !UserSession.getInstance().isAdmin(); - cbPetStatus.setDisable(isRestricted && isStaff); + if (isStaff && isOriginallyOwnedOrAdopted) { + cbPetStatus.setDisable(true); + vbCustomerField.setDisable(true); + vbStoreField.setDisable(true); + } } public void setMode(String mode) { this.mode = mode; lblMode.setText(mode + " Pet"); - if(mode.equals("Add")) { + + if (mode.equals("Add")) { lblPetId.setVisible(false); currentImageUrl = null; selectedImageFile = null; removeImageRequested = false; + cbPetSpecies.setDisable(false); + txtPetBreed.setDisable(false); + cbPetStatus.setDisable(false); + cbPetStatus.getSelectionModel().select(STATUS_AVAILABLE); + applyStatusRules(STATUS_AVAILABLE, false); refreshImagePreview(); - } - else if(mode.equals("Edit")) { + } else if (mode.equals("Edit")) { lblPetId.setVisible(true); refreshImagePreview(); } - updateStatusFieldVisibility(cbPetStatus.getValue()); } private void handleChangeImage() { File file = FilePickerSupport.pickImageFile(btnSave.getScene().getWindow()); - if (file == null) { - return; - } + if (file == null) return; selectedImageFile = file; removeImageRequested = false; lblImageStatus.setText("Selected: " + file.getName()); @@ -471,9 +438,7 @@ public class PetDialogController { } private void refreshImagePreview() { - if (imgPetPreview == null || lblImageStatus == null || btnRemoveImage == null) { - return; - } + if (imgPetPreview == null || lblImageStatus == null || btnRemoveImage == null) return; imgPetPreview.setImage(null); if (selectedImageFile != null) { lblImageStatus.setText("Selected: " + selectedImageFile.getName()); @@ -490,29 +455,4 @@ public class PetDialogController { lblImageStatus.setText("No image selected"); btnRemoveImage.setDisable(true); } - - private void updateStatusFieldVisibility(String status) { - if (status == null) { - vbPriceField.setDisable(false); - vbCustomerField.setDisable(true); - vbStoreField.setDisable(false); - return; - } - boolean isAdmin = UserSession.getInstance().isAdmin(); - boolean customerApplicable = "Owned".equalsIgnoreCase(status) - || "Adopted".equalsIgnoreCase(status) - || "Pending".equalsIgnoreCase(status); - boolean isOwned = "Owned".equalsIgnoreCase(status); - - vbPriceField.setDisable(false); - vbCustomerField.setDisable(!customerApplicable || !isAdmin); - vbStoreField.setDisable(isOwned); - } - - private boolean requiresStore(String status) { - return "Available".equalsIgnoreCase(status) - || "Pending".equalsIgnoreCase(status) - || "Adopted".equalsIgnoreCase(status); - } - }