All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.imunity.furms.ui.views.user_settings.projects.ProjectsView Maven / Gradle / Ivy

There is a newer version: 4.3.1
Show newest version
/*
 * Copyright (c) 2020 Bixbit s.c. All rights reserved.
 * See LICENSE file for licensing information.
 */

package io.imunity.furms.ui.views.user_settings.projects;

import com.google.common.collect.ImmutableList;
import com.vaadin.componentfactory.Tooltip;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridSortOrder;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.SortDirection;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLink;
import io.imunity.furms.api.applications.ProjectApplicationsService;
import io.imunity.furms.api.projects.ProjectService;
import io.imunity.furms.api.validation.exceptions.UserAlreadyInvitedException;
import io.imunity.furms.api.validation.exceptions.UserWithoutFenixIdValidationError;
import io.imunity.furms.domain.communities.CommunityId;
import io.imunity.furms.domain.projects.Project;
import io.imunity.furms.domain.projects.ProjectId;
import io.imunity.furms.ui.components.DenseGrid;
import io.imunity.furms.ui.components.FurmsDialog;
import io.imunity.furms.ui.components.FurmsViewComponent;
import io.imunity.furms.ui.components.GridActionMenu;
import io.imunity.furms.ui.components.GridActionsButtonLayout;
import io.imunity.furms.ui.components.MenuButton;
import io.imunity.furms.ui.components.PageTitle;
import io.imunity.furms.ui.components.RouterGridLink;
import io.imunity.furms.ui.components.ViewHeaderLayout;
import io.imunity.furms.ui.utils.CommonExceptionsHandler;
import io.imunity.furms.ui.views.user_settings.UserSettingsMenu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.invoke.MethodHandles;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.vaadin.flow.component.icon.VaadinIcon.MINUS_CIRCLE;
import static com.vaadin.flow.component.icon.VaadinIcon.PIE_CHART;
import static com.vaadin.flow.component.icon.VaadinIcon.PLUS_CIRCLE;
import static com.vaadin.flow.component.icon.VaadinIcon.SEARCH;
import static com.vaadin.flow.component.icon.VaadinIcon.TRASH;
import static io.imunity.furms.ui.utils.NotificationUtils.showErrorNotification;
import static io.imunity.furms.ui.utils.NotificationUtils.showSuccessNotification;
import static io.imunity.furms.ui.utils.VaadinExceptionHandler.handleExceptions;
import static io.imunity.furms.ui.views.user_settings.projects.UserStatus.ACTIVE;
import static io.imunity.furms.ui.views.user_settings.projects.UserStatus.REQUESTED;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

@Route(value = "users/settings/projects", layout = UserSettingsMenu.class)
@PageTitle(key = "view.user-settings.projects.page.title")
public class ProjectsView extends FurmsViewComponent {
	private final static Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

	private final ProjectService projectService;
	private final ProjectApplicationsService projectApplicationsService;
	private final ProjectGridModelMapper mapper;
	private final Grid grid;
	private final Set currentFilters = new HashSet<>();
	private String searchText = "";

	ProjectsView(ProjectService projectService, ProjectApplicationsService projectApplicationsService) {
		this.projectService = projectService;
		this.projectApplicationsService = projectApplicationsService;
		this.mapper = new ProjectGridModelMapper(projectService, projectApplicationsService);
		this.grid = createProjectGrid();

		CheckboxGroup checkboxGroup = createCheckboxLayout();
		loadGridContent();
		getContent().add(createHeaderLayout(checkboxGroup), createSearchFilterLayout(), grid);
	}

	private CheckboxGroup createCheckboxLayout() {
		CheckboxGroup checkboxGroup = new CheckboxGroup<>();
		checkboxGroup.setLabel(getTranslation("view.user-settings.projects.filter.title"));
		checkboxGroup.setItems(UserStatus.values());
		checkboxGroup.setItemLabelGenerator(x -> getTranslation(x.filterText));
		checkboxGroup.select(ACTIVE, REQUESTED);
		currentFilters.add(ACTIVE);
		currentFilters.add(REQUESTED);
		checkboxGroup.addSelectionListener(event -> {
			currentFilters.clear();
			currentFilters.addAll(event.getAllSelectedItems());
			loadGridContent();
		});

		checkboxGroup.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
		return checkboxGroup;
	}

	private HorizontalLayout createHeaderLayout(CheckboxGroup checkboxGroup) {
		return new ViewHeaderLayout(getTranslation("view.user-settings.projects.header"), checkboxGroup);
	}

	private HorizontalLayout createSearchFilterLayout() {
		TextField textField = new TextField();
		textField.setPlaceholder(getTranslation("view.user-settings.projects.field.search"));
		textField.setPrefixComponent(SEARCH.create());
		textField.setValueChangeMode(ValueChangeMode.EAGER);
		textField.setClearButtonVisible(true);
		textField.addValueChangeListener(event -> {
			searchText = textField.getValue().toLowerCase();
			textField.blur();
			loadGridContent();
			textField.focus();
		});

		HorizontalLayout search = new HorizontalLayout(textField);
		search.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
		return search;
	}

