Skip to content

Commit d48fd48

Browse files
authored
Merge pull request #30 from EngStrategy/feature/historic
Added historic page with funcionalities of sorting by date and name
2 parents 80308b7 + db5cbca commit d48fd48

15 files changed

Lines changed: 429 additions & 28 deletions

File tree

src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AgendamentoController.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
44
import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarAgendamentoController;
5+
import com.carvalhotechsolutions.mundoanimal.enums.StatusAgendamento;
56
import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
67
import com.carvalhotechsolutions.mundoanimal.model.Cliente;
78
import com.carvalhotechsolutions.mundoanimal.repositories.AgendamentoRepository;
@@ -334,7 +335,7 @@ public void abrirModalCadastrarAgendamento() {
334335

335336
public void atualizarTableView() {
336337
agendamentosList.clear();
337-
agendamentosList.addAll(agendamentoRepository.findAll());
338+
agendamentosList.addAll(agendamentoRepository.findStatusPendente());
338339
numberOfResults.setText(agendamentosList.size() + " registro(s) retornado(s)");
339340
configurarPaginacao(); // O método atualizado será chamado aqui também
340341
tableView.refresh();
@@ -411,8 +412,12 @@ private boolean verificarDisponibilidadeHorario(LocalDate data, LocalTime horari
411412
return agendamentoRepository.verificarDisponibilidadeHorario(data, horario);
412413
}
413414

414-
public void finalizarAgendamento(Long id) {
415-
agendamentoRepository.deleteById(id);
415+
public void finalizarAgendamento(Long id, String responsavel, String horarioSaida) {
416+
Agendamento agendamentoFinalizado = agendamentoRepository.findById(id);
417+
agendamentoFinalizado.setStatus(StatusAgendamento.FINALIZADO);
418+
agendamentoFinalizado.setHorarioSaida(LocalTime.parse(horarioSaida));
419+
agendamentoFinalizado.setResponsavelAtendimento(responsavel);
420+
agendamentoRepository.save(agendamentoFinalizado);
416421
handleSuccessfulOperation("Agendamento finalizado com sucesso!");
417422
}
418423
}

src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ClienteController.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,7 @@ public class ClienteController implements Initializable {
4747
private TableView<Cliente> tableView;
4848

4949
@FXML
50-
private TableColumn<Cliente, String> nomeColumn;
51-
52-
@FXML
53-
private TableColumn<Cliente, String> telefoneColumn;
54-
55-
@FXML
56-
private TableColumn<Cliente, String> petsColumn;
50+
private TableColumn<Cliente, String> telefoneColumn, petsColumn, nomeColumn;
5751

5852
@FXML
5953
private TableColumn<Cliente, Void> acaoColumn;
@@ -403,12 +397,4 @@ public void handleError(String message) {
403397
FeedbackManager.FeedbackType.ERROR
404398
);
405399
}
406-
407-
private void mostrarAlerta(String titulo, String mensagem, Alert.AlertType tipo) {
408-
Alert alerta = new Alert(tipo);
409-
alerta.setTitle(titulo);
410-
alerta.setHeaderText(null);
411-
alerta.setContentText(mensagem);
412-
alerta.showAndWait();
413-
}
414400
}
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
2+
3+
import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
4+
import com.carvalhotechsolutions.mundoanimal.model.Cliente;
5+
import com.carvalhotechsolutions.mundoanimal.repositories.AgendamentoRepository;
6+
import javafx.application.Platform;
7+
import javafx.beans.property.IntegerProperty;
8+
import javafx.beans.property.SimpleIntegerProperty;
9+
import javafx.beans.property.SimpleStringProperty;
10+
import javafx.collections.FXCollections;
11+
import javafx.collections.ObservableList;
12+
import javafx.collections.transformation.FilteredList;
13+
import javafx.collections.transformation.SortedList;
14+
import javafx.event.ActionEvent;
15+
import javafx.fxml.FXML;
16+
import javafx.fxml.Initializable;
17+
import javafx.scene.control.*;
18+
import javafx.scene.control.cell.PropertyValueFactory;
19+
import javafx.scene.layout.VBox;
20+
21+
import java.net.URL;
22+
import java.time.LocalDate;
23+
import java.util.List;
24+
import java.util.ResourceBundle;
25+
26+
public class HistoricoController implements Initializable {
27+
private static final int ROW_HEIGHT = 79; // Altura de cada linha em pixels
28+
29+
private static final int HEADER_HEIGHT = 79; // Altura do header em pixels
30+
31+
private IntegerProperty itemsPerPage = new SimpleIntegerProperty();
32+
33+
@FXML
34+
private TableColumn<Agendamento, String> dataColumn, donoColumn, petColumn, responsavelColumn, tipoColumn;
35+
36+
@FXML
37+
private TextField filterField;
38+
39+
@FXML
40+
private Label numberOfResults;
41+
42+
@FXML
43+
private TableView<Agendamento> tableView;
44+
45+
@FXML
46+
private Pagination paginator;
47+
48+
@FXML
49+
private Button btnFiltro;
50+
51+
@FXML
52+
private DatePicker dataFinalPicker;
53+
54+
@FXML
55+
private DatePicker dataInicialPicker;
56+
57+
58+
private final AgendamentoRepository agendamentoRepository = new AgendamentoRepository();
59+
private ObservableList<Agendamento> agendamentosList = FXCollections.observableArrayList();
60+
private FilteredList<Agendamento> filteredData;
61+
private SortedList<Agendamento> sortedData;
62+
63+
@Override
64+
public void initialize(URL url, ResourceBundle resourceBundle) {
65+
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
66+
filteredData = new FilteredList<>(agendamentosList, p -> true); // Inicializa antes de atualizar a tabela
67+
sortedData = new SortedList<>(filteredData);
68+
sortedData.comparatorProperty().bind(tableView.comparatorProperty());
69+
70+
// Adicionar listener para mudanças na altura da tabela
71+
tableView.heightProperty().addListener((obs, oldHeight, newHeight) -> {
72+
calcularItensPorPagina(newHeight.doubleValue());
73+
tableView.refresh(); // Força a atualização da TableView
74+
// Reconfigura a paginação quando a altura muda
75+
Platform.runLater(this::configurarPaginacao);
76+
});
77+
78+
// Calcula inicial de itens por página
79+
calcularItensPorPagina(tableView.getHeight());
80+
81+
// Adiciona listener para o campo de busca
82+
filterField.focusedProperty().addListener((observable, oldValue, newValue) -> {
83+
if (newValue) { // Quando o campo recebe foco
84+
limparFiltroData();
85+
}
86+
});
87+
88+
configurarColunas();
89+
configurarBuscaAgendamentos();
90+
atualizarTableView();
91+
}
92+
93+
private void calcularItensPorPagina(double alturaTotal) {
94+
// Subtrai a altura do header da altura total
95+
double alturaDisponivel = alturaTotal - HEADER_HEIGHT;
96+
// Calcula quantas linhas cabem na altura disponível
97+
int numeroLinhas = Math.max(1, (int) Math.floor(alturaDisponivel / ROW_HEIGHT));
98+
// Atualiza a propriedade de itens por página
99+
itemsPerPage.set(numeroLinhas);
100+
}
101+
102+
private void configurarPaginacao() {
103+
if (filteredData.isEmpty()) {
104+
paginator.setPageCount(1);
105+
paginator.setCurrentPageIndex(0);
106+
paginator.setDisable(true);
107+
tableView.setItems(FXCollections.observableArrayList());
108+
return;
109+
}
110+
111+
// Usa o valor dinâmico de itens por página
112+
int totalPages = (int) Math.ceil((double) filteredData.size() / itemsPerPage.get());
113+
paginator.setPageCount(totalPages);
114+
115+
// Se a página atual é maior que o novo número total de páginas,
116+
// ajusta para a última página válida
117+
if (paginator.getCurrentPageIndex() >= totalPages) {
118+
paginator.setCurrentPageIndex(totalPages - 1);
119+
}
120+
121+
paginator.setDisable(false);
122+
paginator.currentPageIndexProperty().addListener((obs, oldIndex, newIndex) -> {
123+
Platform.runLater(() -> {
124+
atualizarPaginaAtual(newIndex.intValue());
125+
tableView.refresh(); // Força a atualização da TableView
126+
});
127+
});
128+
129+
// Atualiza a visualização inicial
130+
atualizarPaginaAtual(paginator.getCurrentPageIndex());
131+
}
132+
133+
private void atualizarPaginaAtual(int pageIndex) {
134+
int startIndex = pageIndex * itemsPerPage.get();
135+
int endIndex = Math.min(startIndex + itemsPerPage.get(), filteredData.size());
136+
137+
// Cria uma nova lista com os itens da página atual
138+
ObservableList<Agendamento> pageItems = FXCollections.observableArrayList(
139+
filteredData.subList(startIndex, endIndex)
140+
);
141+
142+
tableView.setItems(pageItems);
143+
tableView.refresh();
144+
}
145+
146+
public void atualizarTableView() {
147+
148+
List<Agendamento> novosAgendamentos = agendamentoRepository.findStatusFinalizado();
149+
agendamentosList.setAll(novosAgendamentos); // Apenas atualiza os dados existentes
150+
151+
numberOfResults.setText(agendamentosList.size() + " registro(s) retornado(s)");
152+
atualizarPaginacao();
153+
}
154+
155+
private void configurarColunas() {
156+
tipoColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getServico().getNomeServico()));
157+
dataColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getDataHoraFormatada()));
158+
petColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getAnimal().getNome()));
159+
responsavelColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getResponsavelAtendimento()));
160+
donoColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getCliente().getNome()));
161+
}
162+
163+
private void configurarBuscaAgendamentos() {
164+
filterField.textProperty().addListener((observable, oldValue, newValue) -> {
165+
filteredData.setPredicate(agendamento -> {
166+
if (newValue == null || newValue.isEmpty()) {
167+
return true;
168+
}
169+
170+
String lowerCaseFilter = newValue.toLowerCase();
171+
172+
boolean matchesCliente = agendamento.getCliente().getNome().toLowerCase().contains(lowerCaseFilter);
173+
boolean matchesAnimal = agendamento.getAnimal().getNome().toLowerCase().contains(lowerCaseFilter);
174+
boolean matchesResponsavel = agendamento.getResponsavelAtendimento() != null &&
175+
agendamento.getResponsavelAtendimento().toLowerCase().contains(lowerCaseFilter);
176+
boolean matchesServico = agendamento.getServico().getNomeServico().toLowerCase().contains(lowerCaseFilter);
177+
178+
return matchesCliente || matchesAnimal || matchesResponsavel || matchesServico;
179+
});
180+
181+
numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
182+
atualizarPaginacao();
183+
});
184+
}
185+
186+
private void atualizarPaginacao() {
187+
int totalPages = (int) Math.ceil((double) filteredData.size() / itemsPerPage.get());
188+
paginator.setPageCount(Math.max(totalPages, 1));
189+
190+
paginator.setPageFactory(pageIndex -> {
191+
atualizarPagina(pageIndex);
192+
return new VBox(); // Retorna um nó vazio
193+
});
194+
195+
atualizarPagina(0);
196+
}
197+
198+
private void atualizarPagina(int pageIndex) {
199+
int fromIndex = pageIndex * itemsPerPage.get();
200+
int toIndex = Math.min(fromIndex + itemsPerPage.get(), filteredData.size());
201+
202+
if (fromIndex <= toIndex) {
203+
tableView.setItems(FXCollections.observableArrayList(sortedData.subList(fromIndex, toIndex)));
204+
}
205+
}
206+
207+
@FXML
208+
private void aplicarFiltroData() {
209+
LocalDate dataInicial = dataInicialPicker.getValue();
210+
LocalDate dataFinal = dataFinalPicker.getValue();
211+
212+
if (dataInicial != null && dataFinal != null) {
213+
filteredData.setPredicate(agendamento -> {
214+
LocalDate dataAgendamento = agendamento.getDataAgendamento();
215+
return !dataAgendamento.isBefore(dataInicial) && !dataAgendamento.isAfter(dataFinal);
216+
});
217+
} else {
218+
resetarFiltros();
219+
}
220+
221+
atualizarResultados();
222+
}
223+
224+
@FXML
225+
private void limparFiltroData() {
226+
// Limpa os campos de data
227+
dataInicialPicker.setValue(null);
228+
dataFinalPicker.setValue(null);
229+
230+
// Reseta os filtros e atualiza a tabela
231+
resetarFiltros();
232+
atualizarResultados();
233+
}
234+
235+
// Método auxiliar para resetar os filtros
236+
private void resetarFiltros() {
237+
filteredData.setPredicate(agendamento -> true);
238+
}
239+
240+
// Método auxiliar para atualizar contagem e paginação
241+
private void atualizarResultados() {
242+
numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
243+
atualizarPaginacao();
244+
}
245+
}

