Erweiterungen

This commit is contained in:
2025-08-13 16:08:54 +02:00
parent 7a116fda37
commit cbde45629e
2 changed files with 134 additions and 15 deletions

View File

@@ -111,4 +111,8 @@ public class Job {
@Field("app_user")
private String appUser;
// Preis (netto)
@Field("price")
private String price;
}

View File

@@ -86,6 +86,20 @@ public class AddJobView extends Main {
private Checkbox digitalProcessing;
private ComboBox<String> appUser;
// Price field
private TextField price;
// Date picker fields for appointments
private DatePicker pickupDate;
private DatePicker deliveryDate;
// TabSheet and Tab references for dynamic label updates
private TabSheet tabSheet;
private com.vaadin.flow.component.tabs.Tab addressesTab;
private com.vaadin.flow.component.tabs.Tab appointmentsTab;
private com.vaadin.flow.component.tabs.Tab cargoTab;
private com.vaadin.flow.component.tabs.Tab priceTab;
// Submit button
private Button submitButton;
@@ -182,6 +196,17 @@ public class AddJobView extends Main {
appUser.setItems("App-Nutzer");
appUser.setPlaceholder("App-Nutzer auswählen...");
// Price field
price = new TextField("Preis");
price.setPlaceholder("z.B. 150.00");
price.setRequiredIndicatorVisible(true);
// Date picker fields for appointments
pickupDate = new DatePicker("Datum");
pickupDate.setRequiredIndicatorVisible(true);
deliveryDate = new DatePicker("Datum");
deliveryDate.setRequiredIndicatorVisible(true);
// Submit button
submitButton = new Button("Auftrag anlegen", event -> submit());
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
@@ -196,20 +221,20 @@ public class AddJobView extends Main {
add(new ViewToolbar("Neuen Auftrag anlegen"));
// Create TabSheet for organizing the form
TabSheet tabSheet = new TabSheet();
tabSheet = new TabSheet();
tabSheet.setSizeFull();
// Tab 1: Customer & Addresses
tabSheet.add("Auftraggeber & Adressen", createCustomerAndAddressesTab());
addressesTab = tabSheet.add("Auftraggeber & Adressen", createCustomerAndAddressesTab());
// Tab 2: Appointments & Processing
tabSheet.add("Termine & Verarbeitung", createAppointmentsAndProcessingTab());
appointmentsTab = tabSheet.add("Termine & Verarbeitung", createAppointmentsAndProcessingTab());
// Tab 3: Cargo & Tasks
tabSheet.add("Ladung & Aufgaben", createCargoAndTasksTab());
cargoTab = tabSheet.add("Ladung & Aufgaben", createCargoAndTasksTab());
// Tab 4: Price & Submit
tabSheet.add("Preis & Abschluss", createPriceAndSubmitTab());
priceTab = tabSheet.add("Preis & Abschluss", createPriceAndSubmitTab());
add(tabSheet);
@@ -294,8 +319,6 @@ public class AddJobView extends Main {
// Appointment (Pickup)
H3 pickupApptTitle = new H3("Termin (Abholung)");
pickupApptTitle.getStyle().set("margin", "0");
DatePicker pickupDate = new DatePicker("Datum");
pickupDate.setRequiredIndicatorVisible(true);
TimePicker pickupTime = new TimePicker("Uhrzeit");
HorizontalLayout pickupApptRow = new HorizontalLayout(pickupDate, pickupTime);
pickupApptRow.setWidthFull();
@@ -307,8 +330,6 @@ public class AddJobView extends Main {
// Appointment (Delivery)
H3 deliveryApptTitle = new H3("Termin (Lieferung)");
deliveryApptTitle.getStyle().set("margin", "0");
DatePicker deliveryDate = new DatePicker("Datum");
deliveryDate.setRequiredIndicatorVisible(true);
TimePicker deliveryTime = new TimePicker("Uhrzeit");
HorizontalLayout deliveryApptRow = new HorizontalLayout(deliveryDate, deliveryTime);
deliveryApptRow.setWidthFull();
@@ -353,8 +374,6 @@ public class AddJobView extends Main {
// Preis (netto) - moved from createTasksAndNotesSection
H3 priceTitle = new H3("Preis (netto)");
priceTitle.getStyle().set("margin", "0");
TextField price = new TextField("Preis");
price.setRequiredIndicatorVisible(true);
content.add(priceTitle, price);
tabContent.add(content);
@@ -527,6 +546,16 @@ public class AddJobView extends Main {
.asRequired("")
.bind(Job::getDeliveryCity, Job::setDeliveryCity);
// Bind price field with validation
binder.forField(price)
.asRequired("")
.bind(Job::getPrice, Job::setPrice);
// Bind date picker fields with validation (we'll need to add these to Job model later)
// For now, we'll just set up the validation without binding to the model
binder.forField(pickupDate).asRequired("");
binder.forField(deliveryDate).asRequired("");
// Bind optional fields without validation
binder.bind(customerSelection, Job::getCustomerSelection, Job::setCustomerSelection);
binder.bind(pickupCompany, Job::getPickupCompany, Job::setPickupCompany);
@@ -549,20 +578,30 @@ public class AddJobView extends Main {
// Trigger initial validation when view is displayed
triggerValidation();
// Update tab labels with initial validation state
updateTabLabels();
}
private void setupValidationTriggers() {
// List of all required fields
TextField[] requiredFields = {
TextField[] requiredTextFields = {
pickupFirstName, pickupLastName, pickupStreet, pickupHouseNumber, pickupZip, pickupCity,
deliveryFirstName, deliveryLastName, deliveryStreet, deliveryHouseNumber, deliveryZip, deliveryCity
deliveryFirstName, deliveryLastName, deliveryStreet, deliveryHouseNumber, deliveryZip, deliveryCity,
price
};
// Add value change listeners to trigger validation on every change
for (TextField field : requiredFields) {
// List of required date fields
DatePicker[] requiredDateFields = {
pickupDate, deliveryDate
};
// Add value change listeners to trigger validation on every change for text fields
for (TextField field : requiredTextFields) {
field.addValueChangeListener(event -> {
triggerValidation();
updateFieldStyling(field);
updateTabLabels();
});
// Add focus listeners for immediate visual feedback
@@ -572,6 +611,22 @@ public class AddJobView extends Main {
// Set initial styling
updateFieldStyling(field);
}
// Add value change listeners for date fields
for (DatePicker field : requiredDateFields) {
field.addValueChangeListener(event -> {
triggerValidation();
updateDateFieldStyling(field);
updateTabLabels();
});
// Add focus listeners for immediate visual feedback
field.addFocusListener(event -> updateDateFieldStyling(field));
field.addBlurListener(event -> updateDateFieldStyling(field));
// Set initial styling
updateDateFieldStyling(field);
}
}
private void triggerValidation() {
@@ -595,6 +650,63 @@ public class AddJobView extends Main {
}
}
private void updateDateFieldStyling(DatePicker field) {
boolean isEmpty = field.getValue() == null;
if (isEmpty) {
// Apply transparent red background only to the input field, not the label
field.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
field.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
} else {
// Remove styling when field is filled
field.getStyle().remove("--vaadin-input-field-background");
field.getStyle().remove("--vaadin-input-field-border-color");
}
}
private void updateTabLabels() {
// Check validation state for each tab and update labels with exclamation marks
updateTabLabel(addressesTab, "Auftraggeber & Adressen", hasAddressValidationErrors());
updateTabLabel(appointmentsTab, "Termine & Verarbeitung", hasAppointmentValidationErrors());
updateTabLabel(cargoTab, "Ladung & Aufgaben", false); // No required fields in cargo tab
updateTabLabel(priceTab, "Preis & Abschluss", hasPriceValidationErrors());
}
private void updateTabLabel(com.vaadin.flow.component.tabs.Tab tab, String baseLabel, boolean hasErrors) {
if (hasErrors) {
tab.setLabel(baseLabel + " ⚠️");
} else {
tab.setLabel(baseLabel);
}
}
private boolean hasAddressValidationErrors() {
// Check pickup address fields
boolean pickupErrors = isFieldEmpty(pickupFirstName) || isFieldEmpty(pickupLastName) ||
isFieldEmpty(pickupStreet) || isFieldEmpty(pickupHouseNumber) ||
isFieldEmpty(pickupZip) || isFieldEmpty(pickupCity);
// Check delivery address fields
boolean deliveryErrors = isFieldEmpty(deliveryFirstName) || isFieldEmpty(deliveryLastName) ||
isFieldEmpty(deliveryStreet) || isFieldEmpty(deliveryHouseNumber) ||
isFieldEmpty(deliveryZip) || isFieldEmpty(deliveryCity);
return pickupErrors || deliveryErrors;
}
private boolean hasAppointmentValidationErrors() {
return pickupDate.getValue() == null || deliveryDate.getValue() == null;
}
private boolean hasPriceValidationErrors() {
return isFieldEmpty(price);
}
private boolean isFieldEmpty(TextField field) {
String value = field.getValue();
return value == null || value.trim().isEmpty();
}
private void submit() {
try {
Job job = new Job();
@@ -979,6 +1091,9 @@ public class AddJobView extends Main {
digitalProcessing.setValue(false);
appUser.clear();
// Price field
price.clear();
// Benutzer-Feedback
Notification.show("Alle Felder wurden geleert", 2000, Notification.Position.BOTTOM_CENTER);
}