	private Grid createProjectGrid() {
		Grid grid = new DenseGrid<>(ProjectGridModel.class);

		Grid.Column firstColumn = grid.addComponentColumn(project -> {
			Component component = new Span(project.name);
			if (project.status.equals(ACTIVE))
				component = new RouterLink(project.name, ProjectView.class, project.id.id.toString());
			return component;
		})
			.setHeader(getTranslation("view.user-settings.projects.grid.column.1"))
			.setSortable(true)
			.setComparator(comparing(project -> project.name))
			.setComparator(project -> project.name.toLowerCase());
		grid.addColumn(project -> project.description)
			.setHeader(getTranslation("view.user-settings.projects.grid.column.2"))
			.setSortable(true);
		grid.addColumn(project -> getTranslation(project.status.gridText))
			.setHeader(getTranslation("view.user-settings.projects.grid.column.3"))
			.setTextAlign(ColumnTextAlign.END)
			.setSortable(true);
		grid.addComponentColumn(this::createLastColumnContent)
			.setHeader(getTranslation("view.user-settings.projects.grid.column.4"))
			.setTextAlign(ColumnTextAlign.END);
		grid.sort(ImmutableList.of(new GridSortOrder<>(firstColumn, SortDirection.ASCENDING)));
		grid.setAllRowsVisible(false);
		return grid;
	}

	private HorizontalLayout createLastColumnContent(ProjectGridModel project) {
		switch (project.status) {
			case ACTIVE:
				return new GridActionsButtonLayout(
					new RouterGridLink(PIE_CHART, project.id.id.toString(), ProjectView.class),
					createContextMenu(project.id, project.name, project.communityId)
				);
			case NOT_ACTIVE:
				MenuButton applyButton = new MenuButton(PLUS_CIRCLE);
				applyButton.addClickListener(x -> {
					try {
						projectApplicationsService.createForCurrentUser(project.id);
						showSuccessNotification(getTranslation("view.user-settings.projects.applied.notification", project.name));
						loadGridContent();
					} catch (UserAlreadyInvitedException e){
						showErrorNotification(getTranslation("user.already.invited"));
					} catch (Exception e){
						showErrorNotification(getTranslation("base.error.message"));
						throw e;
					}
				});
				return new GridActionsButtonLayout(addApplyTooltip(applyButton));
			case REQUESTED:
				MenuButton removeApplicationButton = new MenuButton(TRASH);
				removeApplicationButton.addClickListener(x -> {
					try {
						projectApplicationsService.removeForCurrentUser(project.id);
					} catch (RuntimeException e){
						boolean handled = CommonExceptionsHandler.showExceptionBasedNotificationError(e);
						if(!handled)
							LOG.error("Could not remove application.");
					}
					loadGridContent();
				});
				return new GridActionsButtonLayout(removeApplicationButton);
			default:
				throw new RuntimeException("This should not happened");
		}
	}

	private MenuButton addApplyTooltip(MenuButton menuButton) {
		Tooltip tooltip = new Tooltip();
		tooltip.add(getTranslation("view.user-settings.projects.apply"));
		tooltip.attachToComponent(menuButton);
		getContent().add(tooltip);
		return menuButton;
	}

	private Component createContextMenu(ProjectId projectId, String projectName, CommunityId communityId) {
		GridActionMenu contextMenu = new GridActionMenu();
		Dialog confirmDialog = createConfirmDialog(projectId, projectName, communityId);

		contextMenu.addItem(new MenuButton(
				getTranslation("view.user-settings.projects.context.menu.leave"), MINUS_CIRCLE),
			event -> confirmDialog.open()
		);

		MenuButton allocationComponent = new MenuButton(
			getTranslation("view.user-settings.projects.menu.allocations"),
			PIE_CHART
		);

		RouterLink allocationsPool = new RouterGridLink(allocationComponent, projectId.id.toString(), ProjectView.class);
		contextMenu.addItem(allocationsPool);
		getContent().add(contextMenu);
		return contextMenu.getTarget();
	}

	private Dialog createConfirmDialog(ProjectId projectId, String projectName, CommunityId communityId) {
		FurmsDialog furmsDialog = new FurmsDialog(getTranslation("view.user-settings.projects.dialog.text", projectName));
		furmsDialog.addConfirmButtonClickListener(event -> {
			try {
				projectService.resignFromMembership(communityId, projectId);
				loadGridContent();
			} catch (Exception e){
				showErrorNotification("base.error.message");
			}
		});
		return furmsDialog;
	}

	private void loadGridContent() {
		grid.setItems(loadProjectsViewsModels());
	}

	private List loadProjectsViewsModels() {
		try {
			Set projects = handleExceptions(() -> projectService.findAll())
				.orElseGet(Collections::emptySet);
			return mapper.map(projects)
				.stream()
				.sorted(comparing(projectViewModel -> projectViewModel.name.toLowerCase()))
				.filter(project -> currentFilters.contains(project.status))
				.filter(project -> searchText.isEmpty() || project.matches(searchText))
				.collect(toList());
		} catch (UserWithoutFenixIdValidationError e) {
			showErrorNotification(getTranslation("user.without.fenixid.error.message"));
		}
		return List.of();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy