Compare commits

..

No commits in common. "9b3fed87a9c3ec26c23056c96eccf3a5ca1f1dcd" and "5c4d2cdc74926d2c661fb7806175cc0d3cacf296" have entirely different histories.

3 changed files with 232 additions and 245 deletions

View File

@ -28,8 +28,9 @@
private String emergencyCAddress;
private String emergencyCPhone;
private String emergencyCEmail;
@Column(columnDefinition = "TEXT")
private String profileImage;
@Lob
private byte[] profilePicture;
@Enumerated(EnumType.STRING)
private Status status;
public enum Status {

View File

@ -16,16 +16,19 @@ 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.data.value.ValueChangeMode;
import com.vaadin.flow.router.*;
import com.vaadin.flow.router.BeforeEvent;
import com.vaadin.flow.router.HasUrlParameter;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.SpringComponent;
import jakarta.annotation.security.PermitAll;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Scope;
import org.vaadin.firitin.components.datepicker.VDatePicker;
import org.vaadin.firitin.form.BeanValidationForm;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@ -33,94 +36,239 @@ import java.util.UUID;
@PermitAll
@Scope("prototype")
@PageTitle("Employee")
@Route(value = "/employees/:employeeId?/:action?", layout = MainLayout.class)
@Route(value = "/employees", layout = MainLayout.class)
public class EmployeeView extends BeanValidationForm<Employee> implements HasUrlParameter<String> {
private static final String SAVE_BUTTON_TEXT = "Save";
private static final String EDIT_BUTTON_TEXT = "Edit";
private static final String NOTIFICATION_SAVE_SUCCESS = "Employee saved successfully.";
private static final String NOTIFICATION_VALIDATE_ERROR = "Please complete the required fields correctly.";
private static final String PHONE_NUMBER_ERROR_MESSAGE = "El teléfono debe contener solo números.";
private final EmployeeService employeeService;
private final TextField firstName = createTextField("Nombres: ", 30, true);
private final TextField lastName = createTextField("Apellidos", 30, true);
private final ComboBox<Employee.Status> status = createStatusComboBox();
private final VDatePicker birthday = new VDatePicker("Fecha de Nacimiento");
private final TextField birthCity = createTextField("Ciudad y País de Nacimiento", 20, false);
private final ComboBox<Employee.MaritalStatus> maritalStatus = createMaritalStatusComboBox();
private final TextField residenceAddress = createTextField("Dirección de Residencia", 50, false);
private final TextField phoneNumber = createTextField("Teléfono", 8, false);
private final EmailField personalEmail = createEmailField("E-mail");
private final TextField position = createTextField("Cargo", 30, false);
private final TextField team = createTextField("Equipo", 30, false);
private final TextField emergencyCName = createTextField("Nombres y Apellidos de Contacto", 50, false);
private final TextField emergencyCAddress = createTextField("Dirección de Contacto", 50, false);
private final TextField emergencyCPhone = createTextField("Teléfono de Contacto", 8, false);
private final EmailField emergencyCEmail = createEmailField("Email de Contacto");
private final TextField firstName;
private final TextField lastName;
private final ComboBox<String> status;
private final VDatePicker birthday;
private final TextField birthCity;
private final ComboBox<String> maritalStatus;
private final TextField residenceAddress;
private final TextField phoneNumber;
private final EmailField personalEmail;
private final TextField position;
private final TextField team;
private final MemoryBuffer buffer = new MemoryBuffer();
private final Upload upload = new Upload(buffer);
private final Image profileImagePreview = new Image();
private final TextField emergencyCName;
private final TextField emergencyCAddress;
private final TextField emergencyCPhone;
private final EmailField emergencyCEmail;
private final Button saveButton = new Button(SAVE_BUTTON_TEXT, e -> saveEmployee());
private final Button editButton = new Button(EDIT_BUTTON_TEXT, e -> enableEditMode());
private final H2 mt;
private final H3 fs;
private final H3 ss;
private final H2 mt = new H2("Información General del Empleado");
private final H3 fs = new H3("Información Personal");
private final H3 ss = new H3("Datos de Contacto de Emergencia");
private final Upload imageUpload;
private final Image employeeImage;
private byte[] imageBytes;
private final Button saveButton;
private final Button editButton;
private final List<TextField> formFields = new ArrayList<>();
public EmployeeView(final EmployeeService employeeService) {
super(Employee.class);
this.employeeService = employeeService;
configureComponents();
assembleLayout();
}
mt = new H2("Información General del Empleado");
fs = new H3("Información Personal");
ss = new H3("Datos de Contacto de Emergencia");
private void configureComponents() {
final HorizontalLayout mainLayout = new HorizontalLayout();
final VerticalLayout sidebar = createSidebar();
final VerticalLayout contentLayout = createContentLayout();
final VerticalLayout contentLayout2 = createContentLayout();
firstName = new TextField("Nombres: ");
firstName.setWidthFull();
firstName.setMaxLength(30);
firstName.setRequired(true);
lastName = new TextField("Apellidos");
lastName.setWidthFull();
lastName.setMaxLength(30);
lastName.setRequired(true);
status = new ComboBox<>("Estado");
status.setItems(List.of("ACTIVE", "INACTIVE"));
lastName.setWidthFull();
lastName.setMaxLength(30);
status.setRequired(true);
birthday = new VDatePicker("Fecha de Nacimiento");
birthday.setWidthFull();
birthCity = new TextField("Ciudad y País de Nacimiento");
birthCity.setWidthFull();
birthCity.setMaxLength(20);
maritalStatus = new ComboBox<>("Estado Civil");
maritalStatus.setItems(List.of("Soltero", "Casado", "Viudo", "Divorciado"));
maritalStatus.setWidthFull();
residenceAddress = new TextField("Dirección de Residencia");
residenceAddress.setWidthFull();
residenceAddress.setMaxLength(50);
phoneNumber = new TextField("Teléfono");
phoneNumber.setWidthFull();
phoneNumber.setMaxLength(8);
phoneNumber.setValueChangeMode(ValueChangeMode.EAGER);
phoneNumber.addValueChangeListener(e -> validatePhoneNumber(phoneNumber, e.getValue()));
emergencyCPhone.setValueChangeMode(ValueChangeMode.EAGER);
emergencyCPhone.addValueChangeListener(e -> validatePhoneNumber(emergencyCPhone, e.getValue()));
configureUpload();
saveButton.setVisible(true);
editButton.setVisible(true);
}
private void configureUpload() {
upload.setAcceptedFileTypes("image/jpeg", "image/png");
upload.setMaxFileSize(1024 * 1024);
upload.addSucceededListener(event -> {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
buffer.getInputStream().transferTo(outputStream);
byte[] imageBytes = outputStream.toByteArray();
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
getEntity().setProfileImage(base64Image);
profileImagePreview.setSrc("data:image/jpeg;base64," + base64Image);
profileImagePreview.setMaxWidth("150px");
profileImagePreview.setMaxHeight("150px");
} catch (IOException e) {
Notification.show("Error al subir la imagen.");
phoneNumber.addValueChangeListener(e -> {
if (!e.getValue().matches("\\d*")) {
phoneNumber.setErrorMessage("El teléfono debe contener solo números.");
}
});
personalEmail = new EmailField("E-mail");
personalEmail.setWidthFull();
personalEmail.setMaxLength(30);
position = new TextField("Cargo");
position.setWidthFull();
position.setMaxLength(30);
team = new TextField("Equipo");
team.setWidthFull();
team.setMaxLength(30);
emergencyCName = new TextField("Nombres y Apellidos de Contacto");
emergencyCName.setWidthFull();
emergencyCName.setMaxLength(50);
emergencyCAddress = new TextField("Dirección de Contacto");
emergencyCAddress.setWidthFull();
emergencyCAddress.setMaxLength(50);
emergencyCPhone = new TextField("Teléfono de Contacto");
emergencyCPhone.setWidthFull();
emergencyCPhone.setMaxLength(8);
emergencyCPhone.setValueChangeMode(ValueChangeMode.EAGER);
emergencyCPhone.addValueChangeListener(e -> {
if (!e.getValue().matches("\\d*")) {
emergencyCPhone.setErrorMessage("El teléfono debe contener solo números.");
}
});
emergencyCEmail = new EmailField("Email de Contacto");
emergencyCEmail.setWidthFull();
emergencyCEmail.setMaxLength(30);
MemoryBuffer buffer = new MemoryBuffer();
imageUpload = new Upload(buffer);
imageUpload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
imageUpload.setMaxFileSize(1024 * 1024);
employeeImage = new Image();
employeeImage.setMaxHeight("150px");
employeeImage.setMaxWidth("150px");
imageUpload.addSucceededListener(event -> {
try {
InputStream inputStream = buffer.getInputStream();
imageBytes = inputStream.readAllBytes();
employeeImage.setSrc(
"data:image/png;base64," + java.util.Base64.getEncoder().encodeToString(imageBytes));
Notification.show("Imagen subida correctamente.");
} catch (Exception ex) {
Notification.show(
"Error al subir la imagen: " + ex.getMessage(), 3000, Notification.Position.MIDDLE);
}
});
editButton = new Button("Editar");
saveButton = new Button("Guardar");
setFormFieldsEnabled(false);
editButton.addClickListener(event -> setFormFieldsEnabled(true));
contentLayout.add(
mt, fs, firstName, lastName, status, birthday, birthCity, maritalStatus,
residenceAddress, phoneNumber, personalEmail, position, team, imageUpload, employeeImage);
contentLayout2.add(
ss, emergencyCName, emergencyCAddress, emergencyCPhone, emergencyCEmail);
setSavedHandler((SavedHandler<Employee>) employee -> {
if (validateForm()) {
employee.setProfilePicture(imageBytes);
employee.setStatus(Employee.Status.valueOf(status.getValue()));
final Employee saved = employeeService.createOrUpdate(employee);
Notification.show("Employee saved successfully.");
getUI().ifPresent(ui -> ui.navigate(EmployeesListView.class));
setEntityWithEnabledSave(saved);
setFormFieldsEnabled(false);
} else {
Notification.show("Please complete the required fields correctly.", 3000, Notification.Position.MIDDLE);
}
});
mainLayout.add(sidebar, contentLayout, contentLayout2);
addClassName("main-layout");
}
private void validatePhoneNumber(final TextField textField, final String value) {
if (!value.matches("\\d*")) {
textField.setErrorMessage(PHONE_NUMBER_ERROR_MESSAGE);
private void setFormFieldsEnabled(final boolean enabled) {
firstName.setEnabled(enabled);
lastName.setEnabled(enabled);
status.setEnabled(enabled);
birthday.setEnabled(enabled);
birthCity.setEnabled(enabled);
maritalStatus.setEnabled(enabled);
residenceAddress.setEnabled(enabled);
phoneNumber.setEnabled(enabled);
personalEmail.setEnabled(enabled);
position.setEnabled(enabled);
team.setEnabled(enabled);
emergencyCName.setEnabled(enabled);
emergencyCAddress.setEnabled(enabled);
emergencyCPhone.setEnabled(enabled);
emergencyCEmail.setEnabled(enabled);
}
private boolean validateForm() {
return !firstName.isEmpty() && !lastName.isEmpty() && status.getValue() != null;
}
private VerticalLayout createSidebar() {
VerticalLayout sidebar = new VerticalLayout();
sidebar.setWidth("250px");
sidebar.add(new Button("Información General", e -> navigateToSection("Información General")));
sidebar.add(new Button("Detalles Profesionales", e -> navigateToSection("Detalles Profesionales")));
return sidebar;
}
private void navigateToSection(final String section) {
Notification.show("Navigating to " + section);
}
private VerticalLayout createContentLayout() {
VerticalLayout contentLayout = new VerticalLayout();
contentLayout.setWidth("100%");
return contentLayout;
}
@Override
public void setParameter(final BeforeEvent beforeEvent, final String s) {
if (StringUtils.isNotBlank(s) && !"new".equals(s)) {
var employee = employeeService.getEmployee(UUID.fromString(s));
setEntityWithEnabledSave(employee);
setFormFieldsEnabled(true);
} else {
setEntityWithEnabledSave(new Employee());
setFormFieldsEnabled(true);
}
}
private void assembleLayout() {
HorizontalLayout mainLayout = new HorizontalLayout();
VerticalLayout contentLayout1 = createContentLayout();
VerticalLayout contentLayout2 = createContentLayout();
contentLayout1.add(
@Override
protected List<Component> getFormComponents() {
return List.of(
mt,
fs,
firstName,
@ -133,172 +281,15 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
phoneNumber,
personalEmail,
position,
team);
contentLayout2.add(
ss, emergencyCName, emergencyCAddress,
emergencyCPhone, emergencyCEmail, upload,
profileImagePreview, saveButton, editButton);
mainLayout.add(contentLayout1, contentLayout2);
addClassName("main-layout");
}
private ComboBox<Employee.MaritalStatus> createMaritalStatusComboBox() {
ComboBox<Employee.MaritalStatus> comboBox = new ComboBox<>("Estado Civil");
comboBox.setItems(Employee.MaritalStatus.values());
comboBox.setItemLabelGenerator(Employee.MaritalStatus::name);
return comboBox;
}
private ComboBox<Employee.Status> createStatusComboBox() {
ComboBox<Employee.Status> comboBox = new ComboBox<>("Estado");
comboBox.setItems(Employee.Status.values());
comboBox.setItemLabelGenerator(Employee.Status::name);
comboBox.setRequiredIndicatorVisible(true); // Indicador de campo requerido
return comboBox;
}
private VerticalLayout createContentLayout() {
VerticalLayout contentLayout = new VerticalLayout();
contentLayout.setWidth("100%");
return contentLayout;
}
private TextField createTextField(final String label, final int maxLength, final boolean required) {
TextField textField = new TextField(label);
textField.setWidthFull();
textField.setMaxLength(maxLength);
textField.setRequired(required);
return textField;
}
private EmailField createEmailField(final String label) {
EmailField emailField = new EmailField(label);
emailField.setWidthFull();
emailField.setMaxLength(30);
return emailField;
}
private <T> ComboBox<T> createComboBox(final String label, final T[] items) {
ComboBox<T> comboBox = new ComboBox<>(label);
comboBox.setItems(items);
comboBox.setItemLabelGenerator(Object::toString);
comboBox.setWidthFull();
return comboBox;
}
private boolean validateForm() {
return !firstName.isEmpty() && !lastName.isEmpty() && status.getValue() != null;
}
private void saveEmployee() {
if (validateForm()) {
Employee employee = getEntity();
employee.setStatus(status.getValue());
employeeService.createOrUpdate(employee);
Notification.show(NOTIFICATION_SAVE_SUCCESS);
getUI().ifPresent(ui -> ui.navigate(EmployeesListView.class));
} else {
Notification.show(NOTIFICATION_VALIDATE_ERROR, 3000, Notification.Position.MIDDLE);
}
}
private void enableEditMode() {
setFieldsEditable();
saveButton.setVisible(true);
editButton.setVisible(false);
}
@Override
public void setParameter(final BeforeEvent beforeEvent, final String action) {
RouteParameters params = beforeEvent.getRouteParameters();
String s = params.get("employeeId").orElse(null);
if ("new".equals(action)) {
setEntityWithEnabledSave(new Employee());
saveButton.setVisible(true);
editButton.setVisible(false);
setFieldsEditable();
} else {
UUID employeeId = UUID.fromString(s);
var employee = employeeService.getEmployee(employeeId);
setEntityWithEnabledSave(employee);
if ("edit".equals(action) && !s.isEmpty()) {
saveButton.setVisible(true);
editButton.setVisible(false);
status.setValue(employee.getStatus());
setFieldsEditable();
} else if ("view".equals(action) && !s.isEmpty()) {
setFieldsReadOnly();
saveButton.setVisible(false);
editButton.setVisible(true);
setFieldsReadOnly();
displayProfileImage(employee);
}
}
}
private void displayProfileImage(final Employee employee) {
if (employee.getProfileImage() != null && !employee.getProfileImage().isEmpty()) {
profileImagePreview.setSrc("data:image/jpeg;base64," + employee.getProfileImage());
profileImagePreview.setVisible(true);
profileImagePreview.setMaxWidth("150px");
profileImagePreview.setMaxHeight("150px");
upload.setVisible(false);
} else {
profileImagePreview.setVisible(false);
upload.setVisible(true);
}
}
private void setFieldsReadOnly() {
firstName.setReadOnly(true);
lastName.setReadOnly(true);
status.setReadOnly(true);
birthday.setReadOnly(true);
birthCity.setReadOnly(true);
maritalStatus.setReadOnly(true);
residenceAddress.setReadOnly(true);
phoneNumber.setReadOnly(true);
personalEmail.setReadOnly(true);
position.setReadOnly(true);
team.setReadOnly(true);
emergencyCName.setReadOnly(true);
emergencyCAddress.setReadOnly(true);
emergencyCPhone.setReadOnly(true);
emergencyCEmail.setReadOnly(true);
upload.setVisible(true);
profileImagePreview.setVisible(true);
}
private void setFieldsEditable() {
firstName.setReadOnly(false);
lastName.setReadOnly(false);
status.setReadOnly(false);
birthday.setReadOnly(false);
birthCity.setReadOnly(false);
maritalStatus.setReadOnly(false);
residenceAddress.setReadOnly(false);
phoneNumber.setReadOnly(false);
personalEmail.setReadOnly(false);
position.setReadOnly(false);
team.setReadOnly(false);
emergencyCName.setReadOnly(false);
emergencyCAddress.setReadOnly(false);
emergencyCPhone.setReadOnly(false);
emergencyCEmail.setReadOnly(false);
upload.setVisible(true);
}
@Override
protected List<Component> getFormComponents() {
return List.of(
mt, fs, firstName, lastName, status, birthday, birthCity, maritalStatus,
residenceAddress, phoneNumber, personalEmail, position, team, ss, emergencyCName,
emergencyCAddress, emergencyCPhone, emergencyCEmail, upload, profileImagePreview, saveButton, editButton
team,
imageUpload,
employeeImage,
ss,
emergencyCName,
emergencyCAddress,
emergencyCPhone,
emergencyCEmail,
editButton
);
}
}

View File

@ -42,7 +42,6 @@ public class EmployeesListView extends Main {
private void configureTable() {
table.setColumns("firstName", "lastName", "status");
addEditButtonColumn("View", this::navigateToEmployeeView);
addEditButtonColumn("Edit", this::navigateToEditView);
setupPagingGrid();
@ -73,11 +72,7 @@ public class EmployeesListView extends Main {
}
private void navigateToEditView(final Employee employee) {
getUI().ifPresent(ui -> ui.navigate(EmployeeView.class, employee.getId().toString() + "/edit"));
}
private void navigateToEmployeeView(final Employee employee) {
getUI().ifPresent(ui -> ui.navigate(EmployeeView.class, employee.getId().toString() + "/view"));
getUI().ifPresent(ui -> ui.navigate(EmployeeView.class, employee.getId().toString()));
}
private void navigateToAddEmployeeView() {