diff --git a/src/main/java/de/assecutor/votianlt/config/DataInitializer.java b/src/main/java/de/assecutor/votianlt/config/DataInitializer.java index 2d1c076..ed826dc 100644 --- a/src/main/java/de/assecutor/votianlt/config/DataInitializer.java +++ b/src/main/java/de/assecutor/votianlt/config/DataInitializer.java @@ -49,40 +49,6 @@ public class DataInitializer implements CommandLineRunner { log.info("Created admin user: admin@votianlt.de / admin123"); } - // Test User - if (!userRepository.existsByEmail("test@votianlt.de")) { - User testUser = new User(); - testUser.setEmail("test@votianlt.de"); - testUser.setPassword(passwordEncoder.encode("test123")); - testUser.setName("Testmann"); - testUser.setFirstname("Test"); - testUser.setIsActivated((byte) 1); - testUser.setIsEmailConfirmed((byte) 1); - testUser.setCreatedAt(LocalDateTime.now()); - testUser.setUpdatedAt(LocalDateTime.now()); - testUser.setRoles(Set.of("USER")); - - userRepository.save(testUser); - log.info("Created test user: test@votianlt.de / test123"); - } - - // Demo User - if (!userRepository.existsByEmail("demo@votianlt.de")) { - User demoUser = new User(); - demoUser.setEmail("demo@votianlt.de"); - demoUser.setPassword(passwordEncoder.encode("demo123")); - demoUser.setName("Demouser"); - demoUser.setFirstname("Demo"); - demoUser.setIsActivated((byte) 1); - demoUser.setIsEmailConfirmed((byte) 1); - demoUser.setCreatedAt(LocalDateTime.now()); - demoUser.setUpdatedAt(LocalDateTime.now()); - demoUser.setRoles(Set.of("USER")); - - userRepository.save(demoUser); - log.info("Created demo user: demo@votianlt.de / demo123"); - } - log.info("Test users initialization completed."); } } diff --git a/src/main/java/de/assecutor/votianlt/model/AppDevice.java b/src/main/java/de/assecutor/votianlt/model/AppDevice.java deleted file mode 100644 index 1d830f4..0000000 --- a/src/main/java/de/assecutor/votianlt/model/AppDevice.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.assecutor.votianlt.model; - -import lombok.Data; -import org.bson.types.ObjectId; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; -import org.springframework.data.mongodb.core.mapping.Field; - -import java.time.LocalDateTime; - -@Data -@Document(collection = "app_device") -public class AppDevice { - - @Id - private ObjectId id; - - @Field("name") - private String name; - - @Field("app_user_id") - private ObjectId appUserId; - - @Field("erstellt_am") - private LocalDateTime erstelltAm; - - @Field("erstellt_von") - private ObjectId erstelltVon; - - @Field("aktualisiert_am") - private LocalDateTime aktualisiertAm; - - @Field("aktualisiert_von") - private ObjectId aktualisiertVon; - - public AppDevice() { - this.erstelltAm = LocalDateTime.now(); - this.aktualisiertAm = LocalDateTime.now(); - } -} diff --git a/src/main/java/de/assecutor/votianlt/model/AppUser.java b/src/main/java/de/assecutor/votianlt/model/AppUser.java index 408e814..bd45f6a 100644 --- a/src/main/java/de/assecutor/votianlt/model/AppUser.java +++ b/src/main/java/de/assecutor/votianlt/model/AppUser.java @@ -50,8 +50,6 @@ public class AppUser { @Field("geraet") private String geraet; - @Field("app_device_id") - private ObjectId appDeviceId; @Field("owner") private ObjectId owner; diff --git a/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java b/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java index 7115fd6..a5d5fd0 100644 --- a/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java +++ b/src/main/java/de/assecutor/votianlt/pages/base/ui/view/MainLayout.java @@ -106,10 +106,9 @@ public final class MainLayout extends AppLayout { SideNavItem jobs = new SideNavItem("Aufträge", "jobs", new Icon(VaadinIcon.LIST)); SideNavItem customers = new SideNavItem("Kunden", "customers", new Icon(VaadinIcon.USERS)); SideNavItem appUsers = new SideNavItem("App-Nutzer", "app-user", new Icon(VaadinIcon.USERS)); - SideNavItem devices = new SideNavItem("Endgeräte", "app-devices", new Icon(VaadinIcon.MOBILE)); SideNavItem statistics = new SideNavItem("Statistiken", "statistics", new Icon(VaadinIcon.BAR_CHART)); - verwaltungContent.add(jobs, customers, appUsers, devices); + verwaltungContent.add(jobs, customers, appUsers); // Only show invoices menu if billing is enabled for the current user if (isBillingEnabledForCurrentUser()) { diff --git a/src/main/java/de/assecutor/votianlt/pages/service/AppDeviceService.java b/src/main/java/de/assecutor/votianlt/pages/service/AppDeviceService.java deleted file mode 100644 index 76803bb..0000000 --- a/src/main/java/de/assecutor/votianlt/pages/service/AppDeviceService.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.assecutor.votianlt.pages.service; - -import de.assecutor.votianlt.model.AppDevice; -import de.assecutor.votianlt.repository.AppDeviceRepository; -import de.assecutor.votianlt.security.SecurityService; -import org.bson.types.ObjectId; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -@Service -@Transactional -public class AppDeviceService { - - private final AppDeviceRepository appDeviceRepository; - private final SecurityService securityService; - - @Autowired - public AppDeviceService(AppDeviceRepository appDeviceRepository, SecurityService securityService) { - this.appDeviceRepository = appDeviceRepository; - this.securityService = securityService; - } - - public AppDevice createAppDevice(AppDevice appDevice) { - // Set creation and update metadata - appDevice.setErstelltAm(java.time.LocalDateTime.now()); - appDevice.setAktualisiertAm(java.time.LocalDateTime.now()); - - // Set creator and updater - current user ID is required - ObjectId currentUserId = securityService.getCurrentUserId(); - appDevice.setErstelltVon(currentUserId); - appDevice.setAktualisiertVon(currentUserId); - - return appDeviceRepository.save(appDevice); - } - - public List findByCurrentUser() { - ObjectId currentUserId = securityService.getCurrentUserId(); - return appDeviceRepository.findByErstelltVon(currentUserId); - } - - public List findUnassignedDevices() { - return appDeviceRepository.findByAppUserIdIsNull(); - } - - public AppDevice findById(ObjectId id) { - return appDeviceRepository.findById(id).orElse(null); - } - - public AppDevice updateAppDevice(AppDevice appDevice) { - appDevice.setAktualisiertAm(java.time.LocalDateTime.now()); - appDevice.setAktualisiertVon(securityService.getCurrentUserId()); - return appDeviceRepository.save(appDevice); - } - - public void deleteById(ObjectId id) { - appDeviceRepository.deleteById(id); - } -} diff --git a/src/main/java/de/assecutor/votianlt/pages/view/AddAppDeviceView.java b/src/main/java/de/assecutor/votianlt/pages/view/AddAppDeviceView.java deleted file mode 100644 index 996df64..0000000 --- a/src/main/java/de/assecutor/votianlt/pages/view/AddAppDeviceView.java +++ /dev/null @@ -1,159 +0,0 @@ -package de.assecutor.votianlt.pages.view; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.formlayout.FormLayout; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.notification.Notification; -import com.vaadin.flow.component.orderedlayout.FlexComponent; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.TextField; -import com.vaadin.flow.data.binder.Binder; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; -import de.assecutor.votianlt.model.AppDevice; -import de.assecutor.votianlt.pages.service.AppDeviceService; -import jakarta.annotation.security.RolesAllowed; -import org.springframework.beans.factory.annotation.Autowired; - -@PageTitle("Neues Endgerät anlegen") -@Route(value = "add-app-device", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class) -@RolesAllowed({ "USER", "ADMIN" }) -public class AddAppDeviceView extends VerticalLayout { - - private final AppDeviceService appDeviceService; - private final Binder binder; - - // Formularfelder - private final TextField nameField; - - @Autowired - public AddAppDeviceView(AppDeviceService appDeviceService) { - this.appDeviceService = appDeviceService; - - // Binder initialisieren - binder = new Binder<>(AppDevice.class); - - // Formularfelder erstellen - nameField = new TextField("Gerätename"); - nameField.setRequired(true); - nameField.setRequiredIndicatorVisible(true); - nameField.setPlaceholder("z.B. iPhone 15, Samsung Galaxy S24"); - nameField.setWidth("100%"); - nameField.addBlurListener(e -> validateNameField()); - - // Layout konfigurieren - setSizeFull(); - setPadding(true); - setSpacing(true); - - // Content zentrieren - setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); - setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER); - - // Hauptcontainer erstellen - VerticalLayout contentContainer = new VerticalLayout(); - contentContainer.setWidth("600px"); - contentContainer.setMaxWidth("90%"); - contentContainer.getStyle().set("background", "var(--lumo-base-color)"); - contentContainer.getStyle().set("border-radius", "8px"); - contentContainer.getStyle().set("box-shadow", "0 2px 8px rgba(0,0,0,0.1)"); - contentContainer.setPadding(true); - contentContainer.setSpacing(true); - - // Titel - H2 title = new H2("Neues Endgerät anlegen"); - title.getStyle().set("margin", "0"); - title.getStyle().set("text-align", "center"); - contentContainer.add(title); - - // Formular - FormLayout formLayout = new FormLayout(); - formLayout.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1)); - formLayout.add(nameField); - contentContainer.add(formLayout); - - // Buttons - HorizontalLayout buttonLayout = new HorizontalLayout(); - buttonLayout.setWidthFull(); - buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); - buttonLayout.setSpacing(true); - - Button backButton = new Button("Zurück"); - backButton.addClickListener(e -> navigateBack()); - - Button saveButton = new Button("Speichern"); - saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); - saveButton.addClickListener(e -> createAppDevice()); - - buttonLayout.add(backButton, saveButton); - contentContainer.add(buttonLayout); - - add(contentContainer); - - // Testdaten einfügen - populateTestData(); - - // Binder konfigurieren - setupBinder(); - } - - private void setupBinder() { - binder.forField(nameField).asRequired("Gerätename ist erforderlich").bind(AppDevice::getName, - AppDevice::setName); - } - - private void populateTestData() { - // No default values - field starts empty - } - - private void createAppDevice() { - // Validate field first - validateNameField(); - - if (nameField.isInvalid()) { - Notification.show("Bitte füllen Sie das Pflichtfeld korrekt aus", 3000, Notification.Position.MIDDLE); - return; - } - - if (binder.validate().isOk()) { - try { - AppDevice appDevice = new AppDevice(); - binder.writeBean(appDevice); - - // Explizit als nicht zugeordnet speichern - appDevice.setAppUserId(null); - - AppDevice savedDevice = appDeviceService.createAppDevice(appDevice); - - Notification.show("Endgerät erfolgreich angelegt: " + savedDevice.getName(), 3000, - Notification.Position.MIDDLE); - - // Zurück zur Übersicht - navigateBack(); - - } catch (Exception e) { - Notification.show("Fehler beim Anlegen des Endgeräts: " + e.getMessage(), 5000, - Notification.Position.MIDDLE); - } - } else { - Notification.show("Bitte füllen Sie alle erforderlichen Felder aus", 3000, Notification.Position.MIDDLE); - } - } - - private void navigateBack() { - getUI().ifPresent(ui -> ui.navigate("app-devices")); - } - - private void validateNameField() { - String value = nameField.getValue(); - if (value == null || value.trim().isEmpty()) { - nameField.setInvalid(true); - nameField.setErrorMessage("Gerätename ist ein Pflichtfeld"); - } else { - nameField.setInvalid(false); - nameField.setErrorMessage(""); - } - } -} diff --git a/src/main/java/de/assecutor/votianlt/pages/view/AddAppUserView.java b/src/main/java/de/assecutor/votianlt/pages/view/AddAppUserView.java index 45dcd93..f74e20d 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/AddAppUserView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/AddAppUserView.java @@ -2,7 +2,6 @@ package de.assecutor.votianlt.pages.view; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.icon.Icon; @@ -18,9 +17,7 @@ import com.vaadin.flow.data.binder.ValidationException; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import de.assecutor.votianlt.model.AppUser; -import de.assecutor.votianlt.model.AppDevice; import de.assecutor.votianlt.pages.service.AppUserService; -import de.assecutor.votianlt.pages.service.AppDeviceService; import jakarta.annotation.security.RolesAllowed; import org.springframework.beans.factory.annotation.Autowired; @@ -30,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired; public class AddAppUserView extends VerticalLayout { private final AppUserService appUserService; - private final AppDeviceService appDeviceService; private final Binder binder = new Binder<>(AppUser.class); // Form fields @@ -38,16 +34,13 @@ public class AddAppUserView extends VerticalLayout { private final TextField firstnameField = new TextField("Vorname"); private final TextField lastnameField = new TextField("Nachname"); private final TextField phoneField = new TextField("Telefon (Mobil)"); - private final TextField appCodeField = new TextField("App-Code"); private final TextField emailField = new TextField("E-Mail-Adresse"); private final PasswordField passwordField = new PasswordField("Passwort"); private final PasswordField confirmPasswordField = new PasswordField("Passwort wiederholen"); - private final ComboBox deviceComboBox = new ComboBox<>("Endgerät"); @Autowired - public AddAppUserView(AppUserService appUserService, AppDeviceService appDeviceService) { + public AddAppUserView(AppUserService appUserService) { this.appUserService = appUserService; - this.appDeviceService = appDeviceService; setSizeFull(); setPadding(true); setSpacing(true); @@ -110,9 +103,6 @@ public class AddAppUserView extends VerticalLayout { phoneField.setRequiredIndicatorVisible(true); phoneField.addBlurListener(e -> validateField(phoneField, "Telefonnummer ist ein Pflichtfeld")); - appCodeField.setWidthFull(); - appCodeField.setRequiredIndicatorVisible(true); - appCodeField.addBlurListener(e -> validateField(appCodeField, "App-Code ist ein Pflichtfeld")); emailField.setWidthFull(); emailField.setRequiredIndicatorVisible(true); @@ -133,25 +123,14 @@ public class AddAppUserView extends VerticalLayout { confirmPasswordField.setRequiredIndicatorVisible(true); confirmPasswordField.addBlurListener(e -> validateConfirmPasswordField()); - // Configure device dropdown - // Geräteauswahl vorbereiten - deviceComboBox.setWidthFull(); - deviceComboBox.setItemLabelGenerator(device -> device.getName()); - deviceComboBox.setRequired(true); - deviceComboBox.setRequiredIndicatorVisible(true); - deviceComboBox.setPlaceholder("Bitte wählen..."); - deviceComboBox.setItems(appDeviceService.findUnassignedDevices()); - deviceComboBox.addBlurListener(e -> validateDeviceField()); // Add fields to form formLayout.add(designationField); formLayout.add(nameLayout); formLayout.add(phoneField); - formLayout.add(appCodeField); formLayout.add(emailField); formLayout.add(passwordField); formLayout.add(confirmPasswordField); - formLayout.add(deviceComboBox); contentContainer.add(formLayout); @@ -177,7 +156,6 @@ public class AddAppUserView extends VerticalLayout { binder.forField(firstnameField).bind(AppUser::getVorname, AppUser::setVorname); binder.forField(lastnameField).bind(AppUser::getNachname, AppUser::setNachname); binder.forField(phoneField).bind(AppUser::getTelefon, AppUser::setTelefon); - binder.forField(appCodeField).bind(AppUser::getAppCode, AppUser::setAppCode); binder.forField(emailField).bind(AppUser::getEmail, AppUser::setEmail); binder.forField(passwordField).asRequired("Passwort ist erforderlich").bind(AppUser::getPassword, AppUser::setPassword); @@ -190,11 +168,6 @@ public class AddAppUserView extends VerticalLayout { (appUser, value) -> { } // Dummy setter - this field is not stored ); - binder.forField(deviceComboBox).asRequired("Bitte ein Gerät auswählen").bind(appUser -> null, // Initialwert, - // wird beim - // Erstellen - // gesetzt - (appUser, appDevice) -> appUser.setAppDeviceId(appDevice != null ? appDevice.getId() : null)); } private void createAppUser() { @@ -212,12 +185,6 @@ public class AddAppUserView extends VerticalLayout { // Save AppUser first to get the ObjectId AppUser savedUser = appUserService.createAppUser(newAppUser); - // Referenz im AppDevice setzen - AppDevice selectedDevice = deviceComboBox.getValue(); - if (selectedDevice != null && savedUser != null && savedUser.getId() != null) { - selectedDevice.setAppUserId(savedUser.getId()); - appDeviceService.updateAppDevice(selectedDevice); - } // Show success message Notification.show("App-Nutzer erfolgreich angelegt", 3000, Notification.Position.MIDDLE); @@ -304,29 +271,18 @@ public class AddAppUserView extends VerticalLayout { } } - private void validateDeviceField() { - if (deviceComboBox.getValue() == null) { - deviceComboBox.setInvalid(true); - deviceComboBox.setErrorMessage("Bitte wählen Sie ein Gerät aus"); - } else { - deviceComboBox.setInvalid(false); - deviceComboBox.setErrorMessage(""); - } - } private boolean validateAllFields() { validateField(designationField, "Kennung ist ein Pflichtfeld"); validateField(firstnameField, "Vorname ist ein Pflichtfeld"); validateField(lastnameField, "Nachname ist ein Pflichtfeld"); validateField(phoneField, "Telefonnummer ist ein Pflichtfeld"); - validateField(appCodeField, "App-Code ist ein Pflichtfeld"); validateEmailField(); validatePasswordField(); validateConfirmPasswordField(); - validateDeviceField(); return !designationField.isInvalid() && !firstnameField.isInvalid() && !lastnameField.isInvalid() - && !phoneField.isInvalid() && !appCodeField.isInvalid() && !emailField.isInvalid() - && !passwordField.isInvalid() && !confirmPasswordField.isInvalid() && !deviceComboBox.isInvalid(); + && !phoneField.isInvalid() && !emailField.isInvalid() + && !passwordField.isInvalid() && !confirmPasswordField.isInvalid(); } } diff --git a/src/main/java/de/assecutor/votianlt/pages/view/AddJobView.java b/src/main/java/de/assecutor/votianlt/pages/view/AddJobView.java index cf0a712..d5d9954 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/AddJobView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/AddJobView.java @@ -1235,9 +1235,20 @@ public class AddJobView extends Main { IntegerField qty = new IntegerField("Anzahl"); qty.setMin(1); - qty.setValue(1); + qty.setMax(9999); // Set reasonable maximum qty.setWidth("10%"); qty.setRequiredIndicatorVisible(true); + qty.setPlaceholder("1"); + // Add validation on blur + qty.addBlurListener(e -> { + if (qty.getValue() == null || qty.getValue() <= 0) { + qty.setInvalid(true); + qty.setErrorMessage("Anzahl muss größer als 0 sein"); + } else { + qty.setInvalid(false); + qty.setErrorMessage(""); + } + }); NumberField weight = new NumberField("Gewicht"); weight.setSuffixComponent(new Span("kg")); @@ -1245,15 +1256,15 @@ public class AddJobView extends Main { weight.setRequiredIndicatorVisible(true); NumberField len = new NumberField("Länge"); - len.setSuffixComponent(new Span("mm")); + len.setSuffixComponent(new Span("cm")); len.setWidth("12%"); len.setRequiredIndicatorVisible(true); NumberField wid = new NumberField("Breite"); - wid.setSuffixComponent(new Span("mm")); + wid.setSuffixComponent(new Span("cm")); wid.setWidth("12%"); wid.setRequiredIndicatorVisible(true); NumberField hei = new NumberField("Höhe"); - hei.setSuffixComponent(new Span("mm")); + hei.setSuffixComponent(new Span("cm")); hei.setWidth("12%"); hei.setRequiredIndicatorVisible(true); @@ -1294,7 +1305,13 @@ public class AddJobView extends Main { numField.setInvalid(numField.getValue() == null || numField.getValue() <= 0); } else if (field instanceof IntegerField) { IntegerField intField = (IntegerField) field; - intField.setInvalid(intField.getValue() == null || intField.getValue() <= 0); + boolean isInvalid = intField.getValue() == null || intField.getValue() <= 0; + intField.setInvalid(isInvalid); + if (isInvalid) { + intField.setErrorMessage("Anzahl muss größer als 0 sein"); + } else { + intField.setErrorMessage(""); + } } }; diff --git a/src/main/java/de/assecutor/votianlt/pages/view/AppDevicesView.java b/src/main/java/de/assecutor/votianlt/pages/view/AppDevicesView.java deleted file mode 100644 index 109925b..0000000 --- a/src/main/java/de/assecutor/votianlt/pages/view/AppDevicesView.java +++ /dev/null @@ -1,107 +0,0 @@ -package de.assecutor.votianlt.pages.view; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.grid.Grid; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.icon.Icon; -import com.vaadin.flow.component.icon.VaadinIcon; -import com.vaadin.flow.component.orderedlayout.FlexComponent; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; -import de.assecutor.votianlt.model.AppDevice; -import de.assecutor.votianlt.model.AppUser; -import de.assecutor.votianlt.pages.service.AppDeviceService; -import de.assecutor.votianlt.pages.service.AppUserService; -import jakarta.annotation.security.RolesAllowed; -import org.springframework.beans.factory.annotation.Autowired; - -@PageTitle("Endgeräte") -@Route(value = "app-devices", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class) -@RolesAllowed({ "USER", "ADMIN" }) -public class AppDevicesView extends VerticalLayout { - - private final AppDeviceService appDeviceService; - @SuppressWarnings("unused") // Wird in Grid-Spalte verwendet - private final AppUserService appUserService; - private final Grid appDeviceGrid; - - @Autowired - public AppDevicesView(AppDeviceService appDeviceService, AppUserService appUserService) { - this.appDeviceService = appDeviceService; - this.appUserService = appUserService; - - setSizeFull(); - setPadding(true); - setSpacing(true); - - // Header mit Titel und Button - HorizontalLayout header = new HorizontalLayout(); - header.setWidthFull(); - header.setAlignItems(FlexComponent.Alignment.CENTER); - - H2 title = new H2("Endgeräte"); - title.getStyle().set("margin", "0"); - - Button addButton = new Button("Neues Endgerät anlegen", new Icon(VaadinIcon.PLUS)); - addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); - addButton.addClickListener(e -> navigateToAddAppDevice()); - - header.add(title, addButton); - header.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN); - add(header); - - // Grid für Endgeräte - appDeviceGrid = new Grid<>(AppDevice.class, false); - appDeviceGrid.setSizeFull(); - - // Grid-Spalten konfigurieren - appDeviceGrid.addColumn(AppDevice::getName).setHeader("Gerätename").setAutoWidth(true); - - // App-Nutzer Spalte mit Name anzeigen - appDeviceGrid.addColumn(appDevice -> { - if (appDevice.getAppUserId() != null) { - try { - AppUser appUser = appUserService.findByCurrentUser().stream() - .filter(user -> user.getId().equals(appDevice.getAppUserId())).findFirst().orElse(null); - if (appUser != null) { - return appUser.getVorname() + " " + appUser.getNachname(); - } - } catch (Exception e) { - // Fehler beim Laden des App-Nutzers ignorieren - } - } - return "Nicht zugeordnet"; - }).setHeader("Zugeordneter App-Nutzer").setAutoWidth(true); - - appDeviceGrid.addColumn(AppDevice::getErstelltAm).setHeader("Erstellt am").setAutoWidth(true); - - // Make grid rows clickable - appDeviceGrid.setSelectionMode(Grid.SelectionMode.SINGLE); - appDeviceGrid.getStyle().set("cursor", "pointer"); - - // Add click listener to navigate to edit view - appDeviceGrid.addItemClickListener(event -> { - AppDevice appDevice = event.getItem(); - if (appDevice != null && appDevice.getId() != null) { - getUI().ifPresent(ui -> ui.navigate("edit-app-device/" + appDevice.getId().toHexString())); - } - }); - - add(appDeviceGrid); - - // Daten laden - loadAppDevices(); - } - - private void loadAppDevices() { - var appDevices = appDeviceService.findByCurrentUser(); - appDeviceGrid.setItems(appDevices); - } - - private void navigateToAddAppDevice() { - getUI().ifPresent(ui -> ui.navigate("add-app-device")); - } -} diff --git a/src/main/java/de/assecutor/votianlt/pages/view/AppUserView.java b/src/main/java/de/assecutor/votianlt/pages/view/AppUserView.java index cf31e0e..be6e52b 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/AppUserView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/AppUserView.java @@ -12,9 +12,7 @@ import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import de.assecutor.votianlt.model.AppUser; -import de.assecutor.votianlt.model.AppDevice; import de.assecutor.votianlt.pages.service.AppUserService; -import de.assecutor.votianlt.pages.service.AppDeviceService; import jakarta.annotation.security.RolesAllowed; import org.springframework.beans.factory.annotation.Autowired; @@ -27,7 +25,7 @@ public class AppUserView extends VerticalLayout { private final Grid appUserGrid; @Autowired - public AppUserView(AppUserService appUserService, AppDeviceService appDeviceService) { + public AppUserView(AppUserService appUserService) { this.appUserService = appUserService; setSizeFull(); @@ -61,13 +59,6 @@ public class AppUserView extends VerticalLayout { appUserGrid.addColumn(AppUser::getTelefon).setHeader("Telefon").setAutoWidth(true); appUserGrid.addColumn(AppUser::getAppCode).setHeader("App-Code").setAutoWidth(true); appUserGrid.addColumn(AppUser::getEmail).setHeader("E-Mail").setAutoWidth(true); - appUserGrid.addColumn(appUser -> { - if (appUser.getAppDeviceId() != null) { - AppDevice device = appDeviceService.findById(appUser.getAppDeviceId()); - return device != null ? device.getName() : "Nicht gefunden"; - } - return "Kein Gerät zugewiesen"; - }).setHeader("Endgerät").setAutoWidth(true); // Make grid rows clickable appUserGrid.setSelectionMode(Grid.SelectionMode.SINGLE); diff --git a/src/main/java/de/assecutor/votianlt/pages/view/EditAppDeviceView.java b/src/main/java/de/assecutor/votianlt/pages/view/EditAppDeviceView.java deleted file mode 100644 index 9fd144f..0000000 --- a/src/main/java/de/assecutor/votianlt/pages/view/EditAppDeviceView.java +++ /dev/null @@ -1,242 +0,0 @@ -package de.assecutor.votianlt.pages.view; - -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.html.Span; -import com.vaadin.flow.component.confirmdialog.ConfirmDialog; -import com.vaadin.flow.component.formlayout.FormLayout; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.notification.Notification; -import com.vaadin.flow.component.orderedlayout.FlexComponent; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.TextField; -import com.vaadin.flow.data.binder.Binder; -import com.vaadin.flow.router.HasUrlParameter; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; -import de.assecutor.votianlt.model.AppDevice; -import de.assecutor.votianlt.model.AppUser; -import de.assecutor.votianlt.pages.service.AppDeviceService; -import de.assecutor.votianlt.pages.service.AppUserService; -import jakarta.annotation.security.RolesAllowed; -import org.bson.types.ObjectId; -import org.springframework.beans.factory.annotation.Autowired; - -@PageTitle("Endgerät bearbeiten") -@Route(value = "edit-app-device", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class) -@RolesAllowed({ "USER", "ADMIN" }) -public class EditAppDeviceView extends VerticalLayout implements HasUrlParameter { - - private final AppDeviceService appDeviceService; - private final AppUserService appUserService; - private final Binder binder; - - // Formularfelder - private final TextField nameField; - private final Span appUserDisplay; - - // Aktuelles Endgerät - private AppDevice currentAppDevice; - - @Autowired - public EditAppDeviceView(AppDeviceService appDeviceService, AppUserService appUserService) { - this.appDeviceService = appDeviceService; - this.appUserService = appUserService; - - // Binder initialisieren - binder = new Binder<>(AppDevice.class); - - // Formularfelder erstellen - nameField = new TextField("Gerätename"); - nameField.setRequired(true); - nameField.setPlaceholder("z.B. iPhone 15, Samsung Galaxy S24"); - nameField.setWidth("100%"); - - // App-Nutzer Anzeige (nur lesend) - appUserDisplay = new Span(); - appUserDisplay.getStyle().set("font-weight", "bold") - .set("padding", "var(--lumo-space-s)") - .set("border", "1px solid var(--lumo-contrast-20pct)") - .set("border-radius", "var(--lumo-border-radius-m)") - .set("background-color", "var(--lumo-contrast-5pct)") - .set("display", "block") - .set("width", "100%"); - - // Layout konfigurieren - setSizeFull(); - setPadding(true); - setSpacing(true); - - // Content zentrieren - setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); - setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER); - - // Hauptcontainer erstellen - VerticalLayout contentContainer = new VerticalLayout(); - contentContainer.setWidth("600px"); - contentContainer.setMaxWidth("90%"); - contentContainer.getStyle().set("background", "var(--lumo-base-color)"); - contentContainer.getStyle().set("border-radius", "8px"); - contentContainer.getStyle().set("box-shadow", "0 2px 8px rgba(0,0,0,0.1)"); - contentContainer.setPadding(true); - contentContainer.setSpacing(true); - - // Titel - H2 title = new H2("Endgerät bearbeiten"); - title.getStyle().set("margin", "0"); - title.getStyle().set("text-align", "center"); - contentContainer.add(title); - - // Formular - FormLayout formLayout = new FormLayout(); - formLayout.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1)); - // Label für App-Nutzer - Span appUserLabel = new Span("Zugeordneter App-Nutzer:"); - appUserLabel.getStyle().set("font-weight", "500") - .set("color", "var(--lumo-secondary-text-color)") - .set("font-size", "var(--lumo-font-size-s)"); - - formLayout.add(nameField); - formLayout.add(appUserLabel); - formLayout.add(appUserDisplay); - contentContainer.add(formLayout); - - // Buttons - HorizontalLayout buttonLayout = new HorizontalLayout(); - buttonLayout.setWidthFull(); - buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); - buttonLayout.setSpacing(true); - - Button backButton = new Button("Zurück"); - backButton.addClickListener(e -> navigateBack()); - - Button saveButton = new Button("Speichern"); - saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); - saveButton.addClickListener(e -> saveAppDevice()); - - Button deleteButton = new Button("Löschen"); - deleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR); - deleteButton.addClickListener(e -> deleteAppDevice()); - - buttonLayout.add(backButton, saveButton, deleteButton); - contentContainer.add(buttonLayout); - - add(contentContainer); - - // Binder konfigurieren - setupBinder(); - } - - @Override - public void setParameter(com.vaadin.flow.router.BeforeEvent event, String parameter) { - try { - ObjectId deviceId = new ObjectId(parameter); - loadAppDevice(deviceId); - } catch (IllegalArgumentException e) { - Notification.show("Ungültige Endgerät-ID", 3000, Notification.Position.MIDDLE); - navigateBack(); - } - } - - private void loadAppDevice(ObjectId deviceId) { - currentAppDevice = appDeviceService.findById(deviceId); - - if (currentAppDevice != null) { - // Formular mit aktuellen Daten füllen - binder.readBean(currentAppDevice); - - // App-Nutzer Anzeige aktualisieren - updateAppUserDisplay(); - } else { - Notification.show("Endgerät nicht gefunden", 3000, Notification.Position.MIDDLE); - navigateBack(); - } - } - - private void setupBinder() { - binder.forField(nameField).asRequired("Gerätename ist erforderlich").bind(AppDevice::getName, - AppDevice::setName); - } - - private void updateAppUserDisplay() { - if (currentAppDevice != null && currentAppDevice.getAppUserId() != null) { - try { - // Finde den zugeordneten App-Nutzer - AppUser assignedUser = appUserService.findByCurrentUser().stream() - .filter(user -> user.getId().equals(currentAppDevice.getAppUserId())) - .findFirst() - .orElse(null); - - if (assignedUser != null) { - String displayText = assignedUser.getVorname() + " " + assignedUser.getNachname() + - " (" + assignedUser.getEmail() + ")"; - appUserDisplay.setText(displayText); - appUserDisplay.getStyle().set("color", "var(--lumo-body-text-color)"); - } else { - appUserDisplay.setText("App-Nutzer nicht gefunden (ID: " + currentAppDevice.getAppUserId() + ")"); - appUserDisplay.getStyle().set("color", "var(--lumo-error-text-color)"); - } - } catch (Exception e) { - appUserDisplay.setText("Fehler beim Laden des App-Nutzers"); - appUserDisplay.getStyle().set("color", "var(--lumo-error-text-color)"); - } - } else { - appUserDisplay.setText("Kein App-Nutzer zugeordnet"); - appUserDisplay.getStyle().set("color", "var(--lumo-secondary-text-color)"); - appUserDisplay.getStyle().set("font-style", "italic"); - } - } - - private void saveAppDevice() { - if (binder.validate().isOk()) { - try { - // Aktuelle Daten in das Modell schreiben - binder.writeBean(currentAppDevice); - - // Endgerät aktualisieren - AppDevice updatedDevice = appDeviceService.updateAppDevice(currentAppDevice); - - Notification.show("Endgerät erfolgreich aktualisiert: " + updatedDevice.getName(), 3000, - Notification.Position.MIDDLE); - - // Zurück zur Übersicht - navigateBack(); - - } catch (Exception e) { - Notification.show("Fehler beim Aktualisieren des Endgeräts: " + e.getMessage(), 5000, - Notification.Position.MIDDLE); - } - } else { - Notification.show("Bitte füllen Sie alle erforderlichen Felder aus", 3000, Notification.Position.MIDDLE); - } - } - - private void deleteAppDevice() { - if (currentAppDevice != null && currentAppDevice.getId() != null) { - ConfirmDialog confirmDialog = new ConfirmDialog(); - confirmDialog.setHeader("Endgerät löschen"); - confirmDialog.setText("Möchten Sie das Endgerät \"" + currentAppDevice.getName() + "\" wirklich löschen?"); - confirmDialog.setCancelText("Abbrechen"); - confirmDialog.setConfirmText("Löschen"); - confirmDialog.setConfirmButtonTheme("error primary"); - - confirmDialog.addConfirmListener(event -> { - try { - appDeviceService.deleteById(currentAppDevice.getId()); - Notification.show("Endgerät erfolgreich gelöscht", 3000, Notification.Position.MIDDLE); - navigateBack(); - } catch (Exception e) { - Notification.show("Fehler beim Löschen des Endgeräts: " + e.getMessage(), 5000, - Notification.Position.MIDDLE); - } - }); - - confirmDialog.open(); - } - } - - private void navigateBack() { - getUI().ifPresent(ui -> ui.navigate("app-devices")); - } -} diff --git a/src/main/java/de/assecutor/votianlt/pages/view/EditAppUserView.java b/src/main/java/de/assecutor/votianlt/pages/view/EditAppUserView.java index 9e89e81..724b34d 100644 --- a/src/main/java/de/assecutor/votianlt/pages/view/EditAppUserView.java +++ b/src/main/java/de/assecutor/votianlt/pages/view/EditAppUserView.java @@ -2,7 +2,6 @@ package de.assecutor.votianlt.pages.view; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.html.H2; import com.vaadin.flow.component.icon.Icon; @@ -20,15 +19,11 @@ import com.vaadin.flow.router.HasUrlParameter; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import de.assecutor.votianlt.model.AppUser; -import de.assecutor.votianlt.model.AppDevice; import de.assecutor.votianlt.pages.service.AppUserService; -import de.assecutor.votianlt.pages.service.AppDeviceService; import jakarta.annotation.security.RolesAllowed; import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.List; @PageTitle("App-Nutzer bearbeiten") @Route(value = "edit-app-user", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class) @@ -36,7 +31,6 @@ import java.util.List; public class EditAppUserView extends VerticalLayout implements HasUrlParameter { private final AppUserService appUserService; - private final AppDeviceService appDeviceService; private AppUser appUser; private final Binder binder = new Binder<>(AppUser.class); @@ -45,18 +39,13 @@ public class EditAppUserView extends VerticalLayout implements HasUrlParameter deviceComboBox = new ComboBox<>("Endgerät"); - - private ObjectId previousDeviceId; @Autowired - public EditAppUserView(AppUserService appUserService, AppDeviceService appDeviceService) { + public EditAppUserView(AppUserService appUserService) { this.appUserService = appUserService; - this.appDeviceService = appDeviceService; setSizeFull(); setPadding(true); setSpacing(true); @@ -109,7 +98,6 @@ public class EditAppUserView extends VerticalLayout implements HasUrlParameter device.getName()); - deviceComboBox.setPlaceholder("Bitte wählen..."); // Add fields to form formLayout.add(designationField); formLayout.add(nameLayout); formLayout.add(phoneField); - formLayout.add(appCodeField); formLayout.add(emailField); formLayout.add(changePasswordField); formLayout.add(confirmChangePasswordField); - formLayout.add(deviceComboBox); contentContainer.add(formLayout); @@ -163,10 +146,7 @@ public class EditAppUserView extends VerticalLayout implements HasUrlParameter getCurrentDevice(appUser), // Get current device - (appUser, appDevice) -> appUser.setAppDeviceId(appDevice != null ? appDevice.getId() : null)); } @Override @@ -174,10 +154,6 @@ public class EditAppUserView extends VerticalLayout implements HasUrlParameter availableDevices = new ArrayList<>(); - - // First, add the currently assigned device if it exists - AppDevice currentDevice = getCurrentDevice(appUser); - if (currentDevice != null) { - availableDevices.add(currentDevice); - } - - // Then add all unassigned devices - List unassignedDevices = appDeviceService.findUnassignedDevices(); - availableDevices.addAll(unassignedDevices); - - deviceComboBox.setItems(availableDevices); - - // Set the current device as selected - if (currentDevice != null) { - deviceComboBox.setValue(currentDevice); - } - } private void deleteAppUser() { // Show confirmation dialog diff --git a/src/main/java/de/assecutor/votianlt/repository/AppDeviceRepository.java b/src/main/java/de/assecutor/votianlt/repository/AppDeviceRepository.java deleted file mode 100644 index 9786ccd..0000000 --- a/src/main/java/de/assecutor/votianlt/repository/AppDeviceRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package de.assecutor.votianlt.repository; - -import de.assecutor.votianlt.model.AppDevice; -import org.bson.types.ObjectId; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface AppDeviceRepository extends MongoRepository { - - // Find all devices created by a specific user - List findByErstelltVon(ObjectId erstelltVon); - - // Find all devices not assigned to any user - List findByAppUserIdIsNull(); -} diff --git a/src/main/resources/application-production.properties b/src/main/resources/application-production.properties new file mode 100644 index 0000000..6c96786 --- /dev/null +++ b/src/main/resources/application-production.properties @@ -0,0 +1,7 @@ +# Production-specific configuration + +# MongoDB - Production database +spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt + +# Disable browser launch in production +vaadin.launch-browser=false \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index aa699a7..0a45580 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -15,8 +15,8 @@ vaadin.allowed-packages=com.vaadin,org.vaadin,de.assecutor.votianlt # Open-in-view is only needed if you use lazy-loaded entities in your Flow views. spring.jpa.open-in-view=false -# MongoDB -spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt +# MongoDB - Development database by default +spring.data.mongodb.uri=mongodb://192.168.180.25:27017/votianlt_dev spring.data.mongodb.auto-index-creation=true spring.data.mongodb.socket-timeout=30000 spring.data.mongodb.connect-timeout=10000