src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/MenuController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) {
6161

6262
// Configure ações para cada botão
6363
// configureButton(inicio_btn, "inicio.fxml");
64-
// configureButton(historico_btn, "historico.fxml");
64+
configureButton(historico_btn, ScreenEnum.HISTORICO);
6565
// configureButton(relatorio_btn, "relatorio.fxml");
6666
configureButton(agendamentos_btn, ScreenEnum.AGENDAMENTOS);
6767
configureButton(secretarios_btn, ScreenEnum.SECRETARIOS);

src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarAgendamentoController.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,19 @@ public void cadastrarAgendamento() {
9393
return;
9494
}
9595

96-
if(finish.getText() != null && !finish.getText().isEmpty()) {
97-
if(!validarCamposFinalizacao()) {
96+
if (finish.getText() != null && !finish.getText().isEmpty()) {
97+
if (!validarCamposFinalizacao()) {
9898
return;
9999
}
100-
agendamentoController.finalizarAgendamento(agendamentoAtual.getId());
100+
101+
String responsavel = create_agendamento_responsavel_field.getText(); // Pegando o responsável
102+
if (responsavel == null || responsavel.isBlank()) {
103+
agendamentoController.handleError("O responsável deve ser informado!");
104+
return;
105+
}
106+
107+
String horarioSaidaStr = create_agendamento_depTime_field.getValue();
108+
agendamentoController.finalizarAgendamento(agendamentoAtual.getId(), responsavel, horarioSaidaStr); // Passando o responsável
101109
fecharModal();
102110
return;
103111
}

src/main/java/com/carvalhotechsolutions/mundoanimal/enums/ScreenEnum.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public enum ScreenEnum {
99
SERVICOS("/fxml/gerenciamento/servicos.fxml", "Serviços", ScreenType.CONTENT),
1010
CLIENTES("/fxml/gerenciamento/clientes.fxml", "Clientes", ScreenType.CONTENT),
1111
PETS("/fxml/gerenciamento/pets.fxml", "Pets", ScreenType.CONTENT),
12-
AGENDAMENTOS("/fxml/gerenciamento/agendamentos.fxml", "Agendamentos", ScreenType.CONTENT);
12+
AGENDAMENTOS("/fxml/gerenciamento/agendamentos.fxml", "Agendamentos", ScreenType.CONTENT),
13+
HISTORICO("/fxml/gerenciamento/historico.fxml", "Historico", ScreenType.CONTENT);
1314

1415
private final String fxmlPath;
1516
private final String title;

src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepository.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.carvalhotechsolutions.mundoanimal.repositories;
22

33
import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
4+
import com.carvalhotechsolutions.mundoanimal.enums.StatusAgendamento;
45
import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
56
import jakarta.persistence.EntityManager;
67
import jakarta.persistence.TypedQuery;
@@ -76,4 +77,31 @@ public List<Agendamento> buscarAgendamentosPorData(LocalDate data) {
7677
.setParameter("data", data)
7778
.getResultList();
7879
}
80+
81+
public List<Agendamento> findStatusFinalizado() {
82+
try(EntityManager em = JPAutil.getEntityManager()) {
83+
String jpql = "SELECT a FROM Agendamento a " +
84+
"WHERE a.status = :statusFinalizado " +
85+
"ORDER BY a.dataAgendamento ASC, a.horarioAgendamento ASC";
86+
87+
return em.createQuery(jpql, Agendamento.class)
88+
.setParameter("statusFinalizado", StatusAgendamento.FINALIZADO)
89+
.getResultList();
90+
}
91+
92+
}
93+
94+
public List<Agendamento> findStatusPendente() {
95+
try (EntityManager em = JPAutil.getEntityManager()) {
96+
String jpql = "SELECT a FROM Agendamento a " +
97+
"WHERE a.status = :statusPendente " +
98+
"ORDER BY a.dataAgendamento ASC, a.horarioAgendamento ASC";
99+
100+
return em.createQuery(jpql, Agendamento.class)
101+
.setParameter("statusPendente", StatusAgendamento.PENDENTE)
102+
.getResultList();
103+
}
104+
}
105+
106+
79107
}

0 commit comments

Comments
 (0)