diff --git a/src/main/java/com/example/customer/Customer.java b/src/main/java/com/example/customer/Customer.java new file mode 100644 index 0000000..9e6e041 --- /dev/null +++ b/src/main/java/com/example/customer/Customer.java @@ -0,0 +1,10 @@ +package com.example.customer; + +import java.time.LocalDate; + +/** + * A customer record. This is a plain, immutable value type backed by + * {@link CustomerService}'s in-memory dummy data, not a JPA entity. + */ +public record Customer(String name, String email, String company, String status, LocalDate customerSince) { +} diff --git a/src/main/java/com/example/customer/CustomerService.java b/src/main/java/com/example/customer/CustomerService.java new file mode 100644 index 0000000..dd57706 --- /dev/null +++ b/src/main/java/com/example/customer/CustomerService.java @@ -0,0 +1,39 @@ +package com.example.customer; + +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.List; + +@Service +public class CustomerService { + + // TODO Replace with a real data source (e.g. a JPA-backed CustomerRepository) once + // customers are no longer dummy data. + private static final List DUMMY_CUSTOMERS = List.of( + new Customer("Alice Johnson", "alice.johnson@example.com", "Acme Corp", "Active", + LocalDate.of(2019, 3, 12)), + new Customer("Bob Smith", "bob.smith@example.com", "Globex Inc", "Active", LocalDate.of(2020, 7, 1)), + new Customer("Carla Diaz", "carla.diaz@example.com", "Initech", "Inactive", LocalDate.of(2018, 11, 23)), + new Customer("David Chen", "david.chen@example.com", "Umbrella Corp", "Prospect", + LocalDate.of(2024, 1, 15)), + new Customer("Elena Petrova", "elena.petrova@example.com", "Hooli", "Active", LocalDate.of(2021, 5, 30)), + new Customer("Frank Müller", "frank.mueller@example.com", "Soylent Corp", "Inactive", + LocalDate.of(2017, 9, 4)), + new Customer("Grace Kim", "grace.kim@example.com", "Stark Industries", "Active", + LocalDate.of(2022, 2, 18)), + new Customer("Hassan Ali", "hassan.ali@example.com", "Wayne Enterprises", "Prospect", + LocalDate.of(2025, 4, 9)), + new Customer("Ingrid Nilsson", "ingrid.nilsson@example.com", "Wonka Industries", "Active", + LocalDate.of(2016, 6, 21)), + new Customer("Julien Moreau", "julien.moreau@example.com", "Cyberdyne Systems", "Inactive", + LocalDate.of(2023, 10, 8)), + new Customer("Katrin Bauer", "katrin.bauer@example.com", "Massive Dynamic", "Active", + LocalDate.of(2020, 12, 3)), + new Customer("Liam O'Connor", "liam.oconnor@example.com", "Aperture Science", "Prospect", + LocalDate.of(2026, 1, 27))); + + public List list() { + return DUMMY_CUSTOMERS; + } +} diff --git a/src/main/java/com/example/customer/package-info.java b/src/main/java/com/example/customer/package-info.java new file mode 100644 index 0000000..0ffe9c5 --- /dev/null +++ b/src/main/java/com/example/customer/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package com.example.customer; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/com/example/customer/ui/CustomerListView.java b/src/main/java/com/example/customer/ui/CustomerListView.java new file mode 100644 index 0000000..a5e07cd --- /dev/null +++ b/src/main/java/com/example/customer/ui/CustomerListView.java @@ -0,0 +1,42 @@ +package com.example.customer.ui; + +import com.example.base.ui.ViewTitle; +import com.example.customer.Customer; +import com.example.customer.CustomerService; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.Menu; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import jakarta.annotation.security.PermitAll; + +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; + +@Route(value = "customers") +@PageTitle("Customers") +@Menu(order = 1, icon = "vaadin:users", title = "Customers") +@PermitAll +class CustomerListView extends VerticalLayout { + + final Grid customerGrid; + + CustomerListView(CustomerService customerService) { + var dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(getLocale()); + + customerGrid = new Grid<>(); + customerGrid.setItems(customerService.list()); + customerGrid.addColumn(Customer::name).setHeader("Name").setSortable(true); + customerGrid.addColumn(Customer::email).setHeader("Email").setSortable(true); + customerGrid.addColumn(Customer::company).setHeader("Company").setSortable(true); + customerGrid.addColumn(Customer::status).setHeader("Status").setSortable(true); + customerGrid.addColumn(customer -> dateFormatter.format(customer.customerSince())) + .setHeader("Customer Since") + .setSortable(true); + customerGrid.setEmptyStateText("No customers found"); + customerGrid.setSizeFull(); + + setSizeFull(); + add(new ViewTitle("Customers"), customerGrid); + } +} diff --git a/src/main/java/com/example/customer/ui/package-info.java b/src/main/java/com/example/customer/ui/package-info.java new file mode 100644 index 0000000..acd3f9a --- /dev/null +++ b/src/main/java/com/example/customer/ui/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package com.example.customer.ui; + +import org.jspecify.annotations.NullMarked; diff --git a/src/test/java/com/example/customer/ui/CustomerListViewTest.java b/src/test/java/com/example/customer/ui/CustomerListViewTest.java new file mode 100644 index 0000000..9dd1ec7 --- /dev/null +++ b/src/test/java/com/example/customer/ui/CustomerListViewTest.java @@ -0,0 +1,31 @@ +package com.example.customer.ui; + +import com.vaadin.browserless.SpringBrowserlessTest; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@WithMockUser(roles = "USER") +class CustomerListViewTest extends SpringBrowserlessTest { + + @Test + void grid_shows_all_dummy_customers() { + var view = navigate(CustomerListView.class); + + assertThat(test(view.customerGrid).size()).isEqualTo(12); + } + + @Test + void grid_shows_customer_columns() { + var view = navigate(CustomerListView.class); + + assertThat(test(view.customerGrid).getCellText(0, 0)).isEqualTo("Alice Johnson"); + assertThat(test(view.customerGrid).getCellText(0, 1)).isEqualTo("alice.johnson@example.com"); + assertThat(test(view.customerGrid).getCellText(0, 2)).isEqualTo("Acme Corp"); + assertThat(test(view.customerGrid).getCellText(0, 3)).isEqualTo("Active"); + assertThat(test(view.customerGrid).getCellText(0, 4)).isNotEmpty(); + } +}