added dropdowns for breed desktop
This commit is contained in:
@@ -42,6 +42,15 @@ public class DropdownApi {
|
||||
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
|
||||
}
|
||||
|
||||
public List<DropdownOption> getPetBreeds(String species) throws Exception {
|
||||
String encoded = java.net.URLEncoder.encode(species, java.nio.charset.StandardCharsets.UTF_8);
|
||||
String response = apiClient.getRawResponse("/api/v1/dropdowns/pet-breeds?species=" + encoded);
|
||||
if (response == null || response.isEmpty()) {
|
||||
throw new IllegalStateException("Empty response from pet breeds endpoint");
|
||||
}
|
||||
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
|
||||
}
|
||||
|
||||
public List<DropdownOption> getProducts() throws Exception {
|
||||
String response = apiClient.getRawResponse("/api/v1/dropdowns/products");
|
||||
if (response == null || response.isEmpty()) {
|
||||
|
||||
@@ -62,7 +62,7 @@ public class AdoptionDialogController {
|
||||
private boolean suppressPaymentDialog = false;
|
||||
|
||||
private ObservableList<String> statusList = FXCollections.observableArrayList(
|
||||
"Pending", "Completed", "Cancelled"
|
||||
"Pending", "Completed", "Missed", "Cancelled"
|
||||
);
|
||||
|
||||
@FXML
|
||||
@@ -282,6 +282,7 @@ public class AdoptionDialogController {
|
||||
}
|
||||
|
||||
suppressPaymentDialog = true;
|
||||
cbAdoptionStatus.setItems(statusList);
|
||||
for (String status : cbAdoptionStatus.getItems()) {
|
||||
if (status.equals(adoption.getAdoptionStatus())) {
|
||||
cbAdoptionStatus.getSelectionModel().select(status);
|
||||
@@ -289,13 +290,57 @@ public class AdoptionDialogController {
|
||||
}
|
||||
}
|
||||
suppressPaymentDialog = false;
|
||||
applyEditModeLock();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyEditModeLock() {
|
||||
String status = cbAdoptionStatus.getValue();
|
||||
|
||||
if ("Cancelled".equalsIgnoreCase(status)) {
|
||||
cbPet.setDisable(true);
|
||||
cbCustomer.setDisable(true);
|
||||
cbEmployee.setDisable(true);
|
||||
dpAdoptionDate.setDisable(true);
|
||||
cbAdoptionStatus.setDisable(true);
|
||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
||||
btnSave.setDisable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
LocalDate adoptionDate = dpAdoptionDate.getValue();
|
||||
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) {
|
||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
||||
dpAdoptionDate.setDisable(true);
|
||||
} else {
|
||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending", "Cancelled"));
|
||||
}
|
||||
if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
|
||||
cbAdoptionStatus.getSelectionModel().selectFirst();
|
||||
}
|
||||
suppressPaymentDialog = false;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
lblMode.setText(mode + " Adoption");
|
||||
lblAdoptionId.setVisible(mode.equals("Edit"));
|
||||
if (mode.equals("Add")) {
|
||||
suppressPaymentDialog = true;
|
||||
cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending"));
|
||||
cbAdoptionStatus.setValue("Pending");
|
||||
cbAdoptionStatus.setDisable(true);
|
||||
suppressPaymentDialog = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void applySelectedPet() {
|
||||
|
||||
@@ -43,24 +43,26 @@ public class AppointmentDialogController {
|
||||
@FXML private Label lblAppointmentId;
|
||||
@FXML private Label lblMode;
|
||||
|
||||
private String mode = null;
|
||||
private String mode = null;
|
||||
private AppointmentDTO selectedAppointment = null;
|
||||
private Long pendingPetSelectionId = null;
|
||||
|
||||
private ObservableList<String> statusList =
|
||||
FXCollections.observableArrayList(
|
||||
"Booked", "Completed", "Missed", "Cancelled"
|
||||
);
|
||||
private boolean isOriginallyCancel = false;
|
||||
private boolean isOriginallyCompletedOrMissed = false;
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
lblMode.setText(mode + " Appointment");
|
||||
lblAppointmentId.setVisible(!mode.equals("Add"));
|
||||
if (mode.equals("Add")) {
|
||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Booked"));
|
||||
cbAppointmentStatus.setValue("Booked");
|
||||
cbAppointmentStatus.setDisable(true);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
cbAppointmentStatus.setItems(statusList);
|
||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Booked", "Completed", "Missed", "Cancelled"));
|
||||
cbPet.setDisable(true);
|
||||
cbEmployee.setPromptText("Select an employee");
|
||||
cbPet.setPromptText("Select a customer first");
|
||||
@@ -228,6 +230,46 @@ public class AppointmentDialogController {
|
||||
applySelectedService();
|
||||
applySelectedCustomer();
|
||||
applySelectedEmployee();
|
||||
applyEditModeLock();
|
||||
}
|
||||
|
||||
private void applyEditModeLock() {
|
||||
String status = cbAppointmentStatus.getValue();
|
||||
isOriginallyCancel = "Cancelled".equalsIgnoreCase(status);
|
||||
isOriginallyCompletedOrMissed = "Completed".equalsIgnoreCase(status) || "Missed".equalsIgnoreCase(status);
|
||||
|
||||
if (isOriginallyCancel) {
|
||||
cbService.setDisable(true);
|
||||
cbCustomer.setDisable(true);
|
||||
cbPet.setDisable(true);
|
||||
cbEmployee.setDisable(true);
|
||||
cbHour.setDisable(true);
|
||||
cbMinute.setDisable(true);
|
||||
dpAppointmentDate.setDisable(true);
|
||||
cbAppointmentStatus.setDisable(true);
|
||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Cancelled"));
|
||||
btnSave.setDisable(true);
|
||||
} else if (isOriginallyCompletedOrMissed) {
|
||||
cbService.setDisable(true);
|
||||
cbCustomer.setDisable(true);
|
||||
cbPet.setDisable(true);
|
||||
cbEmployee.setDisable(true);
|
||||
cbHour.setDisable(true);
|
||||
cbMinute.setDisable(true);
|
||||
dpAppointmentDate.setDisable(true);
|
||||
cbAppointmentStatus.setDisable(false);
|
||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
|
||||
} else {
|
||||
cbService.setDisable(true);
|
||||
cbCustomer.setDisable(true);
|
||||
cbPet.setDisable(true);
|
||||
cbEmployee.setDisable(false);
|
||||
cbHour.setDisable(false);
|
||||
cbMinute.setDisable(false);
|
||||
dpAppointmentDate.setDisable(false);
|
||||
cbAppointmentStatus.setDisable(false);
|
||||
cbAppointmentStatus.setItems(FXCollections.observableArrayList("Booked", "Cancelled"));
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonSaveClicked(MouseEvent e) {
|
||||
|
||||
@@ -121,7 +121,7 @@ public class InventoryDialogController {
|
||||
//Validate inputs
|
||||
errorMsg += Validator.isPresent(txtQuantity.getText(), "Quantity");
|
||||
errorMsg += Validator.isLessThanVarChars(txtQuantity.getText(), "Quantity", 11);
|
||||
errorMsg += Validator.isNonNegativeInteger(txtQuantity.getText(), "Quantity");
|
||||
errorMsg += Validator.isPositiveInteger(txtQuantity.getText(), "Quantity");
|
||||
|
||||
//Operation only occurs if there are no errors
|
||||
if (errorMsg.isEmpty()) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PetDialogController {
|
||||
|
||||
@@ -41,6 +42,8 @@ public class PetDialogController {
|
||||
@FXML private Button btnChangeImage;
|
||||
@FXML private Button btnRemoveImage;
|
||||
@FXML private ComboBox<String> cbPetStatus;
|
||||
@FXML private ComboBox<String> cbPetSpecies;
|
||||
@FXML private ComboBox<String> cbPetBreed;
|
||||
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||
@FXML private ComboBox<DropdownOption> cbStore;
|
||||
@FXML private VBox vbCustomerField;
|
||||
@@ -51,10 +54,8 @@ public class PetDialogController {
|
||||
@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<String> cbPetSpecies;
|
||||
|
||||
private String mode = null;
|
||||
private File selectedImageFile;
|
||||
@@ -65,6 +66,7 @@ public class PetDialogController {
|
||||
private Long pendingStoreId = null;
|
||||
private Long originalCustomerId = null;
|
||||
private boolean isOriginallyOwnedOrAdopted = false;
|
||||
private String pendingBreedValue = null;
|
||||
|
||||
private final ObservableList<String> statusList = FXCollections.observableArrayList(
|
||||
STATUS_AVAILABLE, STATUS_ADOPTED, STATUS_OWNED, STATUS_PENDING
|
||||
@@ -73,6 +75,7 @@ public class PetDialogController {
|
||||
@FXML
|
||||
void initialize() {
|
||||
cbPetStatus.setItems(statusList);
|
||||
cbPetBreed.setDisable(true);
|
||||
|
||||
cbCustomer.setCellFactory(param -> new ListCell<>() {
|
||||
@Override protected void updateItem(DropdownOption o, boolean empty) {
|
||||
@@ -106,6 +109,18 @@ public class PetDialogController {
|
||||
loadCustomers();
|
||||
loadStores();
|
||||
|
||||
cbPetSpecies.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
if (newVal != null && !newVal.isBlank()) {
|
||||
if (!cbPetSpecies.isDisabled()) cbPetBreed.setDisable(false);
|
||||
loadBreeds(newVal);
|
||||
} else {
|
||||
cbPetBreed.setItems(FXCollections.observableArrayList());
|
||||
cbPetBreed.setValue(null);
|
||||
cbPetBreed.setPromptText("Select Species first");
|
||||
if (!cbPetSpecies.isDisabled()) cbPetBreed.setDisable(true);
|
||||
}
|
||||
});
|
||||
|
||||
cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
|
||||
if (newVal != null) applyStatusRules(newVal, true);
|
||||
});
|
||||
@@ -129,6 +144,29 @@ public class PetDialogController {
|
||||
refreshImagePreview();
|
||||
}
|
||||
|
||||
private void loadBreeds(String species) {
|
||||
cbPetBreed.setPromptText("Loading breeds...");
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> options = DropdownApi.getInstance().getPetBreeds(species);
|
||||
List<String> breeds = options.stream().map(DropdownOption::getLabel).collect(Collectors.toList());
|
||||
Platform.runLater(() -> {
|
||||
cbPetBreed.setItems(FXCollections.observableArrayList(breeds));
|
||||
cbPetBreed.setPromptText("Select Breed");
|
||||
if (pendingBreedValue != null) {
|
||||
cbPetBreed.setValue(pendingBreedValue);
|
||||
pendingBreedValue = null;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Platform.runLater(() -> {
|
||||
ActivityLogger.getInstance().logException("PetDialogController.loadBreeds", e, "Loading breeds for species: " + species);
|
||||
cbPetBreed.setPromptText("Unable to load breeds");
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void applyStatusRules(String status, boolean clearInvalidSelections) {
|
||||
if (STATUS_AVAILABLE.equalsIgnoreCase(status)) {
|
||||
vbCustomerField.setDisable(true);
|
||||
@@ -151,9 +189,10 @@ public class PetDialogController {
|
||||
|
||||
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 breedValue = cbPetBreed.getValue() != null ? cbPetBreed.getValue().trim() : "";
|
||||
if (breedValue.isEmpty()) errorMsg += "Breed is required\n";
|
||||
if (cbPetStatus.getSelectionModel().getSelectedItem() == null) errorMsg += "Status is required\n";
|
||||
errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price");
|
||||
|
||||
@@ -171,7 +210,7 @@ public class PetDialogController {
|
||||
|
||||
errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50);
|
||||
errorMsg += Validator.isLessThanVarChars(speciesValue, "Species", 50);
|
||||
errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50);
|
||||
errorMsg += Validator.isLessThanVarChars(breedValue, "Breed", 50);
|
||||
errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12);
|
||||
errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11);
|
||||
errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
|
||||
@@ -224,7 +263,7 @@ public class PetDialogController {
|
||||
PetRequest request = new PetRequest();
|
||||
request.setPetName(txtPetName.getText());
|
||||
request.setPetSpecies(cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "");
|
||||
request.setPetBreed(txtPetBreed.getText());
|
||||
request.setPetBreed(cbPetBreed.getValue() != null ? cbPetBreed.getValue().trim() : "");
|
||||
request.setPetStatus(cbPetStatus.getValue());
|
||||
|
||||
if (txtPetPrice.getText() != null && !txtPetPrice.getText().isBlank()) {
|
||||
@@ -251,9 +290,7 @@ public class PetDialogController {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
List<DropdownOption> options = DropdownApi.getInstance().getPetSpecies();
|
||||
List<String> species = options.stream()
|
||||
.map(DropdownOption::getLabel)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
List<String> species = options.stream().map(DropdownOption::getLabel).collect(Collectors.toList());
|
||||
Platform.runLater(() -> {
|
||||
String current = cbPetSpecies.getValue();
|
||||
cbPetSpecies.setItems(FXCollections.observableArrayList(species));
|
||||
@@ -339,8 +376,6 @@ public class PetDialogController {
|
||||
|
||||
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();
|
||||
@@ -355,6 +390,9 @@ public class PetDialogController {
|
||||
isOriginallyOwnedOrAdopted = STATUS_OWNED.equalsIgnoreCase(pet.getPetStatus())
|
||||
|| STATUS_ADOPTED.equalsIgnoreCase(pet.getPetStatus());
|
||||
|
||||
pendingBreedValue = pet.getPetBreed();
|
||||
cbPetSpecies.setValue(pet.getPetSpecies());
|
||||
|
||||
for (String status : cbPetStatus.getItems()) {
|
||||
if (status.equals(pet.getPetStatus())) {
|
||||
cbPetStatus.getSelectionModel().select(status);
|
||||
@@ -368,7 +406,7 @@ public class PetDialogController {
|
||||
|
||||
private void applyEditModeLock() {
|
||||
cbPetSpecies.setDisable(true);
|
||||
txtPetBreed.setDisable(true);
|
||||
cbPetBreed.setDisable(true);
|
||||
|
||||
boolean isStaff = !UserSession.getInstance().isAdmin();
|
||||
if (isStaff && isOriginallyOwnedOrAdopted) {
|
||||
@@ -388,7 +426,10 @@ public class PetDialogController {
|
||||
selectedImageFile = null;
|
||||
removeImageRequested = false;
|
||||
cbPetSpecies.setDisable(false);
|
||||
txtPetBreed.setDisable(false);
|
||||
cbPetBreed.setDisable(true);
|
||||
cbPetBreed.setItems(FXCollections.observableArrayList());
|
||||
cbPetBreed.setValue(null);
|
||||
cbPetBreed.setPromptText("Select Species first");
|
||||
cbPetStatus.setDisable(false);
|
||||
cbPetStatus.getSelectionModel().select(STATUS_AVAILABLE);
|
||||
applyStatusRules(STATUS_AVAILABLE, false);
|
||||
|
||||
@@ -82,6 +82,10 @@ public class StaffRegisterDialogController {
|
||||
lblError.setText("Password is required.");
|
||||
return;
|
||||
}
|
||||
if (password.length() < 6) {
|
||||
lblError.setText("Password must be at least 6 characters.");
|
||||
return;
|
||||
}
|
||||
if (!password.equals(confirm)) {
|
||||
lblError.setText("Passwords do not match.");
|
||||
return;
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<ComboBox fx:id="cbPetSpecies" editable="true" prefHeight="29.0" prefWidth="336.0" promptText="Select or enter species" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10; -fx-background-color: white;">
|
||||
<ComboBox fx:id="cbPetSpecies" prefHeight="29.0" prefWidth="336.0" promptText="Select Species" 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>
|
||||
@@ -105,11 +105,11 @@
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="txtPetBreed" style="-fx-border-color: #E8EBED; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-radius: 10;">
|
||||
<ComboBox fx:id="cbPetBreed" prefHeight="29.0" prefWidth="336.0" promptText="Select Species first" 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" />
|
||||
<Insets bottom="3.0" left="10.0" right="10.0" top="3.0" />
|
||||
</padding>
|
||||
</TextField>
|
||||
</ComboBox>
|
||||
</children>
|
||||
</VBox>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="8.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||
|
||||
Reference in New Issue
Block a user