diff --git a/user-interface/frontend/themes/datamanager/components/div.css b/user-interface/frontend/themes/datamanager/components/div.css index 946b01b6e..64a133b1a 100644 --- a/user-interface/frontend/themes/datamanager/components/div.css +++ b/user-interface/frontend/themes/datamanager/components/div.css @@ -36,6 +36,21 @@ align-items: baseline; } +.card-layout { + background-color: var(--lumo-base-color); + border: var(--lumo-contrast-10pct); + border-radius: var(--lumo-border-radius-m); + box-shadow: var(--lumo-box-shadow-l); + font-size: var(--lumo-font-size-s); + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: var(--lumo-space-s); + width: clamp(300px, 300px, 15vw); + padding-bottom: var(--lumo-space-l); + padding-inline: var(--lumo-space-l); +} + .disclaimer { display: flex; justify-content: center; @@ -162,18 +177,3 @@ gap: var(--lumo-space-xs); white-space: nowrap; } - -.user-registration-component { - background-color: var(--lumo-base-color); - border: var(--lumo-contrast-10pct); - border-radius: var(--lumo-border-radius-m); - box-shadow: var(--lumo-box-shadow-l); - font-size: var(--lumo-font-size-s); - box-sizing: border-box; - display: flex; - flex-direction: column; - gap: var(--lumo-space-s); - width: clamp(300px, 300px, 15vw); - padding-bottom: var(--lumo-space-l); - padding-inline: var(--lumo-space-l); -} diff --git a/user-interface/frontend/themes/datamanager/components/main.css b/user-interface/frontend/themes/datamanager/components/main.css index fd796bd99..c50ed3a96 100644 --- a/user-interface/frontend/themes/datamanager/components/main.css +++ b/user-interface/frontend/themes/datamanager/components/main.css @@ -425,6 +425,22 @@ grid-area: sampledetails; } +.main.reset-password { + grid-template-columns: auto; + grid-template-rows: auto; + justify-content: center; + /*Should be moved to the parent layout once Login and forgot password components are overhauled*/ + padding-bottom: var(--lumo-space-m); +} + +.main.set-new-password { + grid-template-columns: auto; + grid-template-rows: auto; + justify-content: center; + /*Should be moved to the parent layout once Login and forgot password components are overhauled*/ + padding-bottom: var(--lumo-space-m); +} + .main.user-profile { grid-template-columns: minmax(min-content, auto); grid-template-rows: minmax(min-content, auto); @@ -432,6 +448,14 @@ "user-profile-component" } +.main.user-registration { + grid-template-columns: auto; + grid-template-rows: auto; + justify-content: center; + /*Should be moved to the parent layout once Login and forgot password components are overhauled*/ + padding-bottom: var(--lumo-space-m); +} + /*Large devices (large desktops, 1200px and up)*/ @media only screen and (max-width: 1200px) { .main.experiment { diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/landing/LandingPageLayout.java b/user-interface/src/main/java/life/qbic/datamanager/views/landing/LandingPageLayout.java index c5dffef3f..732892522 100644 --- a/user-interface/src/main/java/life/qbic/datamanager/views/landing/LandingPageLayout.java +++ b/user-interface/src/main/java/life/qbic/datamanager/views/landing/LandingPageLayout.java @@ -3,7 +3,6 @@ import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasElement; import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; @@ -65,7 +64,7 @@ private HorizontalLayout createHeaderButtonLayout() { } private void styleHeaderButtons() { - login.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + login.addClassName("primary"); } /** diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/layouts/BoxLayout.java b/user-interface/src/main/java/life/qbic/datamanager/views/layouts/BoxLayout.java deleted file mode 100644 index 9ba8cce32..000000000 --- a/user-interface/src/main/java/life/qbic/datamanager/views/layouts/BoxLayout.java +++ /dev/null @@ -1,182 +0,0 @@ -package life.qbic.datamanager.views.layouts; - -import com.vaadin.flow.component.Component; -import com.vaadin.flow.component.Text; -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.html.Span; -import com.vaadin.flow.component.orderedlayout.FlexComponent; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import life.qbic.datamanager.views.notifications.DisplayMessage; - -/** - * Box Layout - * - *
A box with a shadow containing a title, description, a layout for fields, a layout for buttons - * and a span to add links. - * Furthermore, the description text can be toggled visible or invisible - * - * @since 1.0.0 - */ -public class BoxLayout extends VerticalLayout { - - private H2 layoutTitle; - private Text descriptionText; - private VerticalLayout notificationLayout; - private VerticalLayout fieldLayout; - private VerticalLayout textLayout; - private VerticalLayout buttonLayout; - private Span linkSpan; - - private final VerticalLayout contentLayout; - - public BoxLayout() { - this.addClassName("grid"); - contentLayout = new VerticalLayout(); - - initLayout(); - styleLayout(); - } - - private void initLayout() { - layoutTitle = new H2("Set Title"); - - textLayout = new VerticalLayout(); - descriptionText = new Text("Enter description text"); - textLayout.add(descriptionText); - notificationLayout = new VerticalLayout(); - fieldLayout = new VerticalLayout(); - buttonLayout = new VerticalLayout(); - - linkSpan = new Span(); - add(contentLayout); - } - - private void styleLayout() { - styleNotificationLayout(); - styleFieldLayout(); - styleFormLayout(); - styleButtonLayout(); - styleDescriptionText(); - - setSizeFull(); - setAlignItems(FlexComponent.Alignment.CENTER); - setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER); - } - - private void styleFormLayout() { - contentLayout.setPadding(false); - contentLayout.setMargin(false); - contentLayout.addClassNames( - "bg-base", - "border", - "rounded-m", - "border-contrast-10", - "box-border", - "flex", - "flex-col", - "w-full", - "text-s", - "shadow-l", - "min-width-300px", - "max-width-15vw", - "pb-l", - "pr-l", - "pl-l"); - contentLayout.add(layoutTitle, notificationLayout, descriptionText, fieldLayout, buttonLayout, - linkSpan); - } - - private void styleFieldLayout() { - fieldLayout.setSpacing(false); - fieldLayout.setMargin(false); - fieldLayout.setPadding(false); - } - - private void styleButtonLayout() { - buttonLayout.setSpacing(false); - buttonLayout.setMargin(false); - buttonLayout.setPadding(false); - } - - private void styleNotificationLayout() { - notificationLayout.setSpacing(false); - notificationLayout.setMargin(false); - notificationLayout.setPadding(false); - } - - private void styleDescriptionText() { - textLayout.addClassName("text-contrast-70"); - } - - /** - * Sets the title text - * - * @param text The text for the title - */ - public void setTitleText(String text) { - layoutTitle.setText(text); - } - - /** - * Adds the field components to the field layout - * - * @param fields The fields could be TextFields, EmailFields, PasswordFields - */ - public void addFields(Component... fields) { - fieldLayout.add(fields); - } - - /** - * Adds buttons to the button layout - * - * @param buttons The buttons that need to be part of the layout - */ - public void addButtons(Button... buttons) { - buttonLayout.add(buttons); - } - - /** - * Sets the description text - * - * @param text The text that allows to enter a description of the process - */ - public void setDescriptionText(String text) { - descriptionText.setText(text); - } - - /** - * Adds a DisplayMessage {@link DisplayMessage} based notification to the BoxLayout - * - * @param displayMessage The notification to be shown to the viewer. - */ - public void setNotification(DisplayMessage displayMessage) { - notificationLayout.add(displayMessage); - } - - /** - * Removes all DisplayMessage {@link DisplayMessage} based Notifications from the BoxLayout - */ - public void removeNotifications() { - notificationLayout.removeAll(); - } - - /** - * Toggles the description text visible or invisible - * - * @param visible The visibility status of the text - */ - public void setDescriptionTextVisible(boolean visible) { - descriptionText.setVisible(visible); - } - - /** - * Span that will hold content like small texts and links that should be not so present as a - * button - * - * @param components Components like Text, RouterLink, or Tertiary Buttons - */ - public void addLinkSpanContent(Component... components) { - linkSpan.add(components); - } -} diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordHandler.java b/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordHandler.java deleted file mode 100644 index ec4f3b7f0..000000000 --- a/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package life.qbic.datamanager.views.login.newpassword; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * Handles setting new passwords - * - *
When a new password is set the handler triggers the use case to update the users password
- * - * @since 1.0.0 - */ -@Component -public class NewPasswordHandler { - - private final String passwordResetQueryParameter; - - @Autowired - NewPasswordHandler(@Value("${routing.password-reset.reset-parameter}") String newPasswordParam) { - this.passwordResetQueryParameter = newPasswordParam; - } - - public String passwordResetQueryParameter() { - return passwordResetQueryParameter; - } - -} diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordLayout.java b/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordLayout.java deleted file mode 100644 index b2c741e74..000000000 --- a/user-interface/src/main/java/life/qbic/datamanager/views/login/newpassword/NewPasswordLayout.java +++ /dev/null @@ -1,198 +0,0 @@ -package life.qbic.datamanager.views.login.newpassword; - -import static life.qbic.logging.service.LoggerFactory.logger; - -import com.vaadin.flow.component.Key; -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.button.ButtonVariant; -import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.PasswordField; -import com.vaadin.flow.router.BeforeEvent; -import com.vaadin.flow.router.HasUrlParameter; -import com.vaadin.flow.router.OptionalParameter; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; -import com.vaadin.flow.server.auth.AnonymousAllowed; -import com.vaadin.flow.spring.annotation.UIScope; -import java.io.Serial; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Predicate; -import life.qbic.application.commons.Result; -import life.qbic.datamanager.views.AppRoutes; -import life.qbic.datamanager.views.landing.LandingPageLayout; -import life.qbic.datamanager.views.layouts.BoxLayout; -import life.qbic.identity.application.user.IdentityService; -import life.qbic.identity.domain.model.EncryptedPassword.PasswordValidationException; -import life.qbic.logging.api.Logger; -import org.apache.commons.lang3.NotImplementedException; -import org.springframework.beans.factory.annotation.Autowired; - - -/** - * Defines the look of the password reset layout. - * - * @since 1.0.0 - */ -@PageTitle("New Password") -@Route(value = AppRoutes.NEW_PASSWORD, layout = LandingPageLayout.class) -@AnonymousAllowed -@UIScope -public class NewPasswordLayout extends VerticalLayout implements HasUrlParameter
+ * Card Stylized component similar to {@link com.vaadin.flow.component.login.LoginOverlay}
+ * component. Informing the user that a reset password email was sent and directing her to the login
+ * layout
+ */
+@SpringComponent
+@UIScope
+public class NewPasswordSetComponent extends Div {
+
+ @Serial
+ private static final long serialVersionUID = -1138757655198857262L;
+
+ private final Button loginButton = new Button("Login");
+
+ public NewPasswordSetComponent() {
+ addClassName("new-password-set-component");
+ loginButton.addClassName("primary");
+ Div introduction = new Div();
+ introduction.add("You can now log in with your new password.");
+ introduction.addClassName("introduction");
+ H2 titleSpan = new H2("New Password saved!");
+ addClassName("card-layout");
+ add(titleSpan, introduction, loginButton);
+ }
+
+ public void addLoginButtonListener(ComponentEventListener
+ * Card Stylized component similar to {@link com.vaadin.flow.component.login.LoginOverlay}
+ * component. Informing the user that a reset password email was sent and directing her to the login
+ * layout
+ */
+@SpringComponent
+@UIScope
+public class ResetEmailSentComponent extends Div {
+
+ @Serial
+ private static final long serialVersionUID = -1138757655198857262L;
+
+ private final Button loginButton = new Button("Login");
+
+
+ public ResetEmailSentComponent() {
+ loginButton.addClassName("primary");
+ Div introduction = new Div();
+ introduction.add("Please check your inbox and follow the instructions to reset your password.");
+ introduction.addClassName("introduction");
+ H2 titleSpan = new H2("Email has been sent");
+ addClassName("card-layout");
+ add(titleSpan, introduction, loginButton);
+ }
+
+ public void addLoginButtonListener(ComponentEventListener
+ * Card Stylized component similar to {@link com.vaadin.flow.component.login.LoginOverlay}
+ * component, Providing the input fields necessary to enable a user to specify his email for which
+ * the password should be reset
+ */
+@SpringComponent
+@UIScope
+public class ResetPasswordComponent extends Div {
+
+ @Serial
+ private static final long serialVersionUID = 6918803421532658723L;
+
+ /*Validation via Binder does not show error message if an email field is used, see
+ * https://github.com/vaadin/flow-components/issues/4618 for details */
+ private final TextField emailField = new TextField("Email");
+ private final Button confirmButton = new Button("Send");
+ private final Div notificationLayout = new Div();
+ private final Binder
+ * Card Stylized component similar to {@link com.vaadin.flow.component.login.LoginOverlay}
+ * component, Providing the input fields necessary to enable a user to set a new password
+ */
+@AnonymousAllowed
+@UIScope
+@SpringComponent
+public class SetNewPasswordComponent extends Div {
+
+ @Serial
+ private static final long serialVersionUID = 4482422913026333378L;
+
+ private final PasswordField password = new PasswordField("Password");
+
+ private final Button confirmButton = new Button("Confirm");
+
+ private final Div notificationLayout = new Div();
+
+ private final Binder
+ * Main component hosting the components necessary for a user to reset her password {@link SetNewPasswordComponent} a
+ * and informing her that her provided input is now set as a new password for her account
+ * {@link NewPasswordSetComponent}
+ * component.
+ */
+@PageTitle("New Password")
+@Route(value = AppRoutes.NEW_PASSWORD, layout = LandingPageLayout.class)
+@AnonymousAllowed
+@UIScope
+@SpringComponent
+public class SetNewPasswordMain extends Main implements HasUrlParametertrue
if the event originated from the client
+ * side, false
otherwise
+ */
+ public ResetPasswordEvent(ResetPasswordComponent source, boolean fromClient, String email) {
+ super(source, fromClient);
+ this.email = email;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+ }
+}
diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordLayout.java b/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordLayout.java
deleted file mode 100644
index 9c422693b..000000000
--- a/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordLayout.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package life.qbic.datamanager.views.login.passwordreset;
-
-import com.vaadin.flow.component.Key;
-import com.vaadin.flow.component.Text;
-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.orderedlayout.FlexComponent;
-import com.vaadin.flow.component.orderedlayout.VerticalLayout;
-import com.vaadin.flow.component.textfield.EmailField;
-import com.vaadin.flow.router.PageTitle;
-import com.vaadin.flow.router.Route;
-import com.vaadin.flow.router.RouterLink;
-import com.vaadin.flow.server.auth.AnonymousAllowed;
-import com.vaadin.flow.spring.annotation.UIScope;
-import java.util.Objects;
-import life.qbic.application.commons.ApplicationResponse;
-import life.qbic.datamanager.views.AppRoutes;
-import life.qbic.datamanager.views.landing.LandingPageLayout;
-import life.qbic.datamanager.views.layouts.BoxLayout;
-import life.qbic.datamanager.views.notifications.ErrorMessage;
-import life.qbic.datamanager.views.register.UserRegistrationMain;
-import life.qbic.identity.application.user.IdentityService;
-import life.qbic.identity.application.user.UserNotFoundException;
-import life.qbic.identity.domain.model.EmailAddress;
-import org.springframework.beans.factory.annotation.Autowired;
-
-
-/**
- * Defines the look of the password reset layout.
- *
- * @since 1.0.0
- */
-@PageTitle("Reset Password")
-@Route(value = AppRoutes.RESET_PASSWORD, layout = LandingPageLayout.class)
-@AnonymousAllowed
-@UIScope
-public class ResetPasswordLayout extends VerticalLayout {
-
- private final IdentityService identityService;
- public EmailField email;
- public Button sendButton;
- public Span registerSpan;
- public BoxLayout enterEmailLayout;
- public LinkSentLayout linkSentLayout;
-
- public ResetPasswordLayout(@Autowired IdentityService identityService) {
- this.identityService = Objects.requireNonNull(identityService);
- initLayout();
- styleLayout();
- addClickListeners();
- }
-
-
- private void initLayout() {
- initLinkSentLayout();
-
- initEnterEmailLayout();
-
- add(enterEmailLayout, linkSentLayout);
- }
-
- private void initEnterEmailLayout() {
- enterEmailLayout = new BoxLayout();
-
- enterEmailLayout.setTitleText("Reset password");
- enterEmailLayout.setDescriptionText(
- "Enter the mail address associated with your account and we'll send you a link to reset your password:");
-
- email = new EmailField("Email");
- enterEmailLayout.addFields(email);
-
- createSendButton();
- enterEmailLayout.addButtons(sendButton);
-
- createSpan();
- enterEmailLayout.addLinkSpanContent(registerSpan);
- }
-
- private void initLinkSentLayout() {
- linkSentLayout = new LinkSentLayout();
- linkSentLayout.setVisible(false);
- }
-
- private void styleLayout() {
-
- styleFieldLayout();
- styleSendButton();
- setAlignItems(FlexComponent.Alignment.CENTER);
- setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
- }
-
- private void createSpan() {
- RouterLink routerLink = new RouterLink("Register", UserRegistrationMain.class);
- registerSpan = new Span(new Text("Don't have an account? "), routerLink);
- registerSpan.addClassName("registration-link");
- }
-
- private void createSendButton() {
- sendButton = new Button("Send");
- }
-
- private void styleFieldLayout() {
- email.setWidthFull();
- }
-
- private void styleSendButton() {
- sendButton.setWidthFull();
- sendButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
- }
-
- private void addClickListeners() {
- sendButton.addClickListener(
- buttonClickEvent -> {
- clearNotifications();
- resetPassword(email.getValue());
- });
- sendButton.addClickShortcut(Key.ENTER);
-
- linkSentLayout.loginButton.addClickListener(
- buttonClickEvent ->
- linkSentLayout
- .getUI()
- .ifPresent(ui -> ui.navigate("login")));
- }
-
- private void resetPassword(String value) {
- var response = identityService.requestPasswordReset(value);
- if (response.hasFailures()) {
- onPasswordResetFailed(response);
- } else {
- onPasswordResetSucceeded();
- }
- }
-
- public void clearNotifications() {
- enterEmailLayout.removeNotifications();
- }
-
- public void showError(String title, String description) {
- clearNotifications();
- ErrorMessage errorMessage = new ErrorMessage(title, description);
- enterEmailLayout.setNotification(errorMessage);
- }
-
- private void showPasswordResetFailedError(String error, String description) {
- showError(error, description);
- }
-
- public void onPasswordResetSucceeded() {
- linkSentLayout.setVisible(true);
- enterEmailLayout.setVisible(false);
- }
-
- public void onPasswordResetFailed(ApplicationResponse response) {
- for (RuntimeException failure : response.failures()) {
- if (failure instanceof EmailAddress.EmailValidationException) {
- showPasswordResetFailedError("Invalid mail address format",
- "Please provide a valid mail address.");
- } else if (failure instanceof UserNotFoundException) {
- showPasswordResetFailedError(
- "User not found", "No user with the provided mail address is known.");
- } else if (failure instanceof IdentityService.UserNotActivatedException) {
- showPasswordResetFailedError("User not active",
- "Please activate your account first to reset the password.");
- } else {
- showPasswordResetFailedError(
- "An unexpected error occurred", "Please contact support@qbic.zendesk.com for help.");
- }
- }
- }
-}
diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordMain.java b/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordMain.java
new file mode 100644
index 000000000..32d906b1e
--- /dev/null
+++ b/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/ResetPasswordMain.java
@@ -0,0 +1,117 @@
+package life.qbic.datamanager.views.login.passwordreset;
+
+import com.vaadin.flow.component.UI;
+import com.vaadin.flow.router.BeforeEnterEvent;
+import com.vaadin.flow.router.BeforeEnterObserver;
+import com.vaadin.flow.router.PageTitle;
+import com.vaadin.flow.router.Route;
+import com.vaadin.flow.server.auth.AnonymousAllowed;
+import com.vaadin.flow.spring.annotation.UIScope;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import life.qbic.datamanager.views.AppRoutes;
+import life.qbic.datamanager.views.general.Main;
+import life.qbic.datamanager.views.landing.LandingPageLayout;
+import life.qbic.identity.application.user.IdentityService;
+import life.qbic.identity.application.user.UserNotFoundException;
+import life.qbic.identity.domain.model.EmailAddress.EmailValidationException;
+import life.qbic.logging.api.Logger;
+import life.qbic.logging.service.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Defines the look of the password reset layout.
+ * It hosts the {@link ResetPasswordComponent} to enable the user to input the email account which
+ * should receive a password reset email and a {@link ResetEmailSentComponent} component informing
+ * the user that an email has been sent to the provided email account /b>
+ *
+ * @since 1.0.0
+ */
+@PageTitle("Reset Password")
+@Route(value = AppRoutes.RESET_PASSWORD, layout = LandingPageLayout.class)
+@AnonymousAllowed
+@UIScope
+public class ResetPasswordMain extends Main implements BeforeEnterObserver {
+
+ private static final Logger log =
+ LoggerFactory.logger(ResetPasswordMain.class.getName());
+ private final transient IdentityService identityService;
+ private final ResetEmailSentComponent resetEmailSentComponent;
+ private final ResetPasswordComponent resetPasswordComponent;
+
+ public ResetPasswordMain(@Autowired IdentityService identityService,
+ @Autowired ResetPasswordComponent resetPasswordComponent,
+ @Autowired ResetEmailSentComponent resetEmailSentComponent) {
+ this.identityService = Objects.requireNonNull(identityService,
+ "Identity service cannot be null");
+ this.resetPasswordComponent = Objects.requireNonNull(resetPasswordComponent,
+ "ResetPasswordComponent cannot be null");
+ this.resetEmailSentComponent = Objects.requireNonNull(resetEmailSentComponent,
+ "ResetEmailSentComponent cannot be null");
+ resetPasswordComponent.addResetPasswordListener(event -> resetPassword(event.getEmail()));
+ resetEmailSentComponent.addLoginButtonListener(event -> {
+ UI.getCurrent().navigate(AppRoutes.LOGIN);
+ resetEmailSentComponent.setVisible(false);
+ resetPasswordComponent.setVisible(true);
+ });
+ addClassName("reset-password");
+ add(resetEmailSentComponent, resetPasswordComponent);
+ log.debug(String.format(
+ "New instance for %s(#%s) created with %s(#%s) and %s(#%s)",
+ this.getClass().getSimpleName(), System.identityHashCode(this),
+ resetPasswordComponent.getClass().getSimpleName(),
+ System.identityHashCode(resetPasswordComponent),
+ resetEmailSentComponent.getClass().getSimpleName(),
+ System.identityHashCode(resetEmailSentComponent)));
+ }
+
+ private void resetPassword(String email) {
+ identityService.requestPasswordReset(email)
+ .ifSuccessOrElse(response -> {
+ resetPasswordComponent.clearNotifications();
+ resetPasswordComponent.setVisible(false);
+ resetEmailSentComponent.setVisible(true);
+ }, response -> handleRegistrationFailure(response.failures()));
+ }
+
+ private void handleRegistrationFailure(Listtrue
if the event originated from the client
+ * side, false
otherwise
+ */
+ public SetNewPasswordEvent(SetNewPasswordComponent source, boolean fromClient,
+ String password) {
+ super(source, fromClient);
+ this.password = password;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+ }
+}
diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/SetNewPasswordMain.java b/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/SetNewPasswordMain.java
new file mode 100644
index 000000000..791d1df9c
--- /dev/null
+++ b/user-interface/src/main/java/life/qbic/datamanager/views/login/passwordreset/SetNewPasswordMain.java
@@ -0,0 +1,128 @@
+package life.qbic.datamanager.views.login.passwordreset;
+
+import static life.qbic.logging.service.LoggerFactory.logger;
+
+import com.vaadin.flow.router.BeforeEvent;
+import com.vaadin.flow.router.HasUrlParameter;
+import com.vaadin.flow.router.OptionalParameter;
+import com.vaadin.flow.router.PageTitle;
+import com.vaadin.flow.router.Route;
+import com.vaadin.flow.server.auth.AnonymousAllowed;
+import com.vaadin.flow.spring.annotation.SpringComponent;
+import com.vaadin.flow.spring.annotation.UIScope;
+import java.io.Serial;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+import life.qbic.application.commons.Result;
+import life.qbic.datamanager.views.AppRoutes;
+import life.qbic.datamanager.views.general.Main;
+import life.qbic.datamanager.views.landing.LandingPageLayout;
+import life.qbic.datamanager.views.login.LoginLayout;
+import life.qbic.datamanager.views.login.passwordreset.SetNewPasswordComponent.SetNewPasswordEvent;
+import life.qbic.identity.application.user.IdentityService;
+import life.qbic.identity.domain.model.EncryptedPassword.PasswordValidationException;
+import life.qbic.logging.api.Logger;
+import org.apache.commons.lang3.NotImplementedException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+
+/**
+ * Set New Password Main
+ *