fix: ExpensesView

This commit is contained in:
Filippo Ferrari 2024-05-20 23:28:44 +02:00
parent 2e97e866d5
commit d3808cce7d

View file

@ -1,207 +1,46 @@
package com.application.munera.views.expenses;
import com.application.munera.data.Category;
import com.application.munera.data.Expense;
import com.application.munera.services.ExpenseService;
import com.application.munera.repositories.ExpenseRepository;
import com.application.munera.views.MainLayout;
import com.vaadin.flow.component.UI;
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.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.Position;
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.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.*;
import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import jakarta.annotation.security.PermitAll;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Optional;
import java.util.List;
@PageTitle("Expenses")
@Route(value = "/:samplePersonID?/:action?(edit)", layout = MainLayout.class)
@RouteAlias(value = "", layout = MainLayout.class)
@Uses(Icon.class)
public class ExpensesView extends Div implements BeforeEnterObserver {
@Route(value = "expenses", layout = MainLayout.class)
@PermitAll
public class ExpensesView extends VerticalLayout {
private final String SAMPLEPERSON_ID = "samplePersonID";
private final String SAMPLEPERSON_EDIT_ROUTE_TEMPLATE = "/%s/edit";
private final ExpenseRepository expenseRepository;
private final Grid<Expense> grid;
private final Grid<Expense> grid = new Grid<>(Expense.class, false);
@Autowired
public ExpensesView(ExpenseRepository expenseRepository) {
this.expenseRepository = expenseRepository;
this.grid = new Grid<>(Expense.class);
addClassName("expenses-view");
setSizeFull();
private TextField name;
private TextField category;
private TextField cost;
private TextField isPeriodic;
private TextField periodUnit;
private TextField periodInterval;
private final Button cancel = new Button("Cancel");
private final Button save = new Button("Save");
private final BeanValidationBinder<Expense> binder;
private Expense expense;
private final ExpenseService expenseService;
public ExpensesView(ExpenseService expenseService) {
this.expenseService = expenseService;
addClassNames("expenses-view");
// Create UI
SplitLayout splitLayout = new SplitLayout();
createGridLayout(splitLayout);
createEditorLayout(splitLayout);
add(splitLayout);
// Configure Grid
grid.addColumn("name").setAutoWidth(true);
grid.addColumn("category").setAutoWidth(true);
grid.addColumn("cost").setAutoWidth(true);
grid.addColumn("isPeriodic").setAutoWidth(true);
grid.addColumn("periodUnit").setAutoWidth(true);
grid.addColumn("periodInterval").setAutoWidth(true);
// LitRenderer<Expense> importantRenderer = LitRenderer.<Expense>of(
// "<vaadin-icon icon='vaadin:${item.icon}' style='width: var(--lumo-icon-size-s); height: var(--lumo-icon-size-s); color: ${item.color};'></vaadin-icon>")
// .withProperty("icon", important -> important.isImportant() ? "check" : "minus").withProperty("color",
// important -> important.isImportant()
// ? "var(--lumo-primary-text-color)"
// : "var(--lumo-disabled-text-color)");
//
// grid.addColumn(importantRenderer).setHeader("Important").setAutoWidth(true);
grid.setItems(query -> expenseService.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(SAMPLEPERSON_EDIT_ROUTE_TEMPLATE, event.getValue().getId()));
} else {
clearForm();
UI.getCurrent().navigate(ExpensesView.class);
}
});
// Configure Form
binder = new BeanValidationBinder<>(Expense.class);
// Bind fields. This is where you'd define e.g. validation rules
binder.bindInstanceFields(this);
cancel.addClickListener(e -> {
clearForm();
refreshGrid();
});
save.addClickListener(e -> {
try {
if (this.expense == null) {
this.expense = new Expense();
}
binder.writeBean(this.expense);
expenseService.update(this.expense);
clearForm();
refreshGrid();
Notification.show("Data updated");
UI.getCurrent().navigate(ExpensesView.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(Position.MIDDLE);
n.addThemeVariants(NotificationVariant.LUMO_ERROR);
} catch (ValidationException validationException) {
Notification.show("Failed to update the data. Check again that all values are valid");
}
});
configureGrid();
add(grid);
updateList();
}
@Override
public void beforeEnter(BeforeEnterEvent event) {
Optional<Long> samplePersonId = event.getRouteParameters().get(SAMPLEPERSON_ID).map(Long::parseLong);
if (samplePersonId.isPresent()) {
Optional<Expense> samplePersonFromBackend = expenseService.get(samplePersonId.get());
if (samplePersonFromBackend.isPresent()) {
populateForm(samplePersonFromBackend.get());
} else {
Notification.show(
String.format("The requested samplePerson was not found, ID = %s", samplePersonId.get()), 3000,
Notification.Position.BOTTOM_START);
// when a row is selected but the data is no longer available,
// refresh grid
refreshGrid();
event.forwardTo(ExpensesView.class);
}
}
private void configureGrid() {
grid.addClassNames("expense-grid");
grid.setSizeFull();
grid.setColumns("id", "name", "category.name", "cost", "description", "isPeriodic", "periodUnit", "periodInterval", "date");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
}
private void createEditorLayout(SplitLayout splitLayout) {
Div editorLayoutDiv = new Div();
editorLayoutDiv.setClassName("editor-layout");
Div editorDiv = new Div();
editorDiv.setClassName("editor");
editorLayoutDiv.add(editorDiv);
FormLayout formLayout = new FormLayout();
name = new TextField("First Name");
category = new TextField("Last Name");
cost = new TextField("Email");
isPeriodic = new TextField("Phone");
periodUnit = new TextField("Date Of Birth");
periodInterval = new TextField("Occupation");
// important = new Checkbox("Important");
formLayout.add(name, category, cost, isPeriodic, periodUnit, periodInterval);
editorDiv.add(formLayout);
createButtonLayout(editorLayoutDiv);
splitLayout.addToSecondary(editorLayoutDiv);
private void updateList() {
List<Expense> expenses = expenseRepository.findAll();
grid.setItems(expenses);
}
private void createButtonLayout(Div editorLayoutDiv) {
HorizontalLayout buttonLayout = new HorizontalLayout();
buttonLayout.setClassName("button-layout");
cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
buttonLayout.add(save, cancel);
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() {
populateForm(null);
}
private void populateForm(Expense value) {
this.expense = value;
binder.readBean(this.expense);
}
}
}