diff --git a/src/main/java/com/primefactorsolutions/model/Document.java b/src/main/java/com/primefactorsolutions/model/Document.java index 3b8b200..2e3b222 100644 --- a/src/main/java/com/primefactorsolutions/model/Document.java +++ b/src/main/java/com/primefactorsolutions/model/Document.java @@ -13,6 +13,9 @@ public class Document extends BaseEntity { private String fileName; @Enumerated(EnumType.STRING) private DocumentType documentType; + @ManyToOne + @JoinColumn(name = "employee_id", nullable = false) + private Employee employee; @Lob @Column(columnDefinition = "BLOB") private byte[] fileData; diff --git a/src/main/java/com/primefactorsolutions/service/DocumentService.java b/src/main/java/com/primefactorsolutions/service/DocumentService.java index 838840f..efdf0cc 100644 --- a/src/main/java/com/primefactorsolutions/service/DocumentService.java +++ b/src/main/java/com/primefactorsolutions/service/DocumentService.java @@ -2,20 +2,20 @@ package com.primefactorsolutions.service; import com.primefactorsolutions.model.Document; import com.primefactorsolutions.repositories.DocumentRepository; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanComparator; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.Optional; @Service +@AllArgsConstructor public class DocumentService { private final DocumentRepository documentRepository; - public DocumentService(final DocumentRepository documentRepository) { - this.documentRepository = documentRepository; - } - public void saveDocument(final Document newDocument) { documentRepository.save(newDocument); } @@ -24,7 +24,29 @@ public class DocumentService { return documentRepository.findAll(); } - public Optional getDocumentById(final UUID id) { - return documentRepository.findById(id); + public Document getDocument(final UUID id) { + Optional employee = documentRepository.findById(id); + return employee.orElse(null); + } + + public List findDocuments( + final int start, final int pageSize, final String sortProperty, final boolean asc) { + List documents = documentRepository.findAll(); + + int end = Math.min(start + pageSize, documents.size()); + documents.sort(new BeanComparator<>(sortProperty)); + + if (!asc) { + Collections.reverse(documents); + } + + return documents.subList(start, end); + } + + public List findDocuments(final int start, final int pageSize) { + List employees = documentRepository.findAll(); + + int end = Math.min(start + pageSize, employees.size()); + return employees.subList(start, end); } } diff --git a/src/main/java/com/primefactorsolutions/views/DocumentsView.java b/src/main/java/com/primefactorsolutions/views/DocumentView.java similarity index 73% rename from src/main/java/com/primefactorsolutions/views/DocumentsView.java rename to src/main/java/com/primefactorsolutions/views/DocumentView.java index 37b11b5..4b9014f 100644 --- a/src/main/java/com/primefactorsolutions/views/DocumentsView.java +++ b/src/main/java/com/primefactorsolutions/views/DocumentView.java @@ -5,31 +5,32 @@ import com.primefactorsolutions.model.DocumentType; import com.primefactorsolutions.model.Employee; import com.primefactorsolutions.service.DocumentService; import com.primefactorsolutions.service.EmployeeService; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.html.Main; import com.vaadin.flow.component.notification.Notification; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.upload.Upload; import com.vaadin.flow.component.upload.receivers.MemoryBuffer; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; +import com.vaadin.flow.router.*; import com.vaadin.flow.spring.annotation.SpringComponent; import jakarta.annotation.security.PermitAll; import org.springframework.context.annotation.Scope; +import org.vaadin.firitin.form.BeanValidationForm; import java.io.IOException; import java.util.List; +import java.util.UUID; @SpringComponent @PermitAll @Scope("prototype") -@PageTitle("Documents") -@Route(value = "/documents", layout = MainLayout.class) -public class DocumentsView extends Main { +@PageTitle("Document") +@Route(value = "/documents/:documentId?/:action?", layout = MainLayout.class) +public class DocumentView extends BeanValidationForm implements HasUrlParameter { + private final H2 title = new H2("Edit Documents"); private final TextField fileName = new TextField("Document Name"); private final ComboBox documentType = new ComboBox<>("Document Type"); private final ComboBox employeeComboBox = new ComboBox<>("Employee"); @@ -39,11 +40,11 @@ public class DocumentsView extends Main { private final EmployeeService employeeService; private boolean fileUploaded = false; - public DocumentsView(final DocumentService documentService, final EmployeeService employeeService) { + public DocumentView(final DocumentService documentService, final EmployeeService employeeService) { + super(Document.class); this.documentService = documentService; this.employeeService = employeeService; initializeView(); - addComponents(); } private void initializeView() { @@ -75,27 +76,27 @@ public class DocumentsView extends Main { uploadButton.addSucceededListener(event -> handleUploadSuccess()); } - private void addComponents() { - H2 title = new H2("Edit Documents"); - Button saveButton = createSaveButton(); - Button closeButton = createCloseButton(); - HorizontalLayout buttonLayout = new HorizontalLayout(saveButton, closeButton); - - add(title, fileName, documentType, employeeComboBox, uploadButton, buttonLayout); - } - - private Button createSaveButton() { + protected Button createSaveButton() { Button saveButton = new Button("Save"); saveButton.addClickListener(event -> saveDocument()); return saveButton; } - private Button createCloseButton() { + protected Button createCloseButton() { Button closeButton = new Button("Close"); closeButton.addClickListener(event -> closeForm()); return closeButton; } + + private void closeForm() { + navigateToDocumentsListView(); + } + + private void navigateToDocumentsListView() { + getUI().ifPresent(ui -> ui.navigate(DocumentsListView.class)); + } + private void handleUploadSuccess() { fileUploaded = true; Notification.show("File uploaded successfully."); @@ -104,6 +105,7 @@ public class DocumentsView extends Main { private void saveDocument() { if (isFormValid()) { Document document = createDocument(); + document.setEmployee(employeeComboBox.getValue()); documentService.saveDocument(document); Notification.show("File saved successfully."); clearForm(); @@ -143,7 +145,23 @@ public class DocumentsView extends Main { fileUploaded = false; } - private void closeForm() { - clearForm(); + + @Override + public void setParameter(final BeforeEvent beforeEvent, final String action) { + final RouteParameters params = beforeEvent.getRouteParameters(); + final String s = params.get("documentId").orElse(null); + + if ("new".equals(action)) { + setEntityWithEnabledSave(new Document()); + } else { + UUID documentId = UUID.fromString(s); + var document = documentService.getDocument(documentId); + setEntityWithEnabledSave(document); + } + } + + @Override + protected List getFormComponents() { + return List.of(title, fileName, documentType, employeeComboBox, uploadButton, createCloseButton()); } } diff --git a/src/main/java/com/primefactorsolutions/views/DocumentsListView.java b/src/main/java/com/primefactorsolutions/views/DocumentsListView.java new file mode 100644 index 0000000..0a311b1 --- /dev/null +++ b/src/main/java/com/primefactorsolutions/views/DocumentsListView.java @@ -0,0 +1,143 @@ +package com.primefactorsolutions.views; + +import com.primefactorsolutions.model.Document; +import com.primefactorsolutions.model.DocumentType; +import com.primefactorsolutions.model.Employee; +import com.primefactorsolutions.service.DocumentService; +import com.primefactorsolutions.service.EmployeeService; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.combobox.ComboBox; +import com.vaadin.flow.component.html.Main; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.spring.annotation.SpringComponent; +import org.vaadin.firitin.components.grid.PagingGrid; +import com.vaadin.flow.component.grid.GridSortOrder; +import com.vaadin.flow.data.provider.SortDirection; +import jakarta.annotation.security.PermitAll; +import org.springframework.context.annotation.Scope; + +import java.util.List; + + +@SpringComponent +@Scope("prototype") +@PageTitle("Documents") +@Route(value = "/documents", layout = MainLayout.class) +@PermitAll +public class DocumentsListView extends Main { + + private final DocumentService documentService; + private final EmployeeService employeeService; + private final PagingGrid documentGrid = new PagingGrid<>(Document.class); + + public DocumentsListView(final DocumentService documentService, final EmployeeService employeeService) { + this.documentService = documentService; + this.employeeService = employeeService; + initializeView(); + updateDocumentGrid(); + } + + private void initializeView() { + configureDocumentGrid(); + add(createActionButton("Add Document", this::navigateToAddDocumentView)); + add(createDocumentTypeFilter()); + add(createEmployeeFilter()); + add(documentGrid); + } + + private void configureDocumentGrid() { + documentGrid.setColumns("fileName", "documentType"); + documentGrid.addComponentColumn(this::createEmployeeSpan).setHeader("Employee"); + addDocumentActionColumn("View", this::navigateToDocumentView); + addDocumentActionColumn("Edit", this::navigateToEditDocumentView); + addDocumentActionColumn("Download", this::navigateToDownloadDocumentView); + configurePagination(); + } + + private Span createEmployeeSpan(final Document document) { + Employee employee = document.getEmployee(); + String employeeName = employee.getFirstName() + " " + employee.getLastName(); + return new Span(employeeName); + } + + + private void addDocumentActionColumn(final String label, final DocumentActionHandler handler) { + documentGrid.addComponentColumn(document -> createActionButton(label, () -> handler.handle(document))); + } + + private Button createActionButton(final String label, final Runnable onClickAction) { + Button actionButton = new Button(label); + actionButton.addClickListener(event -> onClickAction.run()); + return actionButton; + } + + private ComboBox createDocumentTypeFilter() { + ComboBox documentTypeFilter = new ComboBox<>("Document Type"); + documentTypeFilter.setItems(DocumentType.values()); + documentTypeFilter.addValueChangeListener(event -> updateDocumentGrid()); + return documentTypeFilter; + } + + private ComboBox createEmployeeFilter() { + ComboBox employeeFilter = new ComboBox<>("Employee"); + List employees = employeeService.findAllEmployees(); + employeeFilter.setItems(employees); + employeeFilter.setItemLabelGenerator(employee -> employee.getFirstName() + " " + employee.getLastName()); + employeeFilter.addValueChangeListener(event -> updateDocumentGrid()); + return employeeFilter; + } + + private void navigateToEditDocumentView(final Document document) { + navigateToDocumentView(document, "edit"); + } + + private void navigateToDocumentView(final Document document) { + navigateToDocumentView(document, "view"); + } + + private void navigateToDocumentView(final Document document, final String action) { + getUI().ifPresent(ui -> ui.navigate(DocumentView.class, document.getId().toString() + "/" + action)); + } + + private void navigateToDownloadDocumentView(final Document document) { + // No operation + } + + private void navigateToAddDocumentView() { + getUI().ifPresent(ui -> ui.navigate(DocumentView.class, "new")); + } + + private void configurePagination() { + documentGrid.setPaginationBarMode(PagingGrid.PaginationBarMode.BOTTOM); + documentGrid.setPageSize(5); + } + + private void updateDocumentGrid() { + documentGrid.setPagingDataProvider((page, pageSize) -> fetchDocuments((int) page, pageSize)); + } + + private List fetchDocuments(final int page, final int size) { + int startIndex = page * size; + return isSortOrderPresent() + ? fetchSortedDocuments(startIndex, size) + : documentService.findDocuments(startIndex, size); + } + + private boolean isSortOrderPresent() { + return !documentGrid.getSortOrder().isEmpty(); + } + + private List fetchSortedDocuments(final int start, final int pageSize) { + GridSortOrder sortOrder = documentGrid.getSortOrder().getFirst(); + return documentService.findDocuments(start, pageSize, + sortOrder.getSorted().getKey(), + sortOrder.getDirection() == SortDirection.ASCENDING); + } + + @FunctionalInterface + private interface DocumentActionHandler { + void handle(Document document); + } +} \ No newline at end of file diff --git a/src/main/java/com/primefactorsolutions/views/MainLayout.java b/src/main/java/com/primefactorsolutions/views/MainLayout.java index 36aaa54..42abb45 100644 --- a/src/main/java/com/primefactorsolutions/views/MainLayout.java +++ b/src/main/java/com/primefactorsolutions/views/MainLayout.java @@ -81,7 +81,7 @@ public class MainLayout extends AppLayout { LineAwesomeIcon.SUPERSCRIPT_SOLID.create()); // admin.addItem(new SideNavItem("Employees", EmployeeView.class, // LineAwesomeIcon.USER_EDIT_SOLID.create())); - admin.addItem(new SideNavItem("Documents", DocumentsView.class, + admin.addItem(new SideNavItem("Documents", DocumentsListView.class, LineAwesomeIcon.FILE_ALT_SOLID.create())); SideNavItem timeOff = new SideNavItem("My Time-off", TimeoffView.class,