feat: CategoriesView

fully functional
This commit is contained in:
filippo-ferrari 2024-05-23 23:49:44 +02:00
parent 386687137e
commit 8b9bfedbfe

View file

@ -5,62 +5,109 @@ import com.application.munera.services.CategoryService;
import com.application.munera.views.MainLayout; import com.application.munera.views.MainLayout;
import com.vaadin.flow.component.UI; import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.Uses;
import com.vaadin.flow.component.formlayout.FormLayout; import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.splitlayout.SplitLayout;
import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder; import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.*;
import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
import com.vaadin.flow.router.Route; import org.springframework.data.domain.PageRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.ObjectOptimisticLockingFailureException;
import java.util.Optional; import java.util.Optional;
@PageTitle("Categories") @PageTitle("Categories")
@Route(value = "categories/:categoryID?/:action?(edit)", layout = MainLayout.class) @Route(value = "categories/:categoryID?/:action?(edit)", layout = MainLayout.class)
public class CategoriesView extends VerticalLayout implements BeforeEnterObserver { @Uses(Icon.class)
public class CategoriesView extends Div implements BeforeEnterObserver {
private final String CATEGORY_ID = "categoryID"; private final String CATEGORY_ID = "categoryID";
private final TextField categoryNameField = new TextField("Category Name"); private final String CATEGORY_EDIT_ROUTE_TEMPLATE = "categories/%s/edit";
private final Button addButton = new Button("Add Category");
private final Grid<Category> categoryGrid = new Grid<>(Category.class);
private final Button removeButton = new Button("Remove Category");
@Autowired private final Grid<Category> grid = new Grid<>(Category.class, false);
private final CategoryService categoryService;
private final Button cancel = new Button("Cancel");
private final Button save = new Button("Save");
private final BeanValidationBinder<Category> binder; private final BeanValidationBinder<Category> binder;
private Category category; private Category category;
private final CategoryService categoryService;
private TextField name;
public CategoriesView(CategoryService categoryService) { public CategoriesView(CategoryService categoryService) {
this.categoryService = categoryService; this.categoryService = categoryService;
addClassNames("categories-view");
FormLayout formLayout = new FormLayout(); // Create UI
formLayout.add(categoryNameField, addButton); SplitLayout splitLayout = new SplitLayout();
categoryGrid.setColumns("id", "name"); createGridLayout(splitLayout);
categoryGrid.setItems(categoryService.findAll()); createEditorLayout(splitLayout);
categoryGrid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) { add(splitLayout);
UI.getCurrent().navigate(String.format("/manage-categories/%d/edit", event.getValue().getId()));
} else { // Configure Grid
grid.addColumn(Category::getName).setHeader("Name").setSortable(true);
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.setItems(query -> categoryService.list(
PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query)))
.stream());
grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);
// when a row is selected or deselected, populate form
grid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) UI.getCurrent().navigate(String.format(CATEGORY_EDIT_ROUTE_TEMPLATE, event.getValue().getId()));
else {
clearForm(); clearForm();
UI.getCurrent().navigate(CategoriesView.class); UI.getCurrent().navigate(CategoriesView.class);
} }
}); });
removeButton.setEnabled(false); // Configure Form
removeButton.addClickListener(event -> removeCategory());
addButton.addClickListener(event -> addCategory());
binder = new BeanValidationBinder<>(Category.class); binder = new BeanValidationBinder<>(Category.class);
// Bind fields. This is where you'd define e.g. validation rules
binder.bindInstanceFields(this); binder.bindInstanceFields(this);
add(formLayout, categoryGrid, removeButton); cancel.addClickListener(e -> {
clearForm();
refreshGrid();
});
save.addClickListener(e -> {
try {
if (this.category == null) {
this.category = new Category();
}
binder.writeBean(this.category);
categoryService.update(this.category);
clearForm();
refreshGrid();
Notification.show("Data updated");
UI.getCurrent().navigate(CategoriesView.class);
} catch (ObjectOptimisticLockingFailureException exception) {
Notification n = Notification.show(
"Error updating the data. Somebody else has updated the record while you were making changes.");
n.setPosition(Notification.Position.MIDDLE);
n.addThemeVariants(NotificationVariant.LUMO_ERROR);
} catch (ValidationException validationException) {
Notification.show("Failed to update the data. Check again that all values are valid");
}
});
} }
@Override @Override
@ -77,27 +124,47 @@ public class CategoriesView extends VerticalLayout implements BeforeEnterObserve
// when a row is selected but the data is no longer available, // when a row is selected but the data is no longer available,
// refresh grid // refresh grid
refreshGrid(); refreshGrid();
event.forwardTo(ExpensesView.class); event.forwardTo(CategoriesView.class);
} }
} }
} }
private void addCategory() { private void createEditorLayout(SplitLayout splitLayout) {
Category newCategory = new Category(); Div editorLayoutDiv = new Div();
binder.writeBeanIfValid(newCategory); editorLayoutDiv.setClassName("editor-layout");
categoryService.update(newCategory);
refreshGrid(); Div editorDiv = new Div();
Notification.show("Category added successfully"); editorDiv.setClassName("editor");
editorLayoutDiv.add(editorDiv);
FormLayout formLayout = new FormLayout();
name = new TextField("Name");
formLayout.add(name);
editorDiv.add(formLayout);
createButtonLayout(editorLayoutDiv);
splitLayout.addToSecondary(editorLayoutDiv);
} }
private void removeCategory() { private void createButtonLayout(Div editorLayoutDiv) {
if (category != null) { HorizontalLayout buttonLayout = new HorizontalLayout();
categoryService.delete(category); buttonLayout.setClassName("button-layout");
clearForm(); cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
refreshGrid(); save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
Notification.show("Category removed successfully"); buttonLayout.add(save, cancel);
UI.getCurrent().navigate(CategoriesView.class); editorLayoutDiv.add(buttonLayout);
} }
private void createGridLayout(SplitLayout splitLayout) {
Div wrapper = new Div();
wrapper.setClassName("grid-wrapper");
splitLayout.addToPrimary(wrapper);
wrapper.add(grid);
}
private void refreshGrid() {
grid.select(null);
grid.getDataProvider().refreshAll();
} }
private void clearForm() { private void clearForm() {
@ -107,9 +174,6 @@ public class CategoriesView extends VerticalLayout implements BeforeEnterObserve
private void populateForm(Category value) { private void populateForm(Category value) {
this.category = value; this.category = value;
binder.readBean(this.category); binder.readBean(this.category);
}
private void refreshGrid() {
categoryGrid.setItems(categoryService.findAll());
} }
} }