diff --git a/README.md b/README.md
index e0ea843..2864584 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,55 @@
-# MundoAnimal
+# 🐾 Mundo Animal - Sistema de Gestão para Petshop
+
+Mundo Animal é um sistema desktop desenvolvido em **JavaFX** com **PostgreSQL** e **Hibernate (JPA)**, projetado para a gestão eficiente de um petshop. O sistema permite o gerenciamento de clientes, animais, agendamentos, serviços e secretários.
+
+## 🚀 Tecnologias Utilizadas
+- **Java 23**
+- **JavaFX** (para interface gráfica)
+- **PostgreSQL** (banco de dados relacional)
+- **Hibernate/JPA** (persistência de dados)
+- **Maven** (gerenciador de dependências)
+- **BCrypt** (para criptografar senhas)
+
+## 📌Funcionalidades Principais
+- **Autenticação:** Login seguro para administradores e secretários.
+- **Gerenciamento de Agendamentos:** Exibição dinâmica dos próximos atendimentos na tela inicial.
+- **Cadastro de Clientes e Animais:** Relacionamento entre clientes e seus respectivos pets.
+- **Controle de Serviços:** Registros de atendimento e relatório de operações.
+- **Interface intuitiva:** Com animações suaves e pop-ups de confirmação.
+
+## 🛠️ Instalação e Execução
+### Pré-requisitos
+- Java 21+ instalado
+- PostgreSQL instalado
+- Maven instalado
+
+## 📂 Estrutura do Projeto
+```
+MundoAnimal/
+│── src/
+│ ├── main/
+│ │ ├── java/com/carvalhotechsolutions/mundoanimal/
+│ │ │ ├── controllers/
+│ │ │ ├── models/
+│ │ │ ├── repository/
+│ │ │ ├── services/
+│ │ ├── resources/
+│ │ │ ├── fxml/
+│ │ │ ├── images/
+│ │ │ ├── styles/
+│── pom.xml
+│── README.md
+```
+
+## 🤝 Contribuição
+Se deseja contribuir, siga os passos:
+1. Fork este repositório
+2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
+3. Commit suas alterações (`git commit -m 'Adiciona nova funcionalidade'`)
+4. Envie um push para a branch (`git push origin feature/nova-funcionalidade`)
+5. Abra um Pull Request
+
+## 📜 Licença
+Este projeto está sob a licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes.
+
+---
diff --git a/pom.xml b/pom.xml
index 5a30722..62a4c67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,10 +93,46 @@
fontawesomefx
8.2
+
+
+ io.github.typhon0
+ AnimateFX
+ 1.3.0
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.0
+ test
+
+
+
+
+ org.mockito
+ mockito-core
+ 5.5.0
+ test
+
+
+
+
+ com.h2database
+ h2
+ 2.3.232
+ test
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.2
+
org.apache.maven.plugins
maven-jar-plugin
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/Main.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/Main.java
index 00aedf6..1513553 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/Main.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/Main.java
@@ -1,48 +1,29 @@
package com.carvalhotechsolutions.mundoanimal;
+import animatefx.animation.FadeIn;
+import com.carvalhotechsolutions.mundoanimal.database.DatabaseChecker;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManager;
import javafx.application.Application;
-import javafx.application.Platform;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.scene.control.Alert;
import javafx.stage.Stage;
-import java.io.IOException;
-
public class Main extends Application {
@Override
- public void start(Stage stage) throws IOException {
-
- boolean isConnected = DatabaseChecker.testConnectionAndInitializeAdmin();
- if (!isConnected) {
- Alert alert = new Alert(Alert.AlertType.ERROR);
- alert.setTitle("Erro de Conexão");
- alert.setHeaderText("Não foi possível conectar ao banco de dados.");
- alert.setContentText("Verifique as configurações do banco e tente novamente.");
- alert.showAndWait();
- Platform.exit(); // Encerra a aplicação
- return;
- }
-
- // Carrega o arquivo FXML da interface principal
- FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/autenticacao/login.fxml"));
- Parent root = fxmlLoader.load();
-
- // Define a cena com o layout carregado
- Scene scene = new Scene(root);
- // Aplica o CSS à cena
- String css = this.getClass().getResource("/css/style.css").toExternalForm();
- scene.getStylesheets().add(css);
-
- // Configura o palco principal
- stage.setTitle("Login");
- stage.setScene(scene);
- stage.setFullScreen(true);
- stage.setFullScreenExitHint("");
- stage.setResizable(false);
- // Exibe a interface
+ public void start(Stage stage) {
+
+ // Verifica conexão com o banco de dados
+ DatabaseChecker.testConnectionAndInitializeAdmin();
+ // Inicializa o SceneManager
+ ScreenManager sceneManager = new ScreenManager(stage);
+ // Inicializa o SceneManagerHolder
+ ScreenManagerHolder.initialize(sceneManager);
+ // Seleciona a primeira tela da aplicação
+ sceneManager.switchTo(ScreenEnum.LOGIN);
+ // Exibe a tela
stage.show();
+ // Aplicando FadeIn (AnimateFX)
+ new FadeIn(sceneManager.getScreen(ScreenEnum.LOGIN)).play();
}
public static void main(String[] args) {
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/LoginController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/LoginController.java
similarity index 66%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/LoginController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/LoginController.java
index db50883..41e5c45 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/LoginController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/LoginController.java
@@ -1,18 +1,17 @@
-package com.carvalhotechsolutions.mundoanimal.controllers.login;
+package com.carvalhotechsolutions.mundoanimal.controllers.autenticacao;
-import com.carvalhotechsolutions.mundoanimal.JPAutil;
+import animatefx.animation.FadeIn;
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
import com.carvalhotechsolutions.mundoanimal.model.Usuario;
-import com.carvalhotechsolutions.mundoanimal.security.PasswordUtils;
-import com.carvalhotechsolutions.mundoanimal.utils.NavigationManager;
+import com.carvalhotechsolutions.mundoanimal.utils.PasswordManager;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
import com.carvalhotechsolutions.mundoanimal.utils.SessionManager;
import jakarta.persistence.EntityManager;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
-import javafx.scene.control.Alert;
-import javafx.scene.control.PasswordField;
-import javafx.scene.control.TextField;
-
-import java.io.IOException;
+import javafx.scene.Node;
+import javafx.scene.control.*;
public class LoginController {
@FXML
@@ -57,14 +56,23 @@ private void handleLogin(ActionEvent event) {
}
// Verifica a senha
- if (!PasswordUtils.checkPassword(password, usuario.getSenha())) {
+ if (!PasswordManager.checkPassword(password, usuario.getSenha())) {
showAlert("Erro", "Senha incorreta.");
return;
}
- // Login bem-sucedido - Direciona para o menu principal
+ // Login bem-sucedido
SessionManager.setCurrentUser(usuario);
- NavigationManager.switchScene(event, "/fxml/gerenciamento/menu.fxml", "Pet Shop Mundo Animal");
+
+// PopupManager.showLoginSuccessPopup(ScreenManagerHolder.getInstance().getStage());
+
+ // Atualiza a interface do menu através do ScreenManagerHolder
+ ScreenManagerHolder.getInstance().getMenuController().updateUserInterface(usuario);
+
+ // Chamando tela de menu e aplicando FadeIn
+ Node menuScreen = ScreenManagerHolder.getInstance().getScreen(ScreenEnum.MENU);
+ new FadeIn(menuScreen).play();
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.MENU);
} catch (Exception e) {
showAlert("Erro", "Ocorreu um erro ao verificar as credenciais: " + e.getMessage());
@@ -72,10 +80,9 @@ private void handleLogin(ActionEvent event) {
}
}
- // Método temporário, apenas para testar a troca de telas, não há lógica alguma aplicada
@FXML
- private void handleForgotPassword(ActionEvent event) throws IOException {
- NavigationManager.switchScene(event, "/fxml/autenticacao/recuperar-senha.fxml", "Recuperar senha");
+ private void handleForgotPassword() {
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.RECUPERAR_SENHA);
}
private void showAlert(String title, String message) {
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RecuperarSenhaController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RecuperarSenhaController.java
new file mode 100644
index 0000000..eb7decb
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RecuperarSenhaController.java
@@ -0,0 +1,110 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.autenticacao;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import com.carvalhotechsolutions.mundoanimal.model.Administrador;
+import com.carvalhotechsolutions.mundoanimal.model.Secretario;
+import com.carvalhotechsolutions.mundoanimal.model.Usuario;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
+import com.carvalhotechsolutions.mundoanimal.utils.SessionManager;
+import jakarta.persistence.EntityManager;
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.TextField;
+
+import java.io.IOException;
+
+public class RecuperarSenhaController {
+
+ @FXML
+ private TextField recovery_cpf_field;
+
+ @FXML
+ private TextField recovery_username_field;
+
+ // Método temporário, apenas para testar a troca de telas, não há lógica alguma aplicada
+ @FXML
+ private void backToLogin() throws IOException {
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.LOGIN);
+ }
+
+ @FXML
+ private void handleResetBtn() throws IOException {
+
+ String cpf = recovery_cpf_field.getText();
+ String username = recovery_username_field.getText();
+
+ if (cpf.isEmpty() || username.isEmpty()) {
+ showAlert("Erro.", "Por favor preencha todos os campos.");
+ return;
+ }
+
+ try (EntityManager em = JPAutil.getEntityManager()) {
+ Usuario usuario = null;
+
+ // Busca o CPF do administrador padrão
+ Administrador adminPadrao = em.createQuery(
+ "SELECT a FROM Administrador a WHERE a.nomeUsuario = 'admin'", Administrador.class)
+ .getSingleResult();
+
+ if (adminPadrao == null) {
+ showAlert("Erro", "Administrador padrão não encontrado no sistema.");
+ return;
+ }
+
+ // Busca o usuário pelo nome de usuário
+ Administrador admin = em.createQuery(
+ "SELECT a FROM Administrador a WHERE a.nomeUsuario = :username", Administrador.class)
+ .setParameter("username", username)
+ .getResultStream()
+ .findFirst()
+ .orElse(null);
+
+ if (admin != null) {
+ // Se for administrador, valida o CPF com o próprio admin padrão
+ if (!cpf.equals(admin.getCpf())) {
+ showAlert("Erro", "CPF inválido para o administrador.");
+ return;
+ }
+ usuario = admin;
+ } else {
+ // Se não for admin, busca em Secretário
+ Secretario secretario = em.createQuery(
+ "SELECT s FROM Secretario s WHERE s.nomeUsuario = :username", Secretario.class)
+ .setParameter("username", username)
+ .getResultStream()
+ .findFirst()
+ .orElse(null);
+
+ if (secretario == null) {
+ showAlert("Erro", "Usuário não encontrado.");
+ return;
+ }
+
+ // Valida o CPF do secretário com o CPF do administrador padrão
+ if (!cpf.equals(adminPadrao.getCpf())) {
+ showAlert("Erro", "CPF inválido para recuperação de senha.");
+ return;
+ }
+ usuario = secretario;
+ }
+
+ // Se passou todas as validações
+ SessionManager.setCurrentUser(usuario);
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.REDEFINIR_SENHA);
+
+ } catch (Exception e) {
+ showAlert("Erro", "Erro ao buscar usuário: " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ private void showAlert(String title, String message) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle(title);
+ alert.setHeaderText(null);
+ alert.setContentText(message);
+ alert.showAndWait();
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RedefinirSenhaController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RedefinirSenhaController.java
new file mode 100644
index 0000000..b044259
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/autenticacao/RedefinirSenhaController.java
@@ -0,0 +1,84 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.autenticacao;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import com.carvalhotechsolutions.mundoanimal.model.Usuario;
+import com.carvalhotechsolutions.mundoanimal.utils.PasswordManager;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
+import com.carvalhotechsolutions.mundoanimal.utils.SessionManager;
+import jakarta.persistence.EntityManager;
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.PasswordField;
+
+
+public class RedefinirSenhaController {
+
+ @FXML
+ private PasswordField reset_confirm_password;
+
+ @FXML
+ private PasswordField reset_new_password;
+
+ @FXML
+ private void handleResetPassword() {
+ String newPassword = reset_new_password.getText();
+ String confirmPassword = reset_confirm_password.getText();
+
+ if (newPassword.isEmpty() || confirmPassword.isEmpty()) {
+ showAlert("Erro", "Por favor, preencha todos os campos.");
+ return;
+ }
+
+ if (!newPassword.equals(confirmPassword)) {
+ showAlert("Erro", "As senhas não coincidem. Tente novamente.");
+ return;
+ }
+
+ if (newPassword.length() < 6) {
+ showAlert("Erro", "A senha deve ter no mínimo 6 caracteres.");
+ return;
+ }
+
+ try (EntityManager em = JPAutil.getEntityManager()) {
+ em.getTransaction().begin();
+
+ // Obtém o usuário da sessão
+ Usuario usuario = SessionManager.getCurrentUser();
+
+ if (usuario == null) {
+ showAlert("Erro", "Nenhum usuário autenticado. Tente novamente.");
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.LOGIN);
+ return;
+ }
+
+ // Atualiza a senha do usuário
+ usuario.setSenha(PasswordManager.hashPassword(newPassword)); // Hash da senha
+ em.merge(usuario); // Atualiza no banco
+ em.getTransaction().commit();
+
+ showAlert("Sucesso", "Senha redefinida com sucesso!");
+ SessionManager.clearSession();
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.LOGIN);
+
+ } catch (Exception e) {
+ showAlert("Erro", "Erro ao redefinir a senha: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ private void showAlert(String title, String message) {
+ Alert alert = new Alert(Alert.AlertType.INFORMATION);
+ alert.setTitle(title);
+ alert.setHeaderText(null);
+ alert.setContentText(message);
+ alert.showAndWait();
+ }
+
+
+ @FXML
+ private void backToRecovery() {
+ SessionManager.clearSession(); // Se ele desistir de redefinir a senha, deverá ser limpa a sessão
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.RECUPERAR_SENHA);
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AgendamentoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AgendamentoController.java
new file mode 100644
index 0000000..42b4bac
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AgendamentoController.java
@@ -0,0 +1,329 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarAgendamentoController;
+import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
+import com.carvalhotechsolutions.mundoanimal.repositories.AgendamentoRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.FeedbackManager;
+import javafx.beans.binding.DoubleBinding;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+import javafx.collections.transformation.SortedList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.HBox;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+
+import java.io.IOException;
+import java.net.URL;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.ResourceBundle;
+
+public class AgendamentoController implements Initializable {
+ @FXML
+ private HBox feedbackContainer;
+
+ @FXML
+ private TableView tableView;
+
+ @FXML
+ private TableColumn servicoColumn;
+
+ @FXML
+ private TableColumn horarioColumn;
+
+ @FXML
+ private TableColumn petColumn;
+
+ @FXML
+ private TableColumn clienteColumn;
+
+ @FXML
+ private TableColumn acaoColumn;
+
+ @FXML
+ private Label numberOfResults;
+
+ @FXML
+ private TextField filterField;
+
+ private FilteredList filteredData;
+
+ private AgendamentoRepository agendamentoRepository = new AgendamentoRepository();
+
+ private ObservableList agendamentosList = FXCollections.observableArrayList();
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
+
+ // Define a largura fixa da coluna de ação
+ acaoColumn.setPrefWidth(354);
+ acaoColumn.setMinWidth(354);
+ acaoColumn.setMaxWidth(354);
+
+ // Faz um bind da largura disponível (largura total da tabela menos a largura fixa da coluna de ação)
+ DoubleBinding larguraDisponivel = tableView.widthProperty().subtract(354);
+
+ // Configura as outras colunas para se redimensionarem proporcionalmente
+ servicoColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.22)); // 22% do espaço restante
+ horarioColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.34)); // 34% do espaço restante
+ petColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.22)); // 22% do espaço restante
+ clienteColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.22)); // 22% do espaço restante
+
+ servicoColumn.setCellValueFactory(new PropertyValueFactory<>("servico"));
+ horarioColumn.setCellValueFactory(new PropertyValueFactory<>("dataHoraFormatada"));
+ petColumn.setCellValueFactory(new PropertyValueFactory<>("animal"));
+ clienteColumn.setCellValueFactory(new PropertyValueFactory<>("cliente"));
+
+ configurarColunaAcao();
+ atualizarTableView();
+ configurarBuscaAgendamentos();
+ }
+
+ private void configurarColunaAcao() {
+ acaoColumn.setCellFactory(param -> new TableCell<>() {
+ private final Button editarButton = new Button("Editar");
+ private final Button cancelarButton = new Button("Cancelar");
+ private final Button finalizarButton = new Button("Finalizar");
+
+ private final HBox container = new HBox(editarButton, cancelarButton, finalizarButton);
+
+ {
+ // Estilizando os botões
+ editarButton.setStyle(
+ "-fx-background-color: #686AFF; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ cancelarButton.setStyle(
+ "-fx-background-color: #FF6F6F; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ finalizarButton.setStyle(
+ "-fx-background-color: #F2F5FA; -fx-font-size: 18px; -fx-text-fill: black; -fx-font-weight: 400; -fx-cursor: hand; -fx-min-width: 90px; -fx-border-color: #CCCCCC; -fx-border-radius: 2px;");
+
+ container.setSpacing(16);
+ container.setPadding(new Insets(0, 16, 0, 0));
+ container.setAlignment(Pos.CENTER);
+
+ // Configurar evento para deletar
+ cancelarButton.setOnAction(event -> {
+ Agendamento agendamento = getTableView().getItems().get(getIndex());
+ abrirModalCancelar(agendamento.getId());
+ });
+
+ // Configurar evento para editar
+ editarButton.setOnAction(event -> {
+ Agendamento agendamento = getTableView().getItems().get(getIndex());
+ abrirModalEditar(agendamento.getId());
+ });
+
+ // Configurar evento para finalizar
+ finalizarButton.setOnAction(event -> {
+ Agendamento agendamento = getTableView().getItems().get(getIndex());
+ abrirModalFinalizar(agendamento.getId());
+ });
+ }
+
+ @Override
+ protected void updateItem(Void item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty) {
+ setGraphic(null);
+ } else {
+ setGraphic(container);
+ }
+ }
+ });
+ }
+
+ private void abrirModalEditar(Long agendamentoId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarAgendamento.fxml"));
+ Parent modalContent = loader.load();
+
+ // Obter o controlador do modal
+ ModalCriarAgendamentoController modalController = loader.getController();
+ modalController.setAgendamentoController(this); // Passa referência do controlador principal
+
+ // Buscar o serviço pelo ID
+ Agendamento agendamento = agendamentoRepository.findById(agendamentoId);
+
+ // Configurar o modal para edição
+ modalController.configurarParaEdicao(agendamento);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Editar Agendamento");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ atualizarTableView();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void abrirModalCancelar(Long agendamentoId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalConfirmarRemocao.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalConfirmarRemocaoController modalController = loader.getController();
+ modalController.setRegisterId(agendamentoId);
+ modalController.configurarParaCancelamento();
+ modalController.setConfirmCallback(() -> {
+ agendamentoRepository.deleteById(agendamentoId);
+ atualizarTableView(); // Atualizar tabela após exclusão
+ handleSuccessfulOperation("Agendamento cancelado com sucesso!");
+ });
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Confirmar Cancelamento");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void abrirModalFinalizar(Long agendamentoId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarAgendamento.fxml"));
+ Parent modalContent = loader.load();
+
+ // Obter o controlador do modal
+ ModalCriarAgendamentoController modalController = loader.getController();
+ modalController.setAgendamentoController(this); // Passa referência do controlador principal
+
+ // Buscar o serviço pelo ID
+ Agendamento agendamento = agendamentoRepository.findById(agendamentoId);
+
+ // Configurar o modal para edição
+ modalController.configurarParaFinalizar(agendamento);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Editar Serviço");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ atualizarTableView();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void abrirModalCadastrarAgendamento() {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarAgendamento.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalCriarAgendamentoController modalController = loader.getController();
+ modalController.setAgendamentoController(this); // Passa referência do controlador principal
+
+ modalController.configurarParaCadastro();
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Cadastrar Agendamento");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.err.println("Erro ao abrir o modal: " + e.getMessage());
+ }
+ }
+
+ public void atualizarTableView() {
+ agendamentosList.setAll(agendamentoRepository.findAll());
+ numberOfResults.setText(agendamentosList.size() + " registro(s) retornado(s)");
+ }
+
+ public void configurarBuscaAgendamentos() {
+ filteredData = new FilteredList<>(agendamentosList, p -> true);
+ filterField.textProperty().addListener((observable, oldValue, newValue) -> {
+ filteredData.setPredicate(agendamento -> {
+ if (newValue == null || newValue.isEmpty()) {
+ return true;
+ }
+ String lowerCaseFilter = newValue.toLowerCase();
+
+ boolean matchesCliente = agendamento.getCliente().getNome().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesAnimal = agendamento.getAnimal().getNome().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesServico = agendamento.getServico().getNomeServico().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesData = agendamento.getDataHoraFormatada().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesStatus = agendamento.getStatus().toString().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesResponsavel = agendamento.getResponsavelAtendimento() != null &&
+ agendamento.getResponsavelAtendimento().toLowerCase().contains(lowerCaseFilter);
+
+ return matchesCliente || matchesAnimal || matchesServico ||
+ matchesData || matchesStatus || matchesResponsavel;
+ });
+// SortedList sortedData = new SortedList<>(filteredData);
+// sortedData.comparatorProperty().bind(tableView.comparatorProperty());
+//
+// tableView.setItems(sortedData);
+ numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
+ });
+ tableView.setItems(filteredData);
+ }
+
+ public void handleSuccessfulOperation(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.SUCCESS
+ );
+ }
+
+ public void handleError(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.ERROR
+ );
+ }
+
+ public void salvarAgendamento(Agendamento agendamento) {
+ boolean horarioDisponivel = verificarDisponibilidadeHorario(
+ agendamento.getDataAgendamento(),
+ agendamento.getHorarioAgendamento()
+ );
+
+ if (!horarioDisponivel && agendamento.getId() == null) {
+ throw new RuntimeException("Horário já está ocupado");
+ }
+
+ agendamentoRepository.save(agendamento);
+ }
+
+ private boolean verificarDisponibilidadeHorario(LocalDate data, LocalTime horario) {
+ // Lógica para verificar se já existe agendamento no mesmo horário
+ return agendamentoRepository.verificarDisponibilidadeHorario(data, horario);
+ }
+
+ public void finalizarAgendamento(Long id) {
+ agendamentoRepository.deleteById(id);
+ handleSuccessfulOperation("Agendamento finalizado com sucesso!");
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AnimalController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AnimalController.java
new file mode 100644
index 0000000..bbcd504
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/AnimalController.java
@@ -0,0 +1,293 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarClienteController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarPetController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalDetalhesPetController;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.repositories.AnimalRepository;
+import com.carvalhotechsolutions.mundoanimal.repositories.ClienteRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.FeedbackManager;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
+import javafx.beans.binding.DoubleBinding;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+import javafx.collections.transformation.SortedList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.HBox;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class AnimalController implements Initializable {
+ @FXML
+ private HBox feedbackContainer;
+
+ @FXML
+ private TableView tableView;
+
+ @FXML
+ private TableColumn nomeColumn;
+
+ @FXML
+ private TableColumn especieColumn;
+
+ @FXML
+ private TableColumn acaoColumn;
+
+ @FXML
+ private Label numberOfResults;
+
+ @FXML
+ private TextField filterField;
+
+ private FilteredList filteredData;
+
+ private Cliente cliente; // Dono dos pets que serão exibidos na tabela
+
+ private ObservableList petsList = FXCollections.observableArrayList();
+
+ private AnimalRepository animalRepository = new AnimalRepository();
+
+ private ClienteRepository clienteRepository = new ClienteRepository();
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
+
+ // Define a largura fixa da coluna de ação
+ acaoColumn.setPrefWidth(354);
+ acaoColumn.setMinWidth(354);
+ acaoColumn.setMaxWidth(354);
+
+ // Faz um bind da largura disponível (largura total da tabela menos a largura fixa da coluna de ação)
+ DoubleBinding larguraDisponivel = tableView.widthProperty().subtract(354);
+
+ // Configura as outras colunas para se redimensionarem proporcionalmente
+ nomeColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.50)); // 50% do espaço restante
+ especieColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.50)); // 50% do espaço restante
+
+ // Configurar colunas
+ nomeColumn.setCellValueFactory(new PropertyValueFactory<>("nome"));
+ especieColumn.setCellValueFactory(new PropertyValueFactory<>("especie"));
+
+ // Configurar botões da coluna de ações
+ configurarColunaAcao();
+ }
+
+ private void configurarColunaAcao() {
+ acaoColumn.setCellFactory(param -> new TableCell<>() {
+ private final Button editarButton = new Button("Editar");
+ private final Button deletarButton = new Button("Deletar");
+ private final Button detalhesButton = new Button("Detalhes");
+
+ private final HBox container = new HBox(editarButton, deletarButton, detalhesButton);
+
+ {
+ // Estilizando os botões
+ editarButton.setStyle(
+ "-fx-background-color: #686AFF; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ deletarButton.setStyle(
+ "-fx-background-color: #FF6F6F; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ detalhesButton.setStyle(
+ "-fx-background-color: #F2F5FA; -fx-font-size: 18px; -fx-text-fill: black; -fx-font-weight: 400; -fx-cursor: hand; -fx-min-width: 90px; -fx-border-color: #CCCCCC; -fx-border-radius: 2px;");
+
+ container.setSpacing(16);
+ container.setPadding(new Insets(0, 16, 0, 0));
+ container.setAlignment(Pos.CENTER);
+
+ // Configurar evento para deletar
+ deletarButton.setOnAction(event -> {
+ Animal animal = getTableView().getItems().get(getIndex());
+ abrirModalExcluir(animal.getId());
+ });
+
+ // Configurar evento para editar
+ editarButton.setOnAction(event -> {
+ Animal animal = getTableView().getItems().get(getIndex());
+ abrirModalEditar(animal.getId());
+ });
+
+ detalhesButton.setOnAction(event -> {
+ Animal animal = getTableView().getItems().get(getIndex());
+ abrirModalDetalhes(animal.getId());
+ });
+ }
+
+ @Override
+ protected void updateItem(Void item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty) {
+ setGraphic(null);
+ } else {
+ setGraphic(container);
+ }
+ }
+ });
+ }
+
+ private void abrirModalDetalhes(Long animalId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalDetalhesPet.fxml"));
+ Parent modalContent = loader.load();
+
+ // Obter o controlador do modal
+ ModalDetalhesPetController modalController = loader.getController();
+
+ // Buscar o serviço pelo ID
+ Animal animal = animalRepository.findById(animalId);
+
+ // Configurar o modal para edição
+ modalController.configurarParaExibicao(animal);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Detalhes do Pet");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void abrirModalEditar(Long animalId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarPet.fxml"));
+ Parent modalContent = loader.load();
+
+ // Obter o controlador do modal
+ ModalCriarPetController modalController = loader.getController();
+ modalController.setAnimalController(this);
+
+ // Buscar o serviço pelo ID
+ Animal animal = animalRepository.findById(animalId);
+
+ // Configurar o modal para edição
+ modalController.configurarParaEdicao(animal);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Editar Pet");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ // Recarrega o cliente do banco de dados para ter a lista atualizada
+ cliente = clienteRepository.findById(cliente.getId());
+
+ // Atualiza a página de clientes
+ ScreenManagerHolder.getInstance().getClienteController().atualizarTableView();
+ atualizarTableView();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void abrirModalExcluir(Long animalId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalConfirmarRemocao.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalConfirmarRemocaoController modalController = loader.getController();
+ modalController.setRegisterId(animalId);
+ modalController.setConfirmCallback(() -> {
+ animalRepository.deleteById(animalId);
+
+ // Recarrega o cliente do banco de dados para ter a lista atualizada
+ cliente = clienteRepository.findById(cliente.getId());
+
+ // Atualiza a página de clientes
+ ScreenManagerHolder.getInstance().getClienteController().atualizarTableView();
+ atualizarTableView();
+ handleSuccessfulOperation("Pet removido com sucesso!");
+ });
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Confirmar Exclusão");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void configurarBuscaPets() {
+ filteredData = new FilteredList<>(petsList, p -> true);
+ filterField.textProperty().addListener((observable, oldValue, newValue) -> {
+ filteredData.setPredicate(animal -> {
+ if (newValue == null || newValue.isEmpty()) {
+ return true;
+ }
+ String lowerCaseFilter = newValue.toLowerCase();
+ boolean matchesNome = animal.getNome().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesEspecie = animal.getEspecie().toString().toLowerCase().contains(lowerCaseFilter);
+
+ return matchesNome || matchesEspecie;
+ });
+
+ SortedList sortedData = new SortedList<>(filteredData);
+ sortedData.comparatorProperty().bind(tableView.comparatorProperty());
+
+ tableView.setItems(sortedData);
+ numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
+ });
+ }
+
+ public void voltarParaPaginaClientes() {
+ filterField.clear();
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.CLIENTES);
+ }
+
+ public void setCliente(Cliente cliente) {
+ this.cliente = cliente;
+ atualizarTableView();
+ configurarBuscaPets();
+ }
+
+ public void atualizarTableView() {
+ petsList.setAll(cliente.getPets());
+ tableView.setItems(petsList);
+ numberOfResults.setText(petsList.size() + " registro(s) retornado(s)");
+ }
+
+ public void handleSuccessfulOperation(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.SUCCESS
+ );
+ }
+
+ public void handleError(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.ERROR
+ );
+ }
+}
+
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ClienteController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ClienteController.java
new file mode 100644
index 0000000..72675bf
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ClienteController.java
@@ -0,0 +1,325 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarClienteController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarPetController;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.repositories.ClienteRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.FeedbackManager;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
+import jakarta.persistence.RollbackException;
+import javafx.beans.binding.DoubleBinding;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.HBox;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+
+import java.io.IOException;
+import java.net.URL;
+import java.sql.SQLException;
+import java.util.ResourceBundle;
+
+public class ClienteController implements Initializable {
+ @FXML
+ private HBox feedbackContainer;
+
+ @FXML
+ private TableView tableView;
+
+ @FXML
+ private TableColumn nomeColumn;
+
+ @FXML
+ private TableColumn telefoneColumn;
+
+ @FXML
+ private TableColumn petsColumn;
+
+ @FXML
+ private TableColumn acaoColumn;
+
+ @FXML
+ private Label numberOfResults;
+
+ @FXML
+ private TextField filterField;
+
+ private ClienteRepository clienteRepository = new ClienteRepository();
+
+ private ObservableList clientesList = FXCollections.observableArrayList();
+
+ private FilteredList filteredData;
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
+
+ // Define a largura fixa da coluna de ação
+ acaoColumn.setPrefWidth(462);
+ acaoColumn.setMinWidth(462);
+ acaoColumn.setMaxWidth(462);
+
+ // Faz um bind da largura disponível (largura total da tabela menos a largura fixa da coluna de ação)
+ DoubleBinding larguraDisponivel = tableView.widthProperty().subtract(462);
+
+ // Configura as outras colunas para se redimensionarem proporcionalmente
+ nomeColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.33)); // 33% do espaço restante
+ telefoneColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.33)); // 33% do espaço restante
+ petsColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.34)); // 34% do espaço restante
+
+ nomeColumn.setCellValueFactory(new PropertyValueFactory<>("nome"));
+ telefoneColumn.setCellValueFactory(new PropertyValueFactory<>("telefone"));
+ petsColumn.setCellValueFactory(cellData ->
+ new SimpleStringProperty(cellData.getValue().getPetsFormatados())
+ );
+
+ configurarColunaAcao();
+ atualizarTableView();
+ configurarBuscaClientes(); // apos atualizarTableView()
+ }
+
+ private void configurarColunaAcao() {
+ acaoColumn.setCellFactory(param -> new TableCell<>() {
+ private final Button editarButton = new Button("Editar");
+ private final Button deletarButton = new Button("Deletar");
+ private final Button novoPetButton = new Button("Novo pet");
+ private final Button verPetsButton = new Button("Ver pets");
+
+ private final HBox container = new HBox(editarButton, deletarButton, novoPetButton, verPetsButton);
+
+ {
+ // Estilizando os botões
+ editarButton.setStyle(
+ "-fx-background-color: #686AFF; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ deletarButton.setStyle(
+ "-fx-background-color: #FF6F6F; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ novoPetButton.setStyle(
+ "-fx-background-color: #2cc428; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ verPetsButton.setStyle(
+ "-fx-background-color: #F2F5FA; -fx-font-size: 18px; -fx-text-fill: black; -fx-font-weight: 400; -fx-cursor: hand; -fx-min-width: 90px; -fx-border-color: #CCCCCC; -fx-border-radius: 2px;");
+
+ container.setSpacing(16);
+ container.setPadding(new Insets(0, 16, 0, 0));
+ container.setAlignment(Pos.CENTER);
+
+ // Configurar evento para deletar
+ deletarButton.setOnAction(event -> {
+ Cliente cliente = getTableView().getItems().get(getIndex());
+ abrirModalExcluir(cliente.getId());
+ });
+
+ // Configurar evento para editar
+ editarButton.setOnAction(event -> {
+ Cliente cliente = getTableView().getItems().get(getIndex());
+ abrirModalEditar(cliente.getId());
+ });
+
+ novoPetButton.setOnAction(event -> {
+ Cliente cliente = getTableView().getItems().get(getIndex());
+ abrirModalCadastrarPet(cliente.getId());
+ });
+
+ verPetsButton.setOnAction(event -> {
+ Cliente cliente = getTableView().getItems().get(getIndex());
+ abrirPaginaVerPets(cliente);
+ });
+ }
+
+ @Override
+ protected void updateItem(Void item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty) {
+ setGraphic(null);
+ } else {
+ setGraphic(container);
+ }
+ }
+ });
+ }
+
+ @FXML
+ public void abrirModalCadastrarCliente() {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarCliente.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalCriarClienteController modalController = loader.getController();
+ modalController.setClienteController(this); // Passa referência do controlador principal
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Cadastrar Cliente");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.err.println("Erro ao abrir o modal: " + e.getMessage());
+ }
+ }
+
+ private void abrirModalEditar(Long clienteId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarCliente.fxml"));
+ Parent modalContent = loader.load();
+
+ // Obter o controlador do modal
+ ModalCriarClienteController modalController = loader.getController();
+ modalController.setClienteController(this); // Passa referência do controlador principal
+
+ // Buscar o serviço pelo ID
+ Cliente cliente = clienteRepository.findById(clienteId);
+
+ // Configurar o modal para edição
+ modalController.configurarParaEdicao(cliente);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Editar Serviço");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ atualizarTableView();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void abrirModalExcluir(Long clienteId) {
+ if (clienteRepository.clientePossuiAgendamentos(clienteId)) {
+ handleError("Cliente possui agendamento(s) pendente(s)");
+ return;
+ }
+
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalConfirmarRemocao.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalConfirmarRemocaoController modalController = loader.getController();
+ modalController.setRegisterId(clienteId);
+ modalController.setConfirmCallback(() -> {
+ clienteRepository.deleteById(clienteId);
+ atualizarTableView(); // Atualizar tabela após exclusão
+ handleSuccessfulOperation("Cliente removido com sucesso!");
+ });
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Confirmar Exclusão");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void abrirModalCadastrarPet(Long clienteId) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarPet.fxml"));
+ Parent modalContent = loader.load();
+
+ // Configurar o controlador do modal
+ ModalCriarPetController modalController = loader.getController();
+ modalController.setClienteController(this); // Passa referência do controlador principal
+
+ // Configurar campos do cliente no modal
+ modalController.configurarParaCadastro(clienteId);
+
+ // Configurar o Stage do modal
+ Stage modalStage = new Stage();
+ modalStage.initModality(Modality.APPLICATION_MODAL);
+ modalStage.setTitle("Cadastrar Pet");
+ modalStage.setScene(new Scene(modalContent));
+ modalStage.setResizable(false);
+ modalStage.showAndWait();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.err.println("Erro ao abrir o modal: " + e.getMessage());
+ }
+ }
+
+ private void abrirPaginaVerPets(Cliente cliente) {
+ if (cliente.getPets().isEmpty()) {
+ handleError("Este cliente não possui pets cadastrados!");
+ return;
+ }
+
+ // Configurar o controlador do modal
+ AnimalController animalController = ScreenManagerHolder.getInstance().getAnimalController();
+ animalController.setCliente(cliente);
+ animalController.atualizarTableView();
+
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.PETS);
+ }
+
+ public void atualizarTableView() {
+ clientesList.setAll(clienteRepository.findAll());
+ numberOfResults.setText(clientesList.size() + " registro(s) retornado(s)");
+ }
+
+ private void configurarBuscaClientes() {
+ filteredData = new FilteredList<>(clientesList, p -> true);
+ filterField.textProperty().addListener((observable, oldValue, newValue) -> {
+ filteredData.setPredicate(cliente -> {
+ if (newValue == null || newValue.isEmpty()) {
+ return true;
+ }
+ String lowerCaseFilter = newValue.toLowerCase();
+ boolean matchesCliente = cliente.getNome().toLowerCase().contains(lowerCaseFilter) ||
+ cliente.getTelefone().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesPet = cliente.getPets().stream()
+ .anyMatch(pet -> pet.getNome().toLowerCase().contains(lowerCaseFilter));
+ return matchesCliente || matchesPet;
+ });
+ numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
+ });
+ tableView.setItems(filteredData);
+ }
+
+ public void handleSuccessfulOperation(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.SUCCESS
+ );
+ }
+
+ public void handleError(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.ERROR
+ );
+ }
+
+ private void mostrarAlerta(String titulo, String mensagem, Alert.AlertType tipo) {
+ Alert alerta = new Alert(tipo);
+ alerta.setTitle(titulo);
+ alerta.setHeaderText(null);
+ alerta.setContentText(mensagem);
+ alerta.showAndWait();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/MenuController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/MenuController.java
similarity index 54%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/MenuController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/MenuController.java
index cc1f26f..562f3b1 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/MenuController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/MenuController.java
@@ -1,14 +1,15 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+import animatefx.animation.FadeIn;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
import com.carvalhotechsolutions.mundoanimal.model.Usuario;
-import com.carvalhotechsolutions.mundoanimal.model.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.utils.ScreenManagerHolder;
import com.carvalhotechsolutions.mundoanimal.utils.SessionManager;
+import javafx.application.Platform;
import javafx.fxml.FXML;
-import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
@@ -16,17 +17,11 @@
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
-
-import java.io.IOException;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
public class MenuController implements Initializable {
- @FXML
- private StackPane contentArea;
-
@FXML
private Button inicio_btn;
@@ -61,37 +56,46 @@ public class MenuController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
- Usuario usuarioLogado = SessionManager.getCurrentUser();
- if (usuarioLogado.getTipoUsuario() == TipoUsuario.SECRETARIO) {
- servicos_btn.setVisible(false);
- secretarios_btn.setVisible(false);
- userTypeLabel.setText("Secretário");
- }
- userNameLabel.setText(usuarioLogado.getNomeUsuario());
// Set up button actions
- servicos_btn.setOnAction(event -> loadPage("servicos.fxml"));
- secretarios_btn.setOnAction(event -> loadPage("secretarios.fxml"));
sair_btn.setOnAction(event -> logout());
+
// Configure ações para cada botão
- configureButton(inicio_btn, "inicio.fxml");
- configureButton(clientes_btn, "clientes.fxml");
- configureButton(agendamentos_btn, "agendamentos.fxml");
- configureButton(historico_btn, "historico.fxml");
- configureButton(relatorio_btn, "relatorio.fxml");
- configureButton(secretarios_btn, "secretarios.fxml");
- configureButton(servicos_btn, "servicos.fxml");
+// configureButton(inicio_btn, "inicio.fxml");
+// configureButton(historico_btn, "historico.fxml");
+// configureButton(relatorio_btn, "relatorio.fxml");
+ configureButton(agendamentos_btn, ScreenEnum.AGENDAMENTOS);
+ configureButton(secretarios_btn, ScreenEnum.SECRETARIOS);
+ configureButton(servicos_btn, ScreenEnum.SERVICOS);
+ configureButton(clientes_btn, ScreenEnum.CLIENTES);
+ }
+
+ public void updateUserInterface(Usuario usuario) {
+ Platform.runLater(() -> {
+ userNameLabel.setText(usuario.getNomeUsuario());
+ userTypeLabel.setText(usuario.getTipoUsuario() == TipoUsuario.SECRETARIO ? "Secretário(a)" : "Administrador(a)");
+
+ boolean isSecretario = usuario.getTipoUsuario() == TipoUsuario.SECRETARIO;
+ servicos_btn.setVisible(!isSecretario);
+ secretarios_btn.setVisible(!isSecretario);
+ });
}
- private void configureButton(Button button, String fxmlFile) {
+ private void configureButton(Button button, ScreenEnum screen) {
button.setOnAction(event -> {
// Gerenciar o botão ativo
setActiveButton(button);
// Carregar a página no contentArea
- loadPage(fxmlFile);
+ Node animatedScreen = ScreenManagerHolder.getInstance().getScreen(screen);
+ new FadeIn(animatedScreen).play();
+ ScreenManagerHolder.getInstance().switchTo(screen);
});
}
+ public Button getActiveButton() {
+ return activeButton;
+ }
+
private void setActiveButton(Button button) {
// Remover a classe 'active' do botão anteriormente ativo, se houver
if (activeButton != null) {
@@ -105,17 +109,6 @@ private void setActiveButton(Button button) {
activeButton = button;
}
- private void loadPage(String fxmlFile) {
- try {
- // Carregar a nova página dentro do contentArea
- Node page = FXMLLoader.load(getClass().getResource("/fxml/gerenciamento/" + fxmlFile));
- contentArea.getChildren().clear();
- contentArea.getChildren().add(page);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
private void logout() {
// Cria um alerta de confirmação
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
@@ -135,17 +128,13 @@ private void logout() {
// Verifica a escolha
if (result.isPresent() && result.get() == ButtonType.OK) {
- try {
- Stage stage = (Stage) contentArea.getScene().getWindow(); // Obtém o estágio atual a partir do contentArea
- Parent loginPage = FXMLLoader.load(getClass().getResource("/fxml/autenticacao/login.fxml")); // Carrega a página de login
- Scene newScene = new Scene(loginPage); // Cria uma nova cena com a página de login carregada
- stage.setScene(newScene); // Define a nova cena no estágio
- stage.show(); // Exibe o estágio atualizado
-
- SessionManager.setCurrentUser(null); // Limpa o usuário logado
- } catch (IOException e) {
- e.printStackTrace();
+ if (activeButton != null) {
+ activeButton.getStyleClass().remove("active");
}
+ ScreenManagerHolder.getInstance().switchTo(ScreenEnum.LOGIN);
+ SessionManager.setCurrentUser(null); // Limpa o usuário logado
+ Node loginScreen = ScreenManagerHolder.getInstance().getScreen(ScreenEnum.LOGIN);
+ new FadeIn(loginScreen).play();
} else {
// Usuário cancelou a ação
alert.close();
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/SecretarioController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/SecretarioController.java
similarity index 59%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/SecretarioController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/SecretarioController.java
index 74d46f9..2987089 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/SecretarioController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/SecretarioController.java
@@ -1,11 +1,15 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarSecretarioController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalEditarSecretarioController;
import com.carvalhotechsolutions.mundoanimal.model.Secretario;
-import com.carvalhotechsolutions.mundoanimal.model.Servico;
import com.carvalhotechsolutions.mundoanimal.repositories.SecretarioRepository;
-import com.carvalhotechsolutions.mundoanimal.repositories.ServicoRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.FeedbackManager;
+import javafx.beans.binding.DoubleBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
@@ -13,10 +17,7 @@
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.TableCell;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
+import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.stage.Modality;
@@ -28,7 +29,13 @@
public class SecretarioController implements Initializable {
@FXML
- private TableView tableViewSecretarios;
+ private HBox feedbackContainer;
+
+ @FXML
+ private Label numberOfResults;
+
+ @FXML
+ private TableView tableView;
@FXML
private TableColumn nomeColumn; // Nome de Usuario
@@ -39,24 +46,43 @@ public class SecretarioController implements Initializable {
@FXML
private TableColumn acaoColumn; // Ação
+ @FXML
+ private TextField filterField;
+
private SecretarioRepository secretarioRepository = new SecretarioRepository();
- private ObservableList secretariosList;
+ private ObservableList secretariosList = FXCollections.observableArrayList();
+
+ private FilteredList filteredData;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
+
+ // Define a largura fixa da coluna de ação
+ acaoColumn.setPrefWidth(246);
+ acaoColumn.setMinWidth(246);
+ acaoColumn.setMaxWidth(246);
+
+ // Faz um bind da largura disponível (largura total da tabela menos a largura fixa da coluna de ação)
+ DoubleBinding larguraDisponivel = tableView.widthProperty().subtract(246);
+
+ // Configura as outras colunas para se redimensionarem proporcionalmente
+ nomeColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.50)); // 50% do espaço restante
+ phoneColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.50)); // 50% do espaço restante
+
nomeColumn.setCellValueFactory(new PropertyValueFactory<>("nomeUsuario"));
phoneColumn.setCellValueFactory(new PropertyValueFactory<>("telefone"));
configurarColunaAcao();
-
atualizarTableView();
+ configurarBuscaSecretarios();
}
public void atualizarTableView() {
- secretariosList = FXCollections.observableArrayList(secretarioRepository.findAll());
- tableViewSecretarios.setItems(secretariosList);
+ secretariosList.setAll(secretarioRepository.findAll());
+ numberOfResults.setText(secretariosList.size() + " registro(s) retornado(s)");
}
private void configurarColunaAcao() {
@@ -67,10 +93,13 @@ private void configurarColunaAcao() {
{
// Estilize os botões
- editarButton.setStyle("-fx-background-color: #2E86C1; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand;");
- deletarButton.setStyle("-fx-background-color: #C0392B; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand;");
- container.setSpacing(18);
- container.setPadding(new Insets(10, 24, 10, 24));
+ editarButton.setStyle(
+ "-fx-background-color: #686AFF; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ deletarButton.setStyle(
+ "-fx-background-color: #FF6F6F; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+
+ container.setSpacing(16);
+ container.setPadding(new Insets(0, 16, 0, 0));
container.setAlignment(Pos.CENTER);
// Configurar evento para deletar
@@ -101,7 +130,7 @@ protected void updateItem(Void item, boolean empty) {
@FXML
public void abrirModalCadastrarSecretario() {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-novo-secretario.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarSecretario.fxml"));
Parent modalContent = loader.load();
// Configurar o controlador do modal
@@ -124,11 +153,12 @@ public void abrirModalCadastrarSecretario() {
private void abrirModalEditar(Long secretarioId) {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-editar-secretario.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalEditarSecretario.fxml"));
Parent modalContent = loader.load();
// Obter o controlador do modal
ModalEditarSecretarioController modalController = loader.getController();
+ modalController.setSecretarioController(this);
// Buscar o serviço pelo ID
Secretario secretario = secretarioRepository.findById(secretarioId);
@@ -153,15 +183,16 @@ private void abrirModalEditar(Long secretarioId) {
private void abrirModalExcluir(Long secretarioId) {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-confirmar-remocao.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalConfirmarRemocao.fxml"));
Parent modalContent = loader.load();
// Configurar o controlador do modal
ModalConfirmarRemocaoController modalController = loader.getController();
- modalController.setServicoId(secretarioId);
+ modalController.setRegisterId(secretarioId);
modalController.setConfirmCallback(() -> {
secretarioRepository.deleteById(secretarioId);
atualizarTableView(); // Atualizar tabela após exclusão
+ handleSuccessfulOperation("Secretário(a) removido(a) com sucesso!");
});
// Configurar o Stage do modal
@@ -177,4 +208,36 @@ private void abrirModalExcluir(Long secretarioId) {
}
}
+ private void configurarBuscaSecretarios() {
+ filteredData = new FilteredList<>(secretariosList, p -> true);
+ filterField.textProperty().addListener((observable, oldValue, newValue) -> {
+ filteredData.setPredicate(secretario -> {
+ if (newValue == null || newValue.isEmpty()) {
+ return true;
+ }
+ String lowerCaseFilter = newValue.toLowerCase();
+ return secretario.getNomeUsuario().toLowerCase().contains(lowerCaseFilter)
+ || secretario.getTelefone().toLowerCase().contains(lowerCaseFilter);
+ });
+ numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
+ });
+ tableView.setItems(filteredData);
+ }
+
+ public void handleSuccessfulOperation(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.SUCCESS
+ );
+ }
+
+ public void handleError(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.ERROR
+ );
+ }
+
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ServicoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ServicoController.java
similarity index 60%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ServicoController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ServicoController.java
index de04c48..58a4540 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ServicoController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/gerenciamento/ServicoController.java
@@ -1,9 +1,14 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalConfirmarRemocaoController;
+import com.carvalhotechsolutions.mundoanimal.controllers.modals.ModalCriarServicoController;
import com.carvalhotechsolutions.mundoanimal.model.Servico;
import com.carvalhotechsolutions.mundoanimal.repositories.ServicoRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.FeedbackManager;
+import javafx.beans.binding.DoubleBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
@@ -11,10 +16,7 @@
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.TableCell;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
+import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.stage.Modality;
@@ -26,6 +28,12 @@
import java.util.ResourceBundle;
public class ServicoController implements Initializable {
+ @FXML
+ private HBox feedbackContainer;
+
+ @FXML
+ private Label numberOfResults;
+
@FXML
private TableView tableView;
@@ -41,12 +49,32 @@ public class ServicoController implements Initializable {
@FXML
private TableColumn acaoColumn;
+ @FXML
+ private TextField filterField;
+
private ServicoRepository servicoRepository = new ServicoRepository();
private ObservableList servicosList = FXCollections.observableArrayList();
+ private FilteredList filteredData;
+
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
+ tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
+
+ // Define a largura fixa da coluna de ação
+ acaoColumn.setPrefWidth(246);
+ acaoColumn.setMinWidth(246);
+ acaoColumn.setMaxWidth(246);
+
+ // Faz um bind da largura disponível (largura total da tabela menos a largura fixa da coluna de ação)
+ DoubleBinding larguraDisponivel = tableView.widthProperty().subtract(246);
+
+ // Configura as outras colunas para se redimensionarem proporcionalmente
+ nomeColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.25)); // 25% do espaço restante
+ descricaoColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.60)); // 60% do espaço restante
+ valorColumn.prefWidthProperty().bind(larguraDisponivel.multiply(0.15)); // 15% do espaço restante
+
nomeColumn.setCellValueFactory(new PropertyValueFactory<>("nomeServico"));
descricaoColumn.setCellValueFactory(new PropertyValueFactory<>("descricao"));
valorColumn.setCellValueFactory(new PropertyValueFactory<>("valorServico"));
@@ -54,6 +82,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) {
configurarColunaValor();
configurarColunaAcao();
atualizarTableView();
+ configurarBuscaServicos();
}
private void configurarColunaAcao() {
@@ -64,10 +93,13 @@ private void configurarColunaAcao() {
{
// Estilize os botões
- editarButton.setStyle("-fx-background-color: #2E86C1; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand;");
- deletarButton.setStyle("-fx-background-color: #C0392B; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand;");
- container.setSpacing(18);
- container.setPadding(new Insets(10, 24, 10, 24));
+ editarButton.setStyle(
+ "-fx-background-color: #686AFF; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+ deletarButton.setStyle(
+ "-fx-background-color: #FF6F6F; -fx-font-size: 18px; -fx-text-fill: white; -fx-font-weight: 800; -fx-cursor: hand; -fx-min-width: 90px;");
+
+ container.setSpacing(16);
+ container.setPadding(new Insets(0, 16, 0, 0));
container.setAlignment(Pos.CENTER);
// Configurar evento para deletar
@@ -115,7 +147,7 @@ protected void updateItem(BigDecimal item, boolean empty) {
@FXML
public void abrirModalCadastrarServico() {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-novo-servico.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarServico.fxml"));
Parent modalContent = loader.load();
// Configurar o controlador do modal
@@ -138,11 +170,12 @@ public void abrirModalCadastrarServico() {
private void abrirModalEditar(Long servicoId) {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-novo-servico.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalCriarServico.fxml"));
Parent modalContent = loader.load();
// Obter o controlador do modal
ModalCriarServicoController modalController = loader.getController();
+ modalController.setServicoController(this);
// Buscar o serviço pelo ID
Servico servico = servicoRepository.findById(servicoId);
@@ -167,15 +200,16 @@ private void abrirModalEditar(Long servicoId) {
private void abrirModalExcluir(Long servicoId) {
try {
- FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modal-confirmar-remocao.fxml"));
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/modals/modalConfirmarRemocao.fxml"));
Parent modalContent = loader.load();
// Configurar o controlador do modal
ModalConfirmarRemocaoController modalController = loader.getController();
- modalController.setServicoId(servicoId);
+ modalController.setRegisterId(servicoId);
modalController.setConfirmCallback(() -> {
servicoRepository.deleteById(servicoId);
atualizarTableView(); // Atualizar tabela após exclusão
+ handleSuccessfulOperation("Serviço removido com sucesso!");
});
// Configurar o Stage do modal
@@ -192,9 +226,46 @@ private void abrirModalExcluir(Long servicoId) {
}
public void atualizarTableView() {
- servicosList = FXCollections.observableArrayList(servicoRepository.findAll());
- tableView.setItems(servicosList);
+ servicosList.setAll(servicoRepository.findAll());
+ numberOfResults.setText(servicosList.size() + " registro(s) retornado(s)");
}
+ private void configurarBuscaServicos() {
+ filteredData = new FilteredList<>(servicosList, p -> true);
+ filterField.textProperty().addListener((observable, oldValue, newValue) -> {
+ filteredData.setPredicate(servico -> {
+ if (newValue == null || newValue.isEmpty()) {
+ return true; // Se o campo de busca estiver vazio, mostra todos os serviços
+ }
+ String lowerCaseFilter = newValue.toLowerCase();
+
+ // Verificando se o nome do serviço, descrição ou preço contém o termo de busca
+ boolean matchesNome = servico.getNomeServico().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesDescricao = servico.getDescricao() != null && servico.getDescricao().toLowerCase().contains(lowerCaseFilter);
+ boolean matchesPreco = servico.getValorServico().toString().contains(newValue); // Comparando com o preço
+
+ // Retorna true se qualquer um dos campos for um match
+ return matchesNome || matchesDescricao || matchesPreco;
+ });
+ numberOfResults.setText(filteredData.size() + " registro(s) retornado(s)");
+ });
+ tableView.setItems(filteredData);
+ }
+
+ public void handleSuccessfulOperation(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.SUCCESS
+ );
+ }
+
+ public void handleError(String message) {
+ FeedbackManager.showFeedback(
+ feedbackContainer,
+ message,
+ FeedbackManager.FeedbackType.ERROR
+ );
+ }
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RecuperarSenhaController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RecuperarSenhaController.java
deleted file mode 100644
index 53bd2c5..0000000
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RecuperarSenhaController.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.carvalhotechsolutions.mundoanimal.controllers.login;
-
-import com.carvalhotechsolutions.mundoanimal.utils.NavigationManager;
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-
-import java.io.IOException;
-
-public class RecuperarSenhaController {
- // Método temporário, apenas para testar a troca de telas, não há lógica alguma aplicada
- @FXML
- private void backToLogin(ActionEvent event) throws IOException {
- NavigationManager.switchScene(event, "/fxml/autenticacao/login.fxml", "Login");
- }
-
- // Método temporário, apenas para testar a troca de telas, não há lógica alguma aplicada
- @FXML
- private void handleResetBtn(ActionEvent event) throws IOException {
- NavigationManager.switchScene(event, "/fxml/autenticacao/redefinir-senha.fxml", "Redefinir senha");
- }
-}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RedefinirSenhaController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RedefinirSenhaController.java
deleted file mode 100644
index 5882cd7..0000000
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/login/RedefinirSenhaController.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.carvalhotechsolutions.mundoanimal.controllers.login;
-
-import com.carvalhotechsolutions.mundoanimal.utils.NavigationManager;
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-
-import java.io.IOException;
-
-public class RedefinirSenhaController {
- // Método temporário, apenas para testar a troca de telas, não há lógica alguma aplicada
- @FXML
- private void backToRecovery(ActionEvent event) throws IOException {
- NavigationManager.switchScene(event, "/fxml/autenticacao/recuperar-senha.fxml", "Recuperar senha");
- }
-}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalConfirmarRemocaoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalConfirmarRemocaoController.java
similarity index 60%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalConfirmarRemocaoController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalConfirmarRemocaoController.java
index 1d57660..f366294 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalConfirmarRemocaoController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalConfirmarRemocaoController.java
@@ -1,23 +1,30 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
+import javafx.scene.control.Label;
import javafx.stage.Stage;
public class ModalConfirmarRemocaoController {
+ @FXML
+ private Label modalMessage;
+
+ @FXML
+ private Label modalTitle;
+
@FXML
private Button cancelarButton;
@FXML
private Button deletarButton;
- private Long servicoId; // Armazena o ID do serviço a ser excluído
+ private Long registerId; // Armazena o ID do registro a ser excluído
private Runnable confirmCallback; // Função para executar após confirmação
// Define o ID do serviço
- public void setServicoId(Long servicoId) {
- this.servicoId = servicoId;
+ public void setRegisterId(Long registerIdId) {
+ this.registerId = registerId;
}
// Define a ação a ser executada após confirmação
@@ -42,4 +49,11 @@ private void fecharModal() {
Stage stage = (Stage) cancelarButton.getScene().getWindow();
stage.close();
}
+
+ public void configurarParaCancelamento() {
+ modalTitle.setText("Confirmar Cancelamento");
+ modalMessage.setText("Cancelar este agendamento permanentemente?");
+ deletarButton.setText("Sim");
+ cancelarButton.setText("Não");
+ }
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarAgendamentoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarAgendamentoController.java
new file mode 100644
index 0000000..6b1c50a
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarAgendamentoController.java
@@ -0,0 +1,342 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.AgendamentoController;
+import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.model.Servico;
+import com.carvalhotechsolutions.mundoanimal.repositories.AgendamentoRepository;
+import com.carvalhotechsolutions.mundoanimal.repositories.AnimalRepository;
+import com.carvalhotechsolutions.mundoanimal.repositories.ClienteRepository;
+import com.carvalhotechsolutions.mundoanimal.repositories.ServicoRepository;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.geometry.Insets;
+import javafx.scene.control.*;
+import javafx.scene.layout.HBox;
+import javafx.stage.Stage;
+import javafx.util.StringConverter;
+
+import java.net.URL;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+
+public class ModalCriarAgendamentoController implements Initializable {
+ @FXML
+ private TextField agendamento_id_field;
+
+ @FXML
+ private TextField finish;
+
+ @FXML
+ private DatePicker create_agendamento_date_field;
+
+ @FXML
+ private ComboBox create_agendamento_time_field;
+
+ @FXML
+ private ComboBox create_agendamento_servico_field;
+
+ @FXML
+ private ComboBox create_agendamento_client_field;
+
+ @FXML
+ private ComboBox create_agendamento_pet_field;
+
+ @FXML
+ private TextField create_agendamento_responsavel_field;
+
+ @FXML
+ private ComboBox create_agendamento_depTime_field;
+
+ @FXML Button actionButton;
+
+ @FXML
+ private HBox endServiceContainer;
+
+ @FXML
+ private HBox lastRegisterContainer;
+
+ private AgendamentoController agendamentoController;
+
+ private ServicoRepository servicoRepository = new ServicoRepository();
+
+ private ClienteRepository clienteRepository = new ClienteRepository();
+
+ private AgendamentoRepository agendamentoRepository = new AgendamentoRepository();
+
+ private Agendamento agendamentoAtual; // em caso de ser edição ou finalizacao
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ configurarCampoData();
+ configurarHorariosDisponiveis();
+ carregarServicos();
+ carregarClientes();
+ gerarHorarios();
+ }
+
+ @FXML
+ public void cadastrarAgendamento() {
+ // Validações
+ if (!validarCampos()) {
+ return;
+ }
+
+ if (agendamentoController == null) {
+ System.out.println("ERRO: agendamentoController é nulo!"); // Log para debug
+ return;
+ }
+
+ if(finish.getText() != null && !finish.getText().isEmpty()) {
+ agendamentoController.finalizarAgendamento(agendamentoAtual.getId());
+ fecharModal();
+ return;
+ }
+
+ try {
+ Agendamento agendamento;
+ boolean isEdicao = agendamento_id_field.getText() != null && !agendamento_id_field.getText().isEmpty();
+
+ if(isEdicao) {
+ Long id = Long.parseLong(agendamento_id_field.getText());
+ agendamento = agendamentoRepository.findById(id);
+ System.out.println("Editando cliente com ID: " + id);
+ } else {
+ agendamento = new Agendamento();
+ System.out.println("Criando novo cliente");
+ }
+
+ // Criar novo agendamento
+ agendamento.setDataAgendamento(create_agendamento_date_field.getValue());
+ agendamento.setHorarioAgendamento(
+ LocalTime.parse(create_agendamento_time_field.getValue(),
+ DateTimeFormatter.ofPattern("HH:mm"))
+ );
+ agendamento.setServico(create_agendamento_servico_field.getValue());
+ agendamento.setCliente(create_agendamento_client_field.getValue());
+ agendamento.setAnimal(create_agendamento_pet_field.getValue());
+
+ agendamentoController.salvarAgendamento(agendamento);
+ agendamentoController.atualizarTableView();
+
+ String mensagem = isEdicao ?
+ "Agendamento atualizado com sucesso!" :
+ "Agendamento cadastrado com sucesso!";
+
+ System.out.println("Exibindo mensagem: " + mensagem); // Log para debug
+ agendamentoController.handleSuccessfulOperation(mensagem);
+
+ fecharModal();
+ } catch (Exception e) {
+ e.printStackTrace();
+ agendamentoController.handleError("Ocorreu um erro inesperado!");
+ }
+ }
+
+ private void configurarHorariosDisponiveis() {
+ // Adicionar listener para atualizar horários disponíveis quando a data for selecionada
+ create_agendamento_date_field.valueProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue != null) {
+ atualizarHorariosDisponiveis(newValue);
+ }
+ });
+ }
+
+ private void atualizarHorariosDisponiveis(LocalDate data) {
+ // Limpar horários anteriores
+ create_agendamento_time_field.getItems().clear();
+
+ // Buscar agendamentos para a data selecionada
+ List agendamentosNaData = agendamentoRepository.buscarAgendamentosPorData(data);
+
+ // Gerar lista de horários
+ List horariosDisponiveis = gerarHorariosDisponiveis(data, agendamentosNaData);
+
+ create_agendamento_time_field.getItems().addAll(horariosDisponiveis);
+ }
+
+ private void gerarHorarios() {
+ List horarios = new ArrayList<>();
+ LocalTime inicio = LocalTime.of(6, 0);
+ LocalTime fim = LocalTime.of(20, 0);
+
+ while (inicio.isBefore(fim.plusMinutes(1))) {
+ horarios.add(inicio.format(DateTimeFormatter.ofPattern("HH:mm")));
+ inicio = inicio.plusMinutes(15);
+ }
+
+ create_agendamento_depTime_field.getItems().addAll(horarios);
+ }
+
+ private List gerarHorariosDisponiveis(LocalDate data, List agendamentosExistentes) {
+ List horariosDisponiveis = new ArrayList<>();
+ LocalTime inicio = LocalTime.of(6, 0);
+ LocalTime fim = LocalTime.of(20, 0);
+
+ while (inicio.isBefore(fim.plusMinutes(1))) {
+ String horarioStr = inicio.format(DateTimeFormatter.ofPattern("HH:mm"));
+
+ // Verificar se o horário já está ocupado
+ LocalTime finalInicio = inicio;
+ boolean horarioOcupado = agendamentosExistentes.stream()
+ .anyMatch(a -> a.getHorarioAgendamento().equals(finalInicio));
+
+ if (!horarioOcupado) {
+ horariosDisponiveis.add(horarioStr);
+ }
+
+ inicio = inicio.plusMinutes(15);
+ }
+
+ return horariosDisponiveis;
+ }
+
+ private void configurarCampoData() {
+ // Definir formato de data brasileiro
+ create_agendamento_date_field.setConverter(new StringConverter() {
+ final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+
+ @Override
+ public String toString(LocalDate date) {
+ return date != null ? dateFormatter.format(date) : "";
+ }
+
+ @Override
+ public LocalDate fromString(String string) {
+ return string != null && !string.isEmpty() ?
+ LocalDate.parse(string, dateFormatter) : null;
+ }
+ });
+
+ // Impedir seleção de datas anteriores
+ create_agendamento_date_field.setDayCellFactory(picker -> new DateCell() {
+ @Override
+ public void updateItem(LocalDate date, boolean empty) {
+ super.updateItem(date, empty);
+ setDisable(empty || date.isBefore(LocalDate.now()));
+ }
+ });
+ }
+
+ private void carregarServicos() {
+ List servicos = servicoRepository.findAll();
+ create_agendamento_servico_field.getItems().addAll(servicos);
+ }
+
+ private void carregarClientes() {
+ List clientes = clienteRepository.findAll();
+ create_agendamento_client_field.getItems().addAll(clientes);
+
+ // Adicionar listener para filtrar pets quando cliente for selecionado
+ create_agendamento_client_field.setOnAction(event -> {
+ Cliente clienteSelecionado = create_agendamento_client_field.getValue();
+ if (clienteSelecionado != null) {
+ carregarPetsPorCliente(clienteSelecionado);
+ }
+ });
+ }
+
+ private void carregarPetsPorCliente(Cliente cliente) {
+ // Limpar pets anteriores
+ create_agendamento_pet_field.getItems().clear();
+
+ // Carregar apenas pets do cliente selecionado
+ create_agendamento_pet_field.getItems().addAll(cliente.getPets());
+ }
+
+ private void fecharModal() {
+ // Obter a janela atual e fechá-la
+ Stage stage = (Stage) create_agendamento_date_field.getScene().getWindow();
+ stage.close();
+ }
+
+ private boolean validarCampos() {
+ if (create_agendamento_date_field.getValue() == null) {
+ mostrarErro("Selecione uma data");
+ return false;
+ }
+ if (create_agendamento_time_field.getValue() == null) {
+ mostrarErro("Selecione um horário");
+ return false;
+ }
+ if (create_agendamento_servico_field.getValue() == null) {
+ mostrarErro("Selecione um serviço");
+ return false;
+ }
+ if (create_agendamento_client_field.getValue() == null) {
+ mostrarErro("Selecione um cliente");
+ return false;
+ }
+ if (create_agendamento_pet_field.getValue() == null) {
+ mostrarErro("Selecione um pet");
+ return false;
+ }
+ return true;
+ }
+
+ private void mostrarErro(String mensagem) {
+ // Implementar exibição de erro (Alert, por exemplo)
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Erro de Validação");
+ alert.setHeaderText(null);
+ alert.setContentText(mensagem);
+ alert.showAndWait();
+ }
+
+ public void configurarParaCadastro() {
+ endServiceContainer.setVisible(false);
+ endServiceContainer.setManaged(false);
+ lastRegisterContainer.setStyle("-fx-border-color: transparent transparent #cccccc transparent;");
+ lastRegisterContainer.setPadding(new Insets(0, 30, 20, 30));
+ actionButton.setText("Cadastrar");
+ }
+
+ public void setAgendamentoController(AgendamentoController agendamentoController) {
+ this.agendamentoController = agendamentoController;
+ }
+
+ public void configurarParaEdicao(Agendamento agendamento) {
+ this.agendamentoAtual = agendamento;
+ agendamento_id_field.setText(agendamento.getId().toString()); // Preencher o campo de ID invisível
+
+ configurarParaCadastro();
+ actionButton.setText("Atualizar");
+
+ // populando campos do formulario com dados atuais do agendamento
+ create_agendamento_date_field.setValue(agendamento.getDataAgendamento());
+ create_agendamento_time_field.setValue(
+ agendamento.getHorarioAgendamento().format(DateTimeFormatter.ofPattern("HH:mm"))
+ );
+ create_agendamento_servico_field.setValue(agendamento.getServico());
+ create_agendamento_client_field.setValue(agendamento.getCliente());
+ create_agendamento_pet_field.setValue(agendamento.getAnimal());
+ }
+
+ public void configurarParaFinalizar(Agendamento agendamento) {
+ this.agendamentoAtual = agendamento;
+ finish.setText("true");
+ actionButton.setText("Finalizar");
+
+ create_agendamento_date_field.setValue(agendamento.getDataAgendamento());
+ create_agendamento_date_field.setDisable(true);
+
+ create_agendamento_time_field.setValue(
+ agendamento.getHorarioAgendamento().format(DateTimeFormatter.ofPattern("HH:mm"))
+ );
+ create_agendamento_time_field.setDisable(true);
+
+ create_agendamento_servico_field.setValue(agendamento.getServico());
+ create_agendamento_servico_field.setDisable(true);
+
+ create_agendamento_client_field.setValue(agendamento.getCliente());
+ create_agendamento_client_field.setDisable(true);
+
+ create_agendamento_pet_field.setValue(agendamento.getAnimal());
+ create_agendamento_pet_field.setDisable(true);
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarClienteController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarClienteController.java
new file mode 100644
index 0000000..fdae565
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarClienteController.java
@@ -0,0 +1,163 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.ClienteController;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.repositories.ClienteRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.MaskedTextField;
+import com.carvalhotechsolutions.mundoanimal.utils.TextFormatterManager;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class ModalCriarClienteController {
+ @FXML
+ private Label titleLabel;
+
+ @FXML
+ private Button actionButton;
+
+ @FXML
+ private TextField client_id_field;
+
+ @FXML
+ private TextField create_client_name_field;
+
+ @FXML
+ private MaskedTextField create_client_phone_field;
+
+ private final ClienteRepository clienteRepository = new ClienteRepository();
+
+ // Referência para o controlador principal
+ private ClienteController clienteController;
+
+ private Cliente clienteAtual; // Armazena o cliente a ser editado (se edição)
+
+
+ public void setClienteController(ClienteController clienteController) {
+ this.clienteController = clienteController;
+ }
+
+ @FXML
+ public void cadastrarCliente() {
+ String nome = create_client_name_field.getText();
+ String telefone = create_client_phone_field.getText();
+
+ if (!validarInputs(nome, telefone)) {
+ return;
+ }
+
+ try {
+ Cliente cliente;
+ boolean isEdicao = client_id_field.getText() != null && !client_id_field.getText().isEmpty();
+
+ if (isEdicao) {
+ Long id = Long.parseLong(client_id_field.getText());
+ cliente = clienteRepository.findById(id);
+ System.out.println("Editando cliente com ID: " + id); // Log para debug
+ } else {
+ cliente = new Cliente();
+ System.out.println("Criando novo cliente"); // Log para debug
+ }
+
+ cliente.setNome(nome);
+ cliente.setTelefone(telefone);
+ clienteRepository.save(cliente);
+
+ if (clienteController == null) {
+ System.out.println("ERRO: clienteController é nulo!"); // Log para debug
+ return;
+ }
+
+ // Atualizar a TableView e mostrar feedback
+ clienteController.atualizarTableView();
+
+ String mensagem = isEdicao ?
+ "Cliente atualizado com sucesso!" :
+ "Cliente cadastrado com sucesso!";
+
+ System.out.println("Exibindo mensagem: " + mensagem); // Log para debug
+ clienteController.handleSuccessfulOperation(mensagem);
+
+ fecharModal();
+ } catch (Exception e) {
+ System.out.println("Erro ao salvar cliente: " + e.getMessage()); // Log para debug
+ if (clienteController != null) {
+ clienteController.handleError("Erro ao " +
+ (client_id_field.getText().isEmpty() ? "cadastrar" : "atualizar") +
+ " cliente!");
+ }
+ e.printStackTrace();
+ }
+ }
+
+ // Configurar o modal para edição
+ public void configurarParaEdicao(Cliente cliente) {
+ this.clienteAtual = cliente;
+
+ // Atualizar campos
+ client_id_field.setText(cliente.getId().toString()); // Preencher o campo de ID invisível
+ create_client_name_field.setText(cliente.getNome());
+ create_client_phone_field.setText(cliente.getTelefone());
+
+ // Alterar título e botão
+ titleLabel.setText("Editar Cliente");
+ actionButton.setText("Salvar");
+ }
+
+ private boolean validarInputs(String nome, String telefone) {
+
+ nome = nome.trim();
+ telefone = telefone.trim(); // trim() usado para remover espaços desnecessários
+
+ if (nome.isEmpty() || telefone.isEmpty()) {
+ mostrarAlerta("Erro", "Campo(s) obrigatório(s) vazio(s)!", Alert.AlertType.ERROR);
+ return false;
+ }
+ String finalTelefone = telefone;
+ boolean telefoneJaCadastrado = clienteRepository.findAll().stream()
+ .anyMatch(cliente -> cliente.getTelefone().equals(finalTelefone) &&
+ (clienteAtual == null || !cliente.getId().equals(clienteAtual.getId())));
+ if (telefoneJaCadastrado){
+ mostrarAlerta("Erro", "O telefone informado já está cadastrado no sistema.", Alert.AlertType.ERROR);
+ return false;
+ }
+ String finalNome = nome;
+ boolean nomeJaCadastrado = clienteRepository.findAll().stream()
+ .anyMatch(cliente -> cliente.getNome().equalsIgnoreCase(finalNome) &&
+ (clienteAtual == null || !cliente.getId().equals(clienteAtual.getId())));
+
+ if (nomeJaCadastrado) {
+ mostrarAlerta("Erro", "Já existe um cliente cadastrado com esse nome.", Alert.AlertType.ERROR);
+ return false;
+ }
+
+ return true;
+ }
+
+ @FXML
+ private void phoneKeyReleased(){
+ TextFormatterManager tfm = new TextFormatterManager();
+ tfm.setMask("(##)#####-####");
+ tfm.setCaracteresValidos("0123456789");
+ tfm.setTf(create_client_phone_field);
+ tfm.formatter();
+ }
+
+ @FXML
+ public void fecharModal() {
+ Stage stage = (Stage) create_client_name_field.getScene().getWindow();
+ stage.close();
+ }
+
+ private void mostrarAlerta(String titulo, String mensagem, Alert.AlertType tipo) {
+ Alert alerta = new Alert(tipo);
+ alerta.setTitle(titulo);
+ alerta.setHeaderText(null);
+ alerta.setContentText(mensagem);
+ alerta.showAndWait();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarPetController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarPetController.java
new file mode 100644
index 0000000..09fb859
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarPetController.java
@@ -0,0 +1,187 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.AnimalController;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.ClienteController;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.repositories.AnimalRepository;
+import com.carvalhotechsolutions.mundoanimal.repositories.ClienteRepository;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class ModalCriarPetController implements Initializable {
+ @FXML
+ private Label titleLabel;
+
+ @FXML
+ private Button actionButton;
+
+ @FXML
+ private TextField pet_id_field;
+
+ @FXML
+ private TextField create_pet_clientName_field;
+
+ @FXML
+ private TextField create_pet_clientPhone_field;
+
+ @FXML
+ private TextField create_pet_name_field;
+
+ @FXML
+ private ComboBox create_pet_specie_field;
+
+ @FXML
+ private TextField create_pet_race_field;
+
+ @FXML
+ private TextField create_pet_age_field;
+
+ @FXML
+ private TextArea create_pet_notes_field;
+
+ private AnimalRepository animalRepository = new AnimalRepository();
+
+ private ClienteRepository clienteRepository = new ClienteRepository();
+
+ private ClienteController clienteController;
+
+ private AnimalController animalController;
+
+ private Cliente cliente; // Armazena o dono do pet que está sendo cadastrado
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ create_pet_specie_field.getItems().addAll(EspecieAnimal.values());
+ Platform.runLater(() -> create_pet_name_field.requestFocus());
+ }
+
+ @FXML
+ public void cadastrarPet() {
+ String nome = create_pet_name_field.getText();
+ EspecieAnimal especie = create_pet_specie_field.getValue();
+ String raca = create_pet_race_field.getText();
+ String idade = create_pet_age_field.getText();
+ String observacoes = create_pet_notes_field.getText();
+
+ if (!validarInputs(nome, especie)) {
+ return;
+ }
+
+ try {
+ Animal animal;
+ boolean isEdicao = pet_id_field.getText() != null && !pet_id_field.getText().isEmpty();
+
+ if (isEdicao) {
+ Long id = Long.parseLong(pet_id_field.getText());
+ animal = animalRepository.findById(id); // Recupera o animal existente
+ System.out.println("Editando animal com ID: " + id); // Log para debug
+ } else {
+ animal = new Animal(); // Novo animal
+ System.out.println("Criando novo animal"); // Log para debug
+ }
+
+ animal.setNome(nome);
+ animal.setEspecie(especie);
+ animal.setRaca(raca.isEmpty() ? null : raca);
+ animal.setIdade(idade.isEmpty() ? null : Integer.parseInt(idade));
+ animal.setObservacoes(observacoes.isEmpty() ? null : observacoes);
+ animal.setDono(this.cliente);
+ animalRepository.save(animal);
+
+ if (clienteController != null) {
+ clienteController.atualizarTableView();
+ }
+
+ String mensagem = isEdicao ?
+ "Pet atualizado com sucesso!" :
+ "Pet cadastrado com sucesso!";
+
+
+ System.out.println("Exibindo mensagem: " + mensagem); // Log para debug
+
+ if(isEdicao) {
+ animalController.handleSuccessfulOperation(mensagem);
+ }
+ else {
+ clienteController.handleSuccessfulOperation(mensagem);
+ }
+
+ fecharModal();
+
+ } catch (NumberFormatException e) {
+ mostrarAlerta("Erro", "Idade deve ser um número válido!", Alert.AlertType.ERROR);
+ } catch (Exception e) {
+ mostrarAlerta("Erro", "Erro ao cadastrar pet: " + e.getMessage(), Alert.AlertType.ERROR);
+ e.printStackTrace();
+ }
+ }
+
+ private boolean validarInputs(String nome, EspecieAnimal especie) {
+ if (nome.isEmpty() || especie == null) {
+ mostrarAlerta("Erro", "Nome do pet e espécie são obrigatórios!", Alert.AlertType.ERROR);
+ return false;
+ }
+ return true;
+ }
+
+ public void configurarParaCadastro(Long clientId) {
+ this.cliente = clienteRepository.findById(clientId);
+
+ create_pet_clientName_field.setText(cliente.getNome());
+ create_pet_clientPhone_field.setText(cliente.getTelefone());
+ create_pet_clientName_field.setEditable(false);
+ create_pet_clientPhone_field.setEditable(false);
+ }
+
+ private void mostrarAlerta(String titulo, String mensagem, Alert.AlertType tipo) {
+ Alert alerta = new Alert(tipo);
+ alerta.setTitle(titulo);
+ alerta.setHeaderText(null);
+ alerta.setContentText(mensagem);
+ alerta.showAndWait();
+ }
+
+ @FXML
+ public void fecharModal() {
+ Stage stage = (Stage) create_pet_name_field.getScene().getWindow();
+ stage.close();
+ }
+
+ public void configurarParaEdicao(Animal animal) {
+ this.cliente = animal.getDono();
+
+ // Atualizar campos
+ pet_id_field.setText(animal.getId().toString()); // Preencher o campo de ID invisível
+ create_pet_clientName_field.setText(cliente.getNome());
+ create_pet_clientPhone_field.setText(cliente.getTelefone());
+ create_pet_clientName_field.setEditable(false);
+ create_pet_clientPhone_field.setEditable(false);
+
+ // Preenchendo campos referentes ao animal
+ create_pet_name_field.setText(animal.getNome());
+ create_pet_specie_field.setValue(animal.getEspecie());
+ create_pet_race_field.setText(animal.getRaca() == null ? "" : animal.getRaca());
+ create_pet_age_field.setText(animal.getIdade() == null ? "" : animal.getIdade().toString());
+ create_pet_notes_field.setText(animal.getObservacoes() == null ? "" : animal.getObservacoes());
+
+ // Alterar título e botão
+ titleLabel.setText("Editar Pet");
+ actionButton.setText("Salvar");
+ }
+
+ public void setClienteController(ClienteController clienteController) {
+ this.clienteController = clienteController;
+ }
+
+ public void setAnimalController(AnimalController animalController) {
+ this.animalController = animalController;
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarSecretarioController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarSecretarioController.java
similarity index 60%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarSecretarioController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarSecretarioController.java
index 83937fb..c291e8c 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarSecretarioController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarSecretarioController.java
@@ -1,15 +1,14 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.SecretarioController;
import com.carvalhotechsolutions.mundoanimal.model.Secretario;
-import com.carvalhotechsolutions.mundoanimal.model.Servico;
-import com.carvalhotechsolutions.mundoanimal.model.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.enums.TipoUsuario;
import com.carvalhotechsolutions.mundoanimal.repositories.SecretarioRepository;
-import com.carvalhotechsolutions.mundoanimal.security.PasswordUtils;
+import com.carvalhotechsolutions.mundoanimal.utils.MaskedTextField;
+import com.carvalhotechsolutions.mundoanimal.utils.PasswordManager;
+import com.carvalhotechsolutions.mundoanimal.utils.TextFormatterManager;
import javafx.fxml.FXML;
-import javafx.geometry.Insets;
import javafx.scene.control.*;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ModalCriarSecretarioController {
@@ -17,7 +16,7 @@ public class ModalCriarSecretarioController {
private TextField create_secretary_name_field;
@FXML
- private TextField create_secretary_phone_field;
+ private MaskedTextField create_secretary_phone_field;
@FXML
private PasswordField create_secretary_password_field;
@@ -38,7 +37,6 @@ public void setSecretarioController(SecretarioController secretarioController) {
@FXML
public void cadastrarSecretario() {
-
String nome = create_secretary_name_field.getText();
String telefone = create_secretary_phone_field.getText();
String password = create_secretary_password_field.getText();
@@ -54,13 +52,14 @@ public void cadastrarSecretario() {
secretario.setNomeUsuario(nome);
secretario.setTelefone(telefone);
- secretario.setSenha(PasswordUtils.hashPassword(create_secretary_password_field.getText()));
+ secretario.setSenha(PasswordManager.hashPassword(create_secretary_password_field.getText()));
secretario.setTipoUsuario(TipoUsuario.SECRETARIO);
secretarioRepository.save(secretario);
if (secretarioController != null) {
secretarioController.atualizarTableView();
+ secretarioController.handleSuccessfulOperation("Secretário(a) cadastrado(a) com sucesso!");
}
fecharModal();
@@ -78,14 +77,42 @@ public void fecharModal() {
}
private boolean validarInputs(String nome, String telefone, String password, String passwordConfirmation) {
+ nome = nome.trim();
+ telefone = telefone.trim();
+
if (nome.isEmpty() || telefone.isEmpty() || password.isEmpty() || passwordConfirmation.isEmpty()) {
mostrarAlerta("Erro", "Campo(s) obrigatório(s) vazio(s)!", Alert.AlertType.ERROR);
return false;
}
+
if (!password.equals(passwordConfirmation)) {
mostrarAlerta("Erro", "Senhas não estão iguais.", Alert.AlertType.ERROR);
return false;
}
+
+ if (password.length() < 6) {
+ mostrarAlerta("Erro", "A senha deve ter no mínimo 6 caracteres.", Alert.AlertType.ERROR);
+ return false;
+ }
+
+ String finalTelefone = telefone;
+
+ boolean telefoneJaCadastrado = secretarioRepository.findAll().stream()
+ .anyMatch(secretario -> secretario.getTelefone().equals(finalTelefone) &&
+ (secretarioAtual == null || !secretario.getId().equals(secretarioAtual.getId())));
+ if (telefoneJaCadastrado) {
+ mostrarAlerta("Erro", "O telefone informado já está cadastrado no sistema.", Alert.AlertType.ERROR);
+ return false;
+ }
+
+ String finalNome = nome;
+ boolean nomeJaCadastrado = secretarioRepository.findAll().stream()
+ .anyMatch(secretario -> secretario.getNomeUsuario().equalsIgnoreCase(finalNome) &&
+ (secretarioAtual == null || !secretario.getId().equals(secretarioAtual.getId())));
+ if (nomeJaCadastrado) {
+ mostrarAlerta("Erro", "Já existe um secretário cadastrado com esse nome.", Alert.AlertType.ERROR);
+ return false;
+ }
return true;
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarServicoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarServicoController.java
similarity index 68%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarServicoController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarServicoController.java
index bd27605..1e576f2 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalCriarServicoController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalCriarServicoController.java
@@ -1,8 +1,10 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.ServicoController;
import com.carvalhotechsolutions.mundoanimal.model.Servico;
import com.carvalhotechsolutions.mundoanimal.repositories.ServicoRepository;
+import com.carvalhotechsolutions.mundoanimal.utils.TextFormatterManager;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.Stage;
@@ -28,7 +30,7 @@ public class ModalCriarServicoController {
@FXML
private TextArea create_service_description_field;
- private ServicoRepository servicoRepository = new ServicoRepository();
+ private final ServicoRepository servicoRepository = new ServicoRepository();
// Referência para o controlador principal
private ServicoController servicoController;
@@ -53,15 +55,16 @@ public void cadastrarServico() {
try {
BigDecimal valor = new BigDecimal(valorStr.replace(",", "."));
-
Servico servico;
+ boolean isEdicao = service_id_field.getText() != null && !service_id_field.getText().isEmpty();
- // Verificar se o serviço já existe (edição)
- if (service_id_field.getText() != null && !service_id_field.getText().isEmpty()) {
+ if (isEdicao) {
Long id = Long.parseLong(service_id_field.getText());
servico = servicoRepository.findById(id); // Recupera o serviço existente
+ System.out.println("Editando serviço com ID: " + id); // Log para debug
} else {
servico = new Servico(); // Novo serviço
+ System.out.println("Criando novo serviço"); // Log para debug
}
servico.setNomeServico(nome);
@@ -71,12 +74,20 @@ public void cadastrarServico() {
// Persistir no banco de dados
servicoRepository.save(servico);
- // Atualizar a TableView no controlador principal
- if (servicoController != null) {
- servicoController.atualizarTableView();
+ if (servicoController == null) {
+ System.out.println("ERRO: servicoController é nulo!"); // Log para debug
+ return;
}
- // Fechar modal
+ servicoController.atualizarTableView();
+
+ String mensagem = isEdicao ?
+ "Serviço atualizado com sucesso!" :
+ "Serviço cadastrado com sucesso!";
+
+ System.out.println("Exibindo mensagem: " + mensagem); // Log para debug
+ servicoController.handleSuccessfulOperation(mensagem);
+
fecharModal();
} catch (NumberFormatException e) {
@@ -100,11 +111,12 @@ public void configurarParaEdicao(Servico servico) {
}
private boolean validarInputs(String nome, String valor) {
+ nome = nome.trim();
+ valor = valor.trim();
if (nome.isEmpty() || valor.isEmpty()) {
mostrarAlerta("Erro", "Campo(s) obrigatório(s) vazio(s)!", Alert.AlertType.ERROR);
return false;
}
-
// Verificar se o valor é numérico
try {
new BigDecimal(valor.replace(",", "."));
@@ -112,6 +124,14 @@ private boolean validarInputs(String nome, String valor) {
mostrarAlerta("Erro", "O campo 'Valor' deve ser numérico!", Alert.AlertType.ERROR);
return false;
}
+ String nomeServico = nome;
+ boolean servicoJaCadastrado = servicoRepository.findAll().stream().anyMatch(s ->
+ nomeServico.equalsIgnoreCase(s.getNomeServico()) && (servicoAtual == null ||
+ !servicoAtual.getId().equals(s.getId())));
+ if (servicoJaCadastrado) {
+ mostrarAlerta("Erro", "Já existe um serviço cadastrado com esse nome.", Alert.AlertType.ERROR);
+ return false;
+ }
return true;
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalDetalhesPetController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalDetalhesPetController.java
new file mode 100644
index 0000000..87e5f18
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalDetalhesPetController.java
@@ -0,0 +1,42 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+
+public class ModalDetalhesPetController {
+ @FXML
+ private Text pet_name_label;
+
+ @FXML
+ private Text pet_specie_label;
+
+ @FXML
+ private Text pet_race_label;
+
+ @FXML
+ private Text pet_age_label;
+
+ @FXML
+ private Text pet_notes_label;
+
+ private Animal animal;
+
+ public void configurarParaExibicao(Animal animal) {
+ this.animal = animal;
+
+ pet_name_label.setText(animal.getNome());
+ pet_specie_label.setText(animal.getEspecie().toString());
+ pet_race_label.setText(animal.getRaca() == null ? "Sem informações" : animal.getRaca());
+ pet_age_label.setText(animal.getIdade() == null ? "Sem informações" : animal.getIdade().toString() + " anos");
+ pet_notes_label.setText(animal.getObservacoes() == null ? "Sem informações" : animal.getObservacoes());
+ }
+
+ @FXML
+ public void fecharModal() {
+ Stage stage = (Stage) pet_name_label.getScene().getWindow();
+ stage.close();
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalEditarSecretarioController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalEditarSecretarioController.java
similarity index 83%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalEditarSecretarioController.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalEditarSecretarioController.java
index 98ecf65..f95cb60 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/ModalEditarSecretarioController.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalEditarSecretarioController.java
@@ -1,5 +1,6 @@
-package com.carvalhotechsolutions.mundoanimal.controllers;
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.SecretarioController;
import com.carvalhotechsolutions.mundoanimal.model.Secretario;
import com.carvalhotechsolutions.mundoanimal.repositories.SecretarioRepository;
import javafx.fxml.FXML;
@@ -43,10 +44,14 @@ public void editarSecretario() {
secretarioRepository.save(secretario);
- if (secretarioController != null) {
- secretarioController.atualizarTableView();
+ if (secretarioController == null) {
+ System.out.println("ERRO: secretarioController é nulo!"); // Log para debug
+ return;
}
+ secretarioController.atualizarTableView();
+ secretarioController.handleSuccessfulOperation("Secretário(a) atualizado(a) com sucesso!");
+
fecharModal();
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalLoginSucessoController.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalLoginSucessoController.java
new file mode 100644
index 0000000..c672674
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/controllers/modals/ModalLoginSucessoController.java
@@ -0,0 +1,4 @@
+package com.carvalhotechsolutions.mundoanimal.controllers.modals;
+
+public class ModalLoginSucessoController {
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/DatabaseChecker.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/database/DatabaseChecker.java
similarity index 73%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/DatabaseChecker.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/database/DatabaseChecker.java
index 79e9152..21d5b9e 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/DatabaseChecker.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/database/DatabaseChecker.java
@@ -1,9 +1,11 @@
-package com.carvalhotechsolutions.mundoanimal;
+package com.carvalhotechsolutions.mundoanimal.database;
import com.carvalhotechsolutions.mundoanimal.model.Administrador;
-import com.carvalhotechsolutions.mundoanimal.model.enums.TipoUsuario;
-import com.carvalhotechsolutions.mundoanimal.security.PasswordUtils;
+import com.carvalhotechsolutions.mundoanimal.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.utils.PasswordManager;
import jakarta.persistence.EntityManager;
+import javafx.application.Platform;
+import javafx.scene.control.Alert;
public class DatabaseChecker {
@@ -12,8 +14,7 @@ private DatabaseChecker() {
throw new UnsupportedOperationException("Esta classe não pode ser instanciada");
}
- public static boolean testConnectionAndInitializeAdmin() {
-
+ public static void testConnectionAndInitializeAdmin() {
try (EntityManager em = JPAutil.getEntityManager()) {
em.getTransaction().begin();
@@ -24,11 +25,15 @@ public static boolean testConnectionAndInitializeAdmin() {
// Após verificar a conexão, inicializa o administrador padrão
initializeAdmin(em);
- return true;
} catch (Exception e) {
System.err.println("Erro ao conectar ao banco de dados: " + e.getMessage());
- return false;
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Erro de Conexão");
+ alert.setHeaderText("Não foi possível conectar ao banco de dados.");
+ alert.setContentText("Verifique as configurações do banco e tente novamente.");
+ alert.showAndWait();
+ Platform.exit(); // Encerra a aplicação
}
}
@@ -45,7 +50,7 @@ private static void initializeAdmin(EntityManager em) {
Administrador admin = new Administrador();
admin.setCpf("123.456.789-10");
admin.setNomeUsuario("admin");
- admin.setSenha(PasswordUtils.hashPassword("admin"));
+ admin.setSenha(PasswordManager.hashPassword("admin"));
admin.setTipoUsuario(TipoUsuario.ADMINISTRADOR);
// Persiste o administrador no banco
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/JPAutil.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/database/JPAutil.java
similarity index 86%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/JPAutil.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/database/JPAutil.java
index 9f96da7..55daddc 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/JPAutil.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/database/JPAutil.java
@@ -1,4 +1,4 @@
-package com.carvalhotechsolutions.mundoanimal;
+package com.carvalhotechsolutions.mundoanimal.database;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/EspecieAnimal.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/EspecieAnimal.java
new file mode 100644
index 0000000..e02d0de
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/EspecieAnimal.java
@@ -0,0 +1,26 @@
+package com.carvalhotechsolutions.mundoanimal.enums;
+
+public enum EspecieAnimal {
+ CACHORRO("Cachorro"),
+ GATO("Gato"),
+ PEIXE("Peixe"),
+ PASSARO("Pássaro"),
+ COELHO("Coelho"),
+ HAMSTER("Hamster"),
+ CAVALO("Cavalo"),
+ REPTIL("Réptil"),
+ ANFIBIO("Anfíbio"),
+ OUTRO("Outro");
+
+ private final String displayName;
+
+ EspecieAnimal(String displayName) {
+ this.displayName = displayName;
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
+
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/ScreenEnum.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/ScreenEnum.java
new file mode 100644
index 0000000..81741d1
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/ScreenEnum.java
@@ -0,0 +1,42 @@
+package com.carvalhotechsolutions.mundoanimal.enums;
+
+public enum ScreenEnum {
+ LOGIN("/fxml/autenticacao/login.fxml", "Login", ScreenType.FULL),
+ RECUPERAR_SENHA("/fxml/autenticacao/recuperarSenha.fxml", "Recuperar senha", ScreenType.FULL),
+ REDEFINIR_SENHA("/fxml/autenticacao/redefinirSenha.fxml", "Redefinir Senha", ScreenType.FULL),
+ MENU("/fxml/gerenciamento/menu.fxml", "Menu Principal", ScreenType.TEMPLATE),
+ SECRETARIOS("/fxml/gerenciamento/secretarios.fxml", "Secretários", ScreenType.CONTENT),
+ SERVICOS("/fxml/gerenciamento/servicos.fxml", "Serviços", ScreenType.CONTENT),
+ CLIENTES("/fxml/gerenciamento/clientes.fxml", "Clientes", ScreenType.CONTENT),
+ PETS("/fxml/gerenciamento/pets.fxml", "Pets", ScreenType.CONTENT),
+ AGENDAMENTOS("/fxml/gerenciamento/agendamentos.fxml", "Agendamentos", ScreenType.CONTENT);
+
+ private final String fxmlPath;
+ private final String title;
+ private final ScreenType type;
+
+ ScreenEnum(String fxmlPath, String title, ScreenType type) {
+ this.fxmlPath = fxmlPath;
+ this.title = title;
+ this.type = type;
+ }
+
+ public String getFxmlPath() {
+ return fxmlPath;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public ScreenType getType() {
+ return type;
+ }
+
+ // Enum para definir o tipo de tela
+ public enum ScreenType {
+ FULL, // Tela completa (como login)
+ TEMPLATE, // Template com menu (como menu.fxml)
+ CONTENT // Conteúdo para ser carregado no contentArea
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/StatusAgendamento.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/StatusAgendamento.java
similarity index 75%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/StatusAgendamento.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/enums/StatusAgendamento.java
index 40858eb..db6c94a 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/StatusAgendamento.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/StatusAgendamento.java
@@ -1,4 +1,4 @@
-package com.carvalhotechsolutions.mundoanimal.model.enums;
+package com.carvalhotechsolutions.mundoanimal.enums;
public enum StatusAgendamento {
PENDENTE, // Agendamento criado e aguardando realização
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/TipoUsuario.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/TipoUsuario.java
similarity index 52%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/TipoUsuario.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/enums/TipoUsuario.java
index d474d4f..63fbd82 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/TipoUsuario.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/enums/TipoUsuario.java
@@ -1,4 +1,4 @@
-package com.carvalhotechsolutions.mundoanimal.model.enums;
+package com.carvalhotechsolutions.mundoanimal.enums;
public enum TipoUsuario {
ADMINISTRADOR,
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Administrador.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Administrador.java
index ca18cda..de9ee0d 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Administrador.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Administrador.java
@@ -7,7 +7,6 @@
@Entity
@Table(name = "tb_admin")
public class Administrador extends Usuario {
-
@Column(nullable = false, unique = true)
private String cpf;
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Agendamento.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Agendamento.java
index d716c74..b833bd0 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Agendamento.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Agendamento.java
@@ -1,11 +1,11 @@
package com.carvalhotechsolutions.mundoanimal.model;
-import com.carvalhotechsolutions.mundoanimal.model.enums.StatusAgendamento;
+import com.carvalhotechsolutions.mundoanimal.enums.StatusAgendamento;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.time.LocalTime;
-import java.util.UUID;
+import java.time.format.DateTimeFormatter;
@Entity
@Table(name = "tb_agendamentos")
@@ -47,6 +47,14 @@ public Agendamento() {
this.status = StatusAgendamento.PENDENTE;
}
+ public String getDataHoraFormatada() {
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+ DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+
+ return dataAgendamento.format(dateFormatter) + " - " +
+ horarioAgendamento.format(timeFormatter);
+ }
+
public Long getId() {
return id;
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Animal.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Animal.java
index 6160581..dca3d02 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Animal.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Animal.java
@@ -1,10 +1,8 @@
package com.carvalhotechsolutions.mundoanimal.model;
-import com.carvalhotechsolutions.mundoanimal.model.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
import jakarta.persistence.*;
-import java.util.UUID;
-
@Entity
@Table(name = "tb_animais")
public class Animal {
@@ -20,13 +18,13 @@ public class Animal {
@Column(nullable = false)
private EspecieAnimal especie;
- @Column(nullable = false)
+ @Column()
private String raca;
- @Column(nullable = false)
+ @Column()
private Integer idade;
- @Column(nullable = false)
+ @Column()
private String observacoes;
@ManyToOne
@@ -88,4 +86,9 @@ public Cliente getDono() {
public void setDono(Cliente dono) {
this.dono = dono;
}
+
+ @Override
+ public String toString() {
+ return this.nome;
+ }
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Cliente.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Cliente.java
index 10d62b4..ee46438 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Cliente.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Cliente.java
@@ -2,7 +2,9 @@
import jakarta.persistence.*;
+import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
@Entity
@Table(name = "tb_cliente")
@@ -18,8 +20,8 @@ public class Cliente {
@Column(unique = true, nullable = false)
private String telefone;
- @OneToMany(mappedBy = "dono", cascade = CascadeType.ALL, orphanRemoval = true)
- private List pets;
+ @OneToMany(mappedBy = "dono", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
+ private List pets = new ArrayList<>();
public Long getId() {
return id;
@@ -52,4 +54,18 @@ public List getPets() {
public void setPets(List pets) {
this.pets = pets;
}
+
+ public String getPetsFormatados() {
+ if (pets.isEmpty()) {
+ return "";
+ }
+ return pets.stream()
+ .map(Animal::getNome)
+ .collect(Collectors.joining(", "));
+ }
+
+ @Override
+ public String toString() {
+ return getNome();
+ }
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Servico.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Servico.java
index 7f894f3..d12a209 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Servico.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Servico.java
@@ -52,4 +52,10 @@ public String getDescricao() {
public void setDescricao(String descricao) {
this.descricao = descricao;
}
+
+ @Override
+ public String toString() {
+ return getNomeServico();
+ }
}
+
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Usuario.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Usuario.java
index 5e7177d..06ea560 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Usuario.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/Usuario.java
@@ -1,10 +1,8 @@
package com.carvalhotechsolutions.mundoanimal.model;
-import com.carvalhotechsolutions.mundoanimal.model.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.enums.TipoUsuario;
import jakarta.persistence.*;
-import java.util.UUID;
-
@MappedSuperclass
public abstract class Usuario {
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/EspecieAnimal.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/EspecieAnimal.java
deleted file mode 100644
index 38b8772..0000000
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/model/enums/EspecieAnimal.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.carvalhotechsolutions.mundoanimal.model.enums;
-
-public enum EspecieAnimal {
- CACHORRO,
- GATO,
- PEIXE,
- PASSARO,
- COELHO,
- HAMSTER,
- CAVALO,
- REPTIL,
- ANFIBIO,
- OUTRO
-}
-
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepository.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepository.java
new file mode 100644
index 0000000..24102f4
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepository.java
@@ -0,0 +1,79 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.TypedQuery;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+
+public class AgendamentoRepository {
+ public Agendamento save(Agendamento agendamento) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ em.getTransaction().begin();
+ if (agendamento.getId() == null) {
+ em.persist(agendamento);
+ } else {
+ em.merge(agendamento);
+ }
+ em.getTransaction().commit();
+ return agendamento;
+ }
+ }
+
+ public Agendamento findById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ TypedQuery query = em.createQuery("SELECT a FROM Agendamento a WHERE a.id = :id", Agendamento.class);
+ query.setParameter("id", id);
+ return query.getSingleResult();
+ }
+ }
+
+ public List findAll() {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ String jpql = "SELECT a FROM Agendamento a " +
+ "ORDER BY a.dataAgendamento ASC, a.horarioAgendamento ASC";
+
+ return em.createQuery(jpql, Agendamento.class)
+ .getResultList();
+ }
+ }
+
+ public void deleteById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ Agendamento agendamento = em.find(Agendamento.class, id);
+ if(agendamento != null) {
+ em.getTransaction().begin();
+ em.remove(agendamento);
+ em.getTransaction().commit();
+ }
+ else {
+ throw new IllegalArgumentException("Agendamento not found!");
+ }
+ }
+ }
+
+ public boolean verificarDisponibilidadeHorario(LocalDate data, LocalTime horario) {
+ String jpql = "SELECT COUNT(a) FROM Agendamento a " +
+ "WHERE a.dataAgendamento = :data " +
+ "AND a.horarioAgendamento = :horario";
+
+ EntityManager em = JPAutil.getEntityManager();
+ Long count = em.createQuery(jpql, Long.class)
+ .setParameter("data", data)
+ .setParameter("horario", horario)
+ .getSingleResult();
+
+ return count == 0;
+ }
+
+ public List buscarAgendamentosPorData(LocalDate data) {
+ String jpql = "SELECT a FROM Agendamento a WHERE a.dataAgendamento = :data";
+ EntityManager em = JPAutil.getEntityManager();
+ return em.createQuery(jpql, Agendamento.class)
+ .setParameter("data", data)
+ .getResultList();
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepository.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepository.java
new file mode 100644
index 0000000..9abc83a
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepository.java
@@ -0,0 +1,60 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.TypedQuery;
+
+import java.util.List;
+
+public class AnimalRepository {
+ public Animal save(Animal animal) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ em.getTransaction().begin();
+ if (animal.getId() == null) {
+ em.persist(animal);
+ } else {
+ em.merge(animal);
+ }
+ em.getTransaction().commit();
+ return animal;
+ }
+ }
+
+ public Animal findById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ TypedQuery query = em.createQuery("SELECT a FROM Animal a WHERE a.id = :id", Animal.class);
+ query.setParameter("id", id);
+ return query.getSingleResult();
+ }
+ }
+
+ public List findAll() {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ TypedQuery query = em.createQuery("SELECT a FROM Animal a ORDER BY a.nome", Animal.class);
+ return query.getResultList();
+ }
+ }
+
+ public void deleteById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ Animal animal = em.find(Animal.class, id);
+ if(animal != null) {
+ em.getTransaction().begin();
+
+ // Remover o animal da lista de pets do cliente
+ Cliente dono = animal.getDono();
+ dono.getPets().remove(animal);
+
+ em.remove(animal);
+
+ em.remove(animal);
+ em.getTransaction().commit();
+ }
+ else {
+ throw new IllegalArgumentException("Animal not found!");
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepository.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepository.java
new file mode 100644
index 0000000..39e8d13
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepository.java
@@ -0,0 +1,62 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.TypedQuery;
+
+import java.util.List;
+
+public class ClienteRepository {
+ public Cliente save(Cliente cliente) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ em.getTransaction().begin();
+ if (cliente.getId() == null) {
+ em.persist(cliente);
+ } else {
+ em.merge(cliente);
+ }
+ em.getTransaction().commit();
+ return cliente;
+ }
+ }
+
+ public Cliente findById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ TypedQuery query = em.createQuery("SELECT c FROM Cliente c WHERE c.id = :id", Cliente.class);
+ query.setParameter("id", id);
+ return query.getSingleResult();
+ }
+ }
+
+ public List findAll() {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ TypedQuery query = em.createQuery("SELECT c FROM Cliente c ORDER BY c.nome", Cliente.class);
+ return query.getResultList();
+ }
+ }
+
+ public void deleteById(Long id) {
+ try(EntityManager em = JPAutil.getEntityManager()) {
+ Cliente cliente = em.find(Cliente.class, id);
+ if(cliente != null) {
+ em.getTransaction().begin();
+ em.remove(cliente);
+ em.getTransaction().commit();
+ }
+ else {
+ throw new IllegalArgumentException("Cliente not found!");
+ }
+ }
+ }
+
+ public boolean clientePossuiAgendamentos(Long clienteId) {
+ try (EntityManager em = JPAutil.getEntityManager()) {
+ String jpql = "SELECT COUNT(a) FROM Agendamento a WHERE a.cliente.id = :clienteId";
+ Long count = em.createQuery(jpql, Long.class)
+ .setParameter("clienteId", clienteId)
+ .getSingleResult();
+ return count > 0;
+ }
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepository.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepository.java
index 9922e66..bd4e251 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepository.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepository.java
@@ -1,6 +1,6 @@
package com.carvalhotechsolutions.mundoanimal.repositories;
-import com.carvalhotechsolutions.mundoanimal.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
import com.carvalhotechsolutions.mundoanimal.model.Secretario;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
@@ -32,7 +32,7 @@ public Secretario findById(Long id) {
public List findAll() {
try(EntityManager em = JPAutil.getEntityManager()) {
- TypedQuery query = em.createQuery("SELECT s FROM Secretario s", Secretario.class);
+ TypedQuery query = em.createQuery("SELECT s FROM Secretario s ORDER BY s.nomeUsuario", Secretario.class);
return query.getResultList();
}
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepository.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepository.java
index 191a2ba..0646c71 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepository.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepository.java
@@ -1,6 +1,6 @@
package com.carvalhotechsolutions.mundoanimal.repositories;
-import com.carvalhotechsolutions.mundoanimal.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
import com.carvalhotechsolutions.mundoanimal.model.Servico;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
@@ -32,7 +32,7 @@ public Servico findById(Long id) {
public List findAll() {
try(EntityManager em = JPAutil.getEntityManager()) {
- TypedQuery query = em.createQuery("SELECT s FROM Servico s", Servico.class);
+ TypedQuery query = em.createQuery("SELECT s FROM Servico s ORDER BY s.nomeServico", Servico.class);
return query.getResultList();
}
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/FeedbackManager.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/FeedbackManager.java
new file mode 100644
index 0000000..9a498c5
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/FeedbackManager.java
@@ -0,0 +1,81 @@
+package com.carvalhotechsolutions.mundoanimal.utils;
+
+import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
+import javafx.animation.FadeTransition;
+import javafx.animation.PauseTransition;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.paint.Color;
+import javafx.util.Duration;
+
+import java.io.IOException;
+
+public class FeedbackManager {
+ private static final String POPUP_FXML = "/fxml/popup/feedback.fxml";
+
+ public enum FeedbackType {
+ SUCCESS("CHECK_CIRCLE", "#FFFFFF", "#43b554"),
+ ERROR("TIMES_CIRCLE", "#FFFFFF" ,"#FF6F6F"),
+ WARNING("EXCLAMATION_CIRCLE", "#FFFFFF" ,"#FFA500"),
+ INFO("INFO_CIRCLE", "#FFFFFF" ,"#686AFF");
+
+ private final String icon;
+ private final String color;
+ private final String backgroundColor;
+
+ FeedbackType(String icon, String color, String backgroundColor) {
+ this.icon = icon;
+ this.color = color;
+ this.backgroundColor = backgroundColor;
+ }
+ }
+
+ public static void showFeedback(HBox container, String message, FeedbackType type) {
+ try {
+ FXMLLoader loader = new FXMLLoader(FeedbackManager.class.getResource(POPUP_FXML));
+ HBox popupContent = loader.load();
+
+ // Configurar o estilo do popup
+ popupContent.getStyleClass().add("popup");
+ popupContent.setStyle(String.format("-fx-background-color: %s;", type.backgroundColor));
+
+ // Encontrar e configurar os componentes
+ FontAwesomeIcon icon = (FontAwesomeIcon) popupContent.lookup("#icon");
+ Label messageLabel = (Label) popupContent.lookup("#message");
+
+ // Configurar o conteúdo
+ icon.setGlyphName(type.icon);
+ icon.setFill(Color.web(type.color));
+ messageLabel.setText(message);
+
+ // Limpar popups anteriores
+ container.getChildren().removeIf(node -> node.getStyleClass().contains("popup"));
+
+ // Adicionar o novo popup
+ container.getChildren().add(popupContent);
+
+ // Animação de entrada
+ FadeTransition fadeIn = new FadeTransition(Duration.seconds(0.5), popupContent);
+ fadeIn.setFromValue(0);
+ fadeIn.setToValue(1);
+ fadeIn.play();
+
+ // Timer para remoção
+ PauseTransition delay = new PauseTransition(Duration.seconds(3));
+ delay.setOnFinished(event -> {
+ FadeTransition fadeOut = new FadeTransition(Duration.seconds(0.5), popupContent);
+ fadeOut.setFromValue(1);
+ fadeOut.setToValue(0);
+ fadeOut.setOnFinished(e -> {
+ container.getChildren().remove(popupContent);
+ });
+ fadeOut.play();
+ });
+ delay.play();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/MaskedTextField.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/MaskedTextField.java
new file mode 100644
index 0000000..06374de
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/MaskedTextField.java
@@ -0,0 +1,502 @@
+package com.carvalhotechsolutions.mundoanimal.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javafx.application.Platform;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+import javafx.scene.control.IndexRange;
+import javafx.scene.control.TextField;
+
+/**
+ * This component receives a mask that dictate the valid input for this field.
+ * @author gbfragoso
+ * @version 2.1
+ */
+public class MaskedTextField extends TextField {
+
+ private static final char MASK_ESCAPE = '\'';
+ private static final char MASK_NUMBER = '#';
+ private static final char MASK_CHARACTER = '?';
+ private static final char MASK_HEXADECIMAL = 'H';
+ private static final char MASK_UPPER_CHARACTER = 'U';
+ private static final char MASK_LOWER_CHARACTER = 'L';
+ private static final char MASK_CHAR_OR_NUM = 'A';
+ private static final char MASK_ANYTHING = '*';
+
+ private int maskLength;
+ private char placeholder;
+ private StringProperty mask;
+ private StringProperty plainText;
+ private StringBuilder plainTextBuilder;
+
+ private List semanticMask;
+
+ public MaskedTextField() {
+ this("", '_');
+ }
+
+ public MaskedTextField(String mask) {
+ this(mask, '_');
+ }
+
+ public MaskedTextField(String mask, char placeholder) {
+ this.mask = new SimpleStringProperty(this, "mask", mask);
+ this.placeholder = placeholder;
+ this.plainText = new SimpleStringProperty(this, "plaintext", "");
+ this.plainTextBuilder = new StringBuilder();
+ this.semanticMask = new ArrayList<>();
+
+ init();
+ }
+
+ private void init() {
+ buildSemanticMask();
+ updateSemanticMask("");
+
+ // When MaskedTextField gains focus caret goes to first placeholder position
+ focusedProperty().addListener((observable, oldValue, newValue) -> {
+ if(newValue) {
+ Platform.runLater(() -> {
+ int pos = firstPlaceholderPosition();
+ selectRange(pos, pos);
+ positionCaret(pos);
+ });
+ }
+ });
+
+ // Add a listener to the plain text property so that binding will properly update the formatting as well
+ this.plainTextProperty().addListener((observable, oldValue, newValue) ->
+ {
+ this.updateSemanticMask(newValue);
+ });
+ }
+
+ // *******************************************************
+ // Properties
+ // *******************************************************
+ public String getPlainText() {
+ return plainText.get();
+ }
+
+ public void setPlainText(String text) {
+ setPlainTextWithUpdate(text);
+ }
+
+ public StringProperty plainTextProperty() {
+ return this.plainText;
+ }
+
+ public String getMask() {
+ return mask.get();
+ }
+
+ /**
+ * Set input mask, rebuild internal mask and update view.
+ * @param mask Mask dictating legal character values.
+ */
+ public void setMask(String mask) {
+ this.mask.set(mask);
+ buildSemanticMask();
+ updateSemanticMask("");
+ }
+
+ public StringProperty maskProperty() {
+ return this.mask;
+ }
+
+ // *******************************************************
+ // Getters and Setters
+ // *******************************************************
+
+ /**
+ * Returns the character to use in place of characters that are not present in the value, ie the user must fill them in.
+ */
+ public char getPlaceholder() {
+ return this.placeholder;
+ }
+
+ /**
+ * Set placeholder character.
+ */
+ public void setPlaceholder(char placeholder) {
+ this.placeholder = placeholder;
+ }
+
+ // *******************************************************
+ // Semantic Mask Methods
+ // *******************************************************
+
+ /**
+ * Build internal mask from input mask using AbstractFactory to add the right MaskCharacter.
+ */
+ private void buildSemanticMask() {
+ char[] newMask = getMask().toCharArray();
+ int i = 0;
+ int length = newMask.length;
+
+ semanticMask.clear();
+
+ MaskFactory factory = new MaskFactory();
+ while(i < length) {
+ char maskValue = newMask[i];
+
+ // If the actual char is MASK_ESCAPE look the next char as literal
+ if (maskValue == MASK_ESCAPE) {
+ semanticMask.add(factory.createMask(maskValue, newMask[i + 1]));
+ i++;
+ } else {
+ char value = isLiteral(maskValue) ? maskValue : placeholder;
+ semanticMask.add(factory.createMask(maskValue, value));
+ }
+
+ i++;
+ }
+
+ maskLength = semanticMask.size();
+ }
+
+ private void resetSemanticMask() {
+ semanticMask.stream().forEach(maskCharacter-> maskCharacter.setValue(placeholder));
+ }
+
+ private void updateSemanticMask(String newText) {
+ resetSemanticMask();
+ stringToValue(newText);
+ setText(valuesToString());
+ }
+
+ // *******************************************************
+ // Private Methods
+ // *******************************************************
+
+ /**
+ * Given a position in mask convert it into plainText position
+ */
+ private int convertToPlainTextPosition(int pos) {
+ int count = 0;
+
+ for (int i = 0; i < maskLength && i < pos; i++) {
+ MaskCharacter m = semanticMask.get(i);
+ if (!(m.getValue() == placeholder || m.isLiteral())) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Given a position in plain text convert it into mask position
+ */
+ private int convertToMaskPosition(int pos) {
+ int countLiterals = 0;
+ int countNonLiterals = 0;
+
+ for (int i = 0; i < maskLength && countNonLiterals < pos; i++) {
+ if (semanticMask.get(i).isLiteral()) {
+ countLiterals++;
+ } else {
+ countNonLiterals++;
+ }
+ }
+
+ return countLiterals + countNonLiterals;
+ }
+
+ /**
+ * Return true if a given char isn't a mask.
+ */
+ private boolean isLiteral(char c){
+ return (c != MASK_ANYTHING &&
+ c != MASK_CHARACTER &&
+ c != MASK_ESCAPE &&
+ c != MASK_NUMBER &&
+ c != MASK_CHAR_OR_NUM &&
+ c != MASK_HEXADECIMAL &&
+ c != MASK_LOWER_CHARACTER &&
+ c != MASK_UPPER_CHARACTER);
+ }
+
+ /**
+ * Return the position of first mask with placeholder on value.
+ */
+ private int firstPlaceholderPosition() {
+ for (int i = 0; i < maskLength; i++) {
+ if (semanticMask.get(i).getValue() == placeholder) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void setPlainTextWithUpdate(String text) {
+ String newText = (text != null) ? text : "";
+ setPlainTextWithoutUpdate(newText);
+ updateSemanticMask(newText);
+ }
+
+ private void setPlainTextWithoutUpdate(String text) {
+ plainTextBuilder = new StringBuilder(text);
+ plainText.set(text);
+ }
+
+ /**
+ * Insert values on semantic mask.
+ * @param text Plain text to be inserted
+ */
+ private void stringToValue(String text) {
+ StringBuilder inputText = new StringBuilder(text);
+ StringBuilder validText = new StringBuilder();
+
+ int maskPosition = 0;
+ int textLength = text.length();
+ int textPosition = 0;
+
+ while (textPosition < textLength) {
+ if (maskPosition < maskLength) {
+ MaskCharacter maskCharacter = semanticMask.get(maskPosition);
+
+ if (!maskCharacter.isLiteral()) {
+ char ch = inputText.charAt(textPosition);
+
+ if(maskCharacter.accept(ch)) {
+ maskCharacter.setValue(ch);
+ validText.append(maskCharacter.getValue());
+ maskPosition++;
+ }
+
+ textPosition++;
+ } else {
+ maskPosition++;
+ }
+ } else {
+ break;
+ }
+ }
+
+ setPlainTextWithoutUpdate(validText.toString());
+ }
+
+ /**
+ * Get all the semanticMask's values and convert it into an string.
+ */
+ private String valuesToString() {
+ StringBuilder value = new StringBuilder();
+ semanticMask.stream().forEach(character -> value.append(character.getValue()));
+ return value.toString();
+ }
+
+ // *******************************************************
+ // Overrides
+ // *******************************************************
+
+ @Override
+ public void replaceText(int start, int end, String newText) {
+ int position = convertToPlainTextPosition(start);
+ int endPosition = convertToPlainTextPosition(end);
+
+ String newString = null;
+ if (start != end) {
+ newString = plainTextBuilder.replace(position, endPosition, newText).toString();
+ } else {
+ newString = plainTextBuilder.insert(position, newText).toString();
+ }
+ updateSemanticMask(newString);
+
+ int newCaretPosition = convertToMaskPosition(position + newText.length());
+ selectRange(newCaretPosition, newCaretPosition);
+ }
+
+ @Override
+ public void replaceSelection(String string) {
+ IndexRange range = getSelection();
+ if (string.equals("")) {
+ deleteText(range.getStart(), range.getEnd());
+ } else {
+ replaceText(range.getStart(), range.getEnd(), string);
+ }
+ }
+
+ @Override
+ public void deleteText(int start, int end) {
+
+ int plainStart = convertToPlainTextPosition(start);
+ int plainEnd = convertToPlainTextPosition(end);
+
+ plainTextBuilder.delete(plainStart, plainEnd);
+ updateSemanticMask(plainTextBuilder.toString());
+
+ selectRange(start, start);
+ }
+
+ @Override
+ public void clear() {
+ setPlainText("");
+ }
+
+ // *******************************************************
+ // Private Classes
+ // *******************************************************
+ private abstract class MaskCharacter {
+
+ private char value;
+
+ public MaskCharacter(char value) {
+ this.value = value;
+ }
+
+ public char getValue() {
+ return this.value;
+ }
+
+ public void setValue(char value) {
+ this.value = value;
+ }
+
+ public boolean isLiteral() {
+ return false;
+ }
+
+ abstract boolean accept(char value);
+ }
+
+ private class MaskFactory {
+
+ public MaskCharacter createMask(char mask, char value) {
+ switch (mask) {
+ case MASK_ANYTHING:
+ return new AnythingCharacter(value);
+ case MASK_CHARACTER:
+ return new LetterCharacter(value);
+ case MASK_NUMBER:
+ return new NumericCharacter(value);
+ case MASK_CHAR_OR_NUM:
+ return new AlphaNumericCharacter(value);
+ case MASK_HEXADECIMAL:
+ return new HexCharacter(value);
+ case MASK_LOWER_CHARACTER:
+ return new LowerCaseCharacter(value);
+ case MASK_UPPER_CHARACTER:
+ return new UpperCaseCharacter(value);
+ default:
+ return new LiteralCharacter(value);
+ }
+
+ }
+ }
+
+ private class AnythingCharacter extends MaskCharacter {
+
+ public AnythingCharacter(char value) {
+ super(value);
+ }
+
+ public boolean accept(char value) {
+ return true;
+ }
+ }
+
+ private class AlphaNumericCharacter extends MaskCharacter {
+
+ public AlphaNumericCharacter(char value) {
+ super(value);
+ }
+
+ public boolean accept(char value) {
+ return Character.isLetterOrDigit(value);
+ }
+ }
+
+ private class LiteralCharacter extends MaskCharacter {
+
+ public LiteralCharacter(char value) {
+ super(value);
+ }
+
+ @Override
+ public boolean isLiteral() {
+ return true;
+ }
+
+ @Override
+ public void setValue(char value) {
+ // Literal can't be changed
+ }
+
+ public boolean accept(char value) {
+ return false;
+ }
+ }
+
+ private class LetterCharacter extends MaskCharacter {
+
+ public LetterCharacter(char value) {
+ super(value);
+ }
+
+ public boolean accept(char value) {
+ return Character.isLetter(value);
+ }
+
+ }
+
+ private class LowerCaseCharacter extends MaskCharacter {
+
+ public LowerCaseCharacter(char value) {
+ super(value);
+ }
+
+ @Override
+ public char getValue() {
+ return Character.toLowerCase(super.getValue());
+ }
+
+ public boolean accept(char value) {
+ return Character.isLetter(value);
+ }
+ }
+
+ private class UpperCaseCharacter extends MaskCharacter {
+
+ public UpperCaseCharacter(char value) {
+ super(value);
+ }
+
+ @Override
+ public char getValue() {
+ return Character.toUpperCase(super.getValue());
+ }
+
+ public boolean accept(char value) {
+ return Character.isLetter(value);
+ }
+ }
+
+ private class NumericCharacter extends MaskCharacter {
+
+ public NumericCharacter(char value) {
+ super(value);
+ }
+
+ @Override
+ public boolean accept(char value) {
+ return Character.isDigit(value);
+ }
+
+ }
+
+ private class HexCharacter extends MaskCharacter {
+
+ public HexCharacter(char value) {
+ super(value);
+ }
+
+ @Override
+ public boolean accept(char value) {
+ return Pattern.matches("[0-9a-fA-F]", String.valueOf(value));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/NavigationManager.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/NavigationManager.java
deleted file mode 100644
index 4cfba8c..0000000
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/NavigationManager.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.carvalhotechsolutions.mundoanimal.utils;
-
-import javafx.event.ActionEvent;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.stage.Stage;
-
-import java.io.IOException;
-
-public class NavigationManager {
- public static void switchScene(ActionEvent event, String fxmlPath, String title) throws IOException {
- FXMLLoader loader = new FXMLLoader(NavigationManager.class.getResource(fxmlPath));
- Parent root = loader.load();
-
- Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
- stage.setScene(new Scene(root));
- stage.setTitle(title);
- }
-}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/security/PasswordUtils.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/PasswordManager.java
similarity index 78%
rename from src/main/java/com/carvalhotechsolutions/mundoanimal/security/PasswordUtils.java
rename to src/main/java/com/carvalhotechsolutions/mundoanimal/utils/PasswordManager.java
index f74d575..dbdeb6f 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/security/PasswordUtils.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/PasswordManager.java
@@ -1,10 +1,10 @@
-package com.carvalhotechsolutions.mundoanimal.security;
+package com.carvalhotechsolutions.mundoanimal.utils;
import org.mindrot.jbcrypt.BCrypt;
-public class PasswordUtils {
+public class PasswordManager {
- private PasswordUtils() {
+ private PasswordManager() {
throw new UnsupportedOperationException("Esta classe não pode ser instanciada");
}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManager.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManager.java
new file mode 100644
index 0000000..dda0649
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManager.java
@@ -0,0 +1,156 @@
+package com.carvalhotechsolutions.mundoanimal.utils;
+
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.AnimalController;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.ClienteController;
+import com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento.MenuController;
+import com.carvalhotechsolutions.mundoanimal.enums.ScreenEnum;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
+
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+public class ScreenManager {
+ private final Stage stage;
+ private final BorderPane masterLayout;
+ private final Map screens;
+ private Map controllers = new HashMap<>();
+ private ScreenEnum currentScreen;
+ private BorderPane menuTemplate;
+ private StackPane contentArea;
+
+ public ScreenManager(Stage stage) {
+ this.stage = stage;
+ this.masterLayout = new BorderPane();
+ this.screens = new EnumMap<>(ScreenEnum.class);
+
+ // Configuração inicial do stage
+ this.stage.setTitle("Sistema PetShop Mundo Animal");
+ this.stage.setMinWidth(1400);
+ this.stage.setMinHeight(820);
+ this.stage.setWidth(1400);
+ this.stage.setHeight(820);
+
+ // Aplicar o CSS global ao masterLayout
+ masterLayout.getStylesheets().add(getClass().getResource("/css/style.css").toExternalForm());
+
+ // Criar a cena principal com o layout mestre
+ Scene masterScene = new Scene(masterLayout);
+ this.stage.setScene(masterScene);
+
+ // Carregar todas as telas
+ loadScreens();
+ }
+
+ private void loadScreens() {
+ for (ScreenEnum screen : ScreenEnum.values()) {
+ try {
+ FXMLLoader loader = new FXMLLoader(getClass().getResource(screen.getFxmlPath()));
+ Node loadedNode = loader.load();
+
+ if (screen.getType() == ScreenEnum.ScreenType.TEMPLATE) {
+ // Se for o template do menu, guarda referência especial
+ if (loadedNode instanceof BorderPane) {
+ menuTemplate = (BorderPane) loadedNode;
+ // Guarda referência da área de conteúdo
+ contentArea = (StackPane) menuTemplate.getCenter();
+ }
+ }
+
+ // Configurar visibilidade inicial
+ loadedNode.setVisible(false);
+ loadedNode.setManaged(false);
+
+ // Adicionar aos mapas de telas e controladores
+ screens.put(screen, loadedNode);
+ controllers.put(screen, loader.getController());
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.err.println("Erro ao carregar a tela: " + screen.getFxmlPath());
+ }
+ }
+ }
+
+ public void switchTo(ScreenEnum screen) {
+ switch (screen.getType()) {
+ case FULL:
+ switchToFullScreen(screen);
+ break;
+ case TEMPLATE:
+ switchToTemplate(screen);
+ break;
+ case CONTENT:
+ switchToContent(screen);
+ break;
+ }
+ currentScreen = screen;
+ }
+
+ private void switchToFullScreen(ScreenEnum screen) {
+ Node newScreen = screens.get(screen);
+ if (newScreen != null) {
+ contentArea.getChildren().clear();
+ masterLayout.getChildren().clear();
+ masterLayout.setCenter(newScreen);
+ newScreen.setVisible(true);
+ newScreen.setManaged(true);
+ }
+ }
+
+ private void switchToTemplate(ScreenEnum screen) {
+ Node template = screens.get(screen);
+ if (template != null) {
+ masterLayout.getChildren().clear();
+ masterLayout.setCenter(template);
+ template.setVisible(true);
+ template.setManaged(true);
+ }
+ }
+
+ private void switchToContent(ScreenEnum screen) {
+ // Garante que o template do menu está visível
+ if (!menuTemplate.isVisible()) {
+ masterLayout.getChildren().clear();
+ masterLayout.setCenter(menuTemplate);
+ menuTemplate.setVisible(true);
+ menuTemplate.setManaged(true);
+ }
+
+ // Carrega o novo conteúdo na área de conteúdo
+ Node content = screens.get(screen);
+ if (content != null && contentArea != null) {
+ contentArea.getChildren().clear();
+ contentArea.getChildren().add(content);
+ content.setVisible(true);
+ content.setManaged(true);
+ }
+ }
+
+ public Stage getStage() {
+ return this.stage;
+ }
+
+ public Node getScreen(ScreenEnum screen) {
+ return screens.get(screen);
+ }
+
+ public MenuController getMenuController() {
+ return (MenuController) controllers.get(ScreenEnum.MENU);
+ }
+
+ public AnimalController getAnimalController() {
+ return (AnimalController) controllers.get(ScreenEnum.PETS);
+ }
+
+ public ClienteController getClienteController() {
+ return (ClienteController) controllers.get(ScreenEnum.CLIENTES);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManagerHolder.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManagerHolder.java
new file mode 100644
index 0000000..0d93cff
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/ScreenManagerHolder.java
@@ -0,0 +1,16 @@
+package com.carvalhotechsolutions.mundoanimal.utils;
+
+public class ScreenManagerHolder {
+ private static ScreenManager instance;
+
+ public static void initialize(ScreenManager manager) {
+ instance = manager;
+ }
+
+ public static ScreenManager getInstance() {
+ if (instance == null) {
+ throw new IllegalStateException("ScreenManager ainda não foi inicializado.");
+ }
+ return instance;
+ }
+}
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/SessionManager.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/SessionManager.java
index ec671d2..c91a1e2 100644
--- a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/SessionManager.java
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/SessionManager.java
@@ -3,7 +3,6 @@
import com.carvalhotechsolutions.mundoanimal.model.Usuario;
public class SessionManager {
-
private static Usuario currentUser;
public static Usuario getCurrentUser() {
@@ -13,5 +12,9 @@ public static Usuario getCurrentUser() {
public static void setCurrentUser(Usuario user) {
currentUser = user;
}
+
+ public static void clearSession() {
+ currentUser = null;
+ }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/TextFormatterManager.java b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/TextFormatterManager.java
new file mode 100644
index 0000000..bb09e0b
--- /dev/null
+++ b/src/main/java/com/carvalhotechsolutions/mundoanimal/utils/TextFormatterManager.java
@@ -0,0 +1,105 @@
+package com.carvalhotechsolutions.mundoanimal.utils;
+
+import java.text.ParseException;
+import javafx.scene.control.TextField;
+import javax.swing.text.MaskFormatter;
+
+/**
+ *
+ * @author Marcos Ricardo Rodrigues
+ */
+public class TextFormatterManager {
+
+ private final MaskFormatter mf;
+ private TextField tf;
+ private String CaracteresValidos;
+ private String mask;
+
+ public TextFormatterManager() {
+ mf = new MaskFormatter();
+ }
+
+ public void formatter(TextField tf, String CaracteresValidos, String mask) {
+ try {
+ mf.setMask(mask);
+ } catch (ParseException ex) {
+ System.out.println(ex.getMessage());
+ }
+
+ mf.setValidCharacters(CaracteresValidos);
+ mf.setValueContainsLiteralCharacters(false);
+ String text = tf.getText().replaceAll("[\\W]", "");
+
+ boolean repetir = true;
+ while (repetir) {
+
+ char ultimoCaractere;
+
+ if (text.equals("")) {
+ break;
+ } else {
+ ultimoCaractere = text.charAt(text.length() - 1);
+ }
+
+ try {
+ text = mf.valueToString(text);
+ repetir = false;
+ } catch (ParseException ex) {
+ text = text.replace(ultimoCaractere + "", "");
+ repetir = true;
+ }
+
+ }
+
+ tf.setText(text);
+
+ if (!text.equals("")) {
+ for (int i = 0; tf.getText().charAt(i) != ' ' && i < tf.getLength() - 1; i++) {
+ tf.forward();
+ }
+ }
+ }
+
+ public void formatter(){
+ formatter(this.tf, this.CaracteresValidos, this.mask);
+ }
+
+ /**
+ * @return the tf
+ */
+ public TextField getTf() {
+ return tf;
+ }
+
+ /**
+ * @param tf the tf to set
+ */
+ public void setTf(TextField tf) {
+ this.tf = tf;
+ }
+
+ /**
+ * @return the CaracteresValidos
+ */
+ public String getCaracteresValidos() {
+ return CaracteresValidos;
+ }
+
+ /**
+ * @param CaracteresValidos the CaracteresValidos to set
+ */
+ public void setCaracteresValidos(String CaracteresValidos) {
+ this.CaracteresValidos = CaracteresValidos;
+ }
+
+ public String getMask() {
+ return mask;
+ }
+
+ /**
+ * @param mask the mask to set
+ */
+ public void setMask(String mask) {
+ this.mask = mask;
+ }
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 587a443..7c5b241 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -7,10 +7,11 @@
requires jakarta.persistence;
requires org.hibernate.orm.core;
requires jbcrypt;
+ requires animatefx;
+ requires fontawesomefx;
+ requires java.desktop;
// Export and open the controllers package
- opens com.carvalhotechsolutions.mundoanimal.controllers to javafx.fxml;
- exports com.carvalhotechsolutions.mundoanimal.controllers;
opens com.carvalhotechsolutions.mundoanimal to javafx.fxml;
exports com.carvalhotechsolutions.mundoanimal;
@@ -19,6 +20,14 @@
org.hibernate.orm.core,
jakarta.persistence;
exports com.carvalhotechsolutions.mundoanimal.model;
- exports com.carvalhotechsolutions.mundoanimal.controllers.login;
- opens com.carvalhotechsolutions.mundoanimal.controllers.login to javafx.fxml;
+ exports com.carvalhotechsolutions.mundoanimal.controllers.autenticacao;
+ opens com.carvalhotechsolutions.mundoanimal.controllers.autenticacao to javafx.fxml;
+ exports com.carvalhotechsolutions.mundoanimal.controllers.modals;
+ opens com.carvalhotechsolutions.mundoanimal.controllers.modals to javafx.fxml;
+ exports com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento;
+ opens com.carvalhotechsolutions.mundoanimal.controllers.gerenciamento to javafx.fxml;
+ exports com.carvalhotechsolutions.mundoanimal.database;
+ opens com.carvalhotechsolutions.mundoanimal.database to javafx.fxml;
+ exports com.carvalhotechsolutions.mundoanimal.utils;
+ opens com.carvalhotechsolutions.mundoanimal.utils to javafx.fxml;
}
\ No newline at end of file
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index fd56067..460cbbb 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -19,10 +19,32 @@
-
+
+
+
+
+ com.carvalhotechsolutions.mundoanimal.model.Usuario
+ com.carvalhotechsolutions.mundoanimal.model.Administrador
+ com.carvalhotechsolutions.mundoanimal.model.Agendamento
+ com.carvalhotechsolutions.mundoanimal.model.Animal
+ com.carvalhotechsolutions.mundoanimal.model.Cliente
+ com.carvalhotechsolutions.mundoanimal.model.Secretario
+ com.carvalhotechsolutions.mundoanimal.model.Servico
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/assets/images/confirmacao-login.png b/src/main/resources/assets/images/confirmacao-login.png
new file mode 100644
index 0000000..1eb009e
Binary files /dev/null and b/src/main/resources/assets/images/confirmacao-login.png differ
diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css
index d18dfbf..65ded6c 100644
--- a/src/main/resources/css/style.css
+++ b/src/main/resources/css/style.css
@@ -19,6 +19,16 @@ root {
-fx-font-family: "Roboto", serif;
}
+.search_input {
+ -fx-font-family: "Roboto", serif;
+ -fx-font-weight: 400;
+ -fx-font-style: normal;
+ -fx-font-size: 18px;
+ -fx-background-color: white;
+ -fx-border-color: #CCCCCC;
+ -fx-border-radius: 5px;
+}
+
.default_text_input {
-fx-font-family: "Roboto", serif;
-fx-font-weight: 400;
@@ -27,6 +37,12 @@ root {
-fx-background-color: transparent;
-fx-border-color: #CCCCCC;
-fx-border-radius: 5px;
+ -fx-background-insets: 0;
+}
+
+.text-area .content {
+ -fx-background-insets: 0;
+ -fx-background-color:white;
}
.default_label {
@@ -36,11 +52,18 @@ root {
-fx-font-size: 18px;
}
+.default_text {
+ -fx-font-family: "Roboto", serif;
+ -fx-font-style: normal;
+ -fx-font-weight: 200;
+ -fx-font-size: 18px;
+}
+
.white_bold_text {
-fx-font-family: "Roboto", serif;
- -fx-font-weight: 800;
+ -fx-font-weight: 700;
-fx-text-fill: white;
- -fx-font-size: 24px;
+ -fx-font-size: 22px;
}
.white_icon {
@@ -128,14 +151,14 @@ root {
-fx-font-family: "Roboto", serif;
-fx-font-style: normal;
-fx-font-weight: 400;
- -fx-font-size: 26px;
+ -fx-font-size: 20px;
}
#top_pane_user_name {
-fx-font-family: "Roboto", serif;
-fx-font-weight: 900;
-fx-font-style: normal;
- -fx-font-size: 24px;
+ -fx-font-size: 20px;
}
#top_pane_user_role {
@@ -143,7 +166,7 @@ root {
-fx-font-family: "Roboto", serif;
-fx-font-weight: 300;
-fx-font-style: normal;
- -fx-font-size: 18px;
+ -fx-font-size: 14px;
}
.menu_btn, .menu_btn_red {
@@ -190,24 +213,37 @@ root {
/* CSS TABELAS - INÍCIO */
+.table-view .scroll-bar * {
+ -fx-min-width: 0;
+ -fx-pref-width: 0;
+ -fx-max-width: 0;
+
+ -fx-min-height: 0;
+ -fx-pref-height: 0;
+ -fx-max-height: 0;
+}
+
.table-column {
-fx-font-family: "Roboto", serif;
-fx-font-size: 18px;
-fx-alignment: CENTER_LEFT;
-fx-padding: 0 0 0 16px;
-fx-pref-height: 79px;
+ -fx-border-color: transparent #e2e2e2 #e2e2e2 transparent;
}
.column-header {
-fx-background-color: #F2F5FA;
- -fx-font-weight: 800;
-fx-alignment: CENTER_LEFT;
- -fx-text-fill: #828282;
- -fx-border-color: transparent #cccccc #cccccc transparent;
+ -fx-border-color: transparent #e2e2e2 #e2e2e2 transparent;
+}
+
+#acaoColumn.table-column {
+ -fx-border-color: transparent transparent #e2e2e2 transparent;
}
#acaoColumn.column-header {
- -fx-border-color: transparent transparent #cccccc transparent;
+ -fx-border-color: transparent transparent #e2e2e2 transparent;
}
/* CSS TABELAS - FIM */
@@ -238,7 +274,7 @@ root {
}
.delete_btn {
- -fx-background-color: #FF0000;
+ -fx-background-color: #FF6F6F;
}
.cancel_btn {
@@ -246,3 +282,13 @@ root {
}
/* CSS MODALS - FIM */
+
+/* CSS POPUP - INÍCIO */
+
+.popup {
+ -fx-background-radius: 5px;
+ -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.2), 10, 0, 0, 0);
+ -fx-font-weight: 800;
+}
+
+/* CSS POPUP - FIM */
\ No newline at end of file
diff --git a/src/main/resources/fxml/autenticacao/login.fxml b/src/main/resources/fxml/autenticacao/login.fxml
index f70fb4e..556108c 100644
--- a/src/main/resources/fxml/autenticacao/login.fxml
+++ b/src/main/resources/fxml/autenticacao/login.fxml
@@ -3,47 +3,41 @@
+
-
+
-
-
-
-
+
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/src/main/resources/fxml/autenticacao/recuperar-senha.fxml b/src/main/resources/fxml/autenticacao/recuperar-senha.fxml
deleted file mode 100644
index ba51fad..0000000
--- a/src/main/resources/fxml/autenticacao/recuperar-senha.fxml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/fxml/autenticacao/recuperarSenha.fxml b/src/main/resources/fxml/autenticacao/recuperarSenha.fxml
new file mode 100644
index 0000000..f3eed88
--- /dev/null
+++ b/src/main/resources/fxml/autenticacao/recuperarSenha.fxml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/autenticacao/redefinir-senha.fxml b/src/main/resources/fxml/autenticacao/redefinir-senha.fxml
deleted file mode 100644
index 7b568ca..0000000
--- a/src/main/resources/fxml/autenticacao/redefinir-senha.fxml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/fxml/autenticacao/redefinirSenha.fxml b/src/main/resources/fxml/autenticacao/redefinirSenha.fxml
new file mode 100644
index 0000000..e477fd8
--- /dev/null
+++ b/src/main/resources/fxml/autenticacao/redefinirSenha.fxml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/gerenciamento/agendamentos.fxml b/src/main/resources/fxml/gerenciamento/agendamentos.fxml
new file mode 100644
index 0000000..3de9344
--- /dev/null
+++ b/src/main/resources/fxml/gerenciamento/agendamentos.fxml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/gerenciamento/clientes.fxml b/src/main/resources/fxml/gerenciamento/clientes.fxml
new file mode 100644
index 0000000..a6c03df
--- /dev/null
+++ b/src/main/resources/fxml/gerenciamento/clientes.fxml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/gerenciamento/menu.fxml b/src/main/resources/fxml/gerenciamento/menu.fxml
index 37f06a8..2ed121d 100644
--- a/src/main/resources/fxml/gerenciamento/menu.fxml
+++ b/src/main/resources/fxml/gerenciamento/menu.fxml
@@ -6,69 +6,188 @@
-
-
-
+
-
+
-
-
-
-
-
-
+
-
+
-
+
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
+
-
+
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
diff --git a/src/main/resources/fxml/gerenciamento/pets.fxml b/src/main/resources/fxml/gerenciamento/pets.fxml
new file mode 100644
index 0000000..0ab5c0c
--- /dev/null
+++ b/src/main/resources/fxml/gerenciamento/pets.fxml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/gerenciamento/secretarios.fxml b/src/main/resources/fxml/gerenciamento/secretarios.fxml
index b1a451a..04266ee 100644
--- a/src/main/resources/fxml/gerenciamento/secretarios.fxml
+++ b/src/main/resources/fxml/gerenciamento/secretarios.fxml
@@ -6,40 +6,81 @@
-
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/src/main/resources/fxml/gerenciamento/servicos.fxml b/src/main/resources/fxml/gerenciamento/servicos.fxml
index f49db84..9a43358 100644
--- a/src/main/resources/fxml/gerenciamento/servicos.fxml
+++ b/src/main/resources/fxml/gerenciamento/servicos.fxml
@@ -6,41 +6,87 @@
-
+
-
-
+
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
diff --git a/src/main/resources/fxml/modals/modal-confirmar-remocao.fxml b/src/main/resources/fxml/modals/modalConfirmarRemocao.fxml
similarity index 83%
rename from src/main/resources/fxml/modals/modal-confirmar-remocao.fxml
rename to src/main/resources/fxml/modals/modalConfirmarRemocao.fxml
index 2a4a922..0013706 100644
--- a/src/main/resources/fxml/modals/modal-confirmar-remocao.fxml
+++ b/src/main/resources/fxml/modals/modalConfirmarRemocao.fxml
@@ -6,14 +6,14 @@
-
+
-
+
@@ -21,7 +21,7 @@
-
+
diff --git a/src/main/resources/fxml/modals/modalCriarAgendamento.fxml b/src/main/resources/fxml/modals/modalCriarAgendamento.fxml
new file mode 100644
index 0000000..03759ef
--- /dev/null
+++ b/src/main/resources/fxml/modals/modalCriarAgendamento.fxml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/modals/modalCriarCliente.fxml b/src/main/resources/fxml/modals/modalCriarCliente.fxml
new file mode 100644
index 0000000..6e17d6b
--- /dev/null
+++ b/src/main/resources/fxml/modals/modalCriarCliente.fxml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/modals/modalCriarPet.fxml b/src/main/resources/fxml/modals/modalCriarPet.fxml
new file mode 100644
index 0000000..7634885
--- /dev/null
+++ b/src/main/resources/fxml/modals/modalCriarPet.fxml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/modals/modal-novo-secretario.fxml b/src/main/resources/fxml/modals/modalCriarSecretario.fxml
similarity index 92%
rename from src/main/resources/fxml/modals/modal-novo-secretario.fxml
rename to src/main/resources/fxml/modals/modalCriarSecretario.fxml
index 3489ad4..9588195 100644
--- a/src/main/resources/fxml/modals/modal-novo-secretario.fxml
+++ b/src/main/resources/fxml/modals/modalCriarSecretario.fxml
@@ -10,7 +10,8 @@
-
+
+
@@ -43,7 +44,7 @@
-
+
diff --git a/src/main/resources/fxml/modals/modal-novo-servico.fxml b/src/main/resources/fxml/modals/modalCriarServico.fxml
similarity index 97%
rename from src/main/resources/fxml/modals/modal-novo-servico.fxml
rename to src/main/resources/fxml/modals/modalCriarServico.fxml
index 9499542..638882e 100644
--- a/src/main/resources/fxml/modals/modal-novo-servico.fxml
+++ b/src/main/resources/fxml/modals/modalCriarServico.fxml
@@ -7,10 +7,10 @@
-
-
-
+
+
+
@@ -54,7 +54,7 @@
-
+
diff --git a/src/main/resources/fxml/modals/modalDetalhesPet.fxml b/src/main/resources/fxml/modals/modalDetalhesPet.fxml
new file mode 100644
index 0000000..7c77f5a
--- /dev/null
+++ b/src/main/resources/fxml/modals/modalDetalhesPet.fxml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fxml/modals/modal-editar-secretario.fxml b/src/main/resources/fxml/modals/modalEditarSecretario.fxml
similarity index 96%
rename from src/main/resources/fxml/modals/modal-editar-secretario.fxml
rename to src/main/resources/fxml/modals/modalEditarSecretario.fxml
index 98a2988..29d0e3b 100644
--- a/src/main/resources/fxml/modals/modal-editar-secretario.fxml
+++ b/src/main/resources/fxml/modals/modalEditarSecretario.fxml
@@ -9,7 +9,7 @@
-
+
diff --git a/src/main/resources/fxml/popup/feedback.fxml b/src/main/resources/fxml/popup/feedback.fxml
new file mode 100644
index 0000000..f07d128
--- /dev/null
+++ b/src/main/resources/fxml/popup/feedback.fxml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepositoryTest.java b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepositoryTest.java
new file mode 100644
index 0000000..c66af42
--- /dev/null
+++ b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AgendamentoRepositoryTest.java
@@ -0,0 +1,217 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.model.Servico;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.NoResultException;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+import java.util.Random;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class AgendamentoRepositoryTest {
+
+ private AgendamentoRepository agendamentoRepository = new AgendamentoRepository();
+ private EntityManager em;
+ private static EntityManagerFactory emf;
+
+ @BeforeEach
+ void setUp() {
+ if (emf == null) {
+ emf = Persistence.createEntityManagerFactory("test"); // Definido em persistence.xml
+ }
+ em = JPAutil.getEntityManager();
+
+ limparBaseDeDados();
+ }
+
+ @Test
+ void save() {
+ // Arrange
+ Agendamento agendamento = criarAgendamentoCompleto();
+
+ // Act
+ Agendamento savedAgendamento = agendamentoRepository.save(agendamento);
+
+ // Assert
+ assertNotNull(savedAgendamento.getId());
+ assertEquals(agendamento.getDataAgendamento(), savedAgendamento.getDataAgendamento());
+ assertEquals(agendamento.getHorarioAgendamento(), savedAgendamento.getHorarioAgendamento());
+ }
+
+ @Test
+ void update() {
+ // Arrange
+ Agendamento agendamento = criarAgendamentoCompleto();
+ Agendamento savedAgendamento = agendamentoRepository.save(agendamento);
+
+ LocalTime novoHorario = LocalTime.of(15, 0);
+ savedAgendamento.setHorarioAgendamento(novoHorario);
+
+ // Act
+ Agendamento updatedAgendamento = agendamentoRepository.save(savedAgendamento);
+
+ // Assert
+ assertEquals(novoHorario, updatedAgendamento.getHorarioAgendamento());
+ assertEquals(savedAgendamento.getId(), updatedAgendamento.getId());
+ }
+
+ @Test
+ void findById() {
+ // Arrange
+ Agendamento agendamento = criarAgendamentoCompleto();
+ Agendamento savedAgendamento = agendamentoRepository.save(agendamento);
+
+ // Act
+ Agendamento foundAgendamento = agendamentoRepository.findById(savedAgendamento.getId());
+
+ // Assert
+ assertNotNull(foundAgendamento);
+ assertEquals(savedAgendamento.getId(), foundAgendamento.getId());
+ }
+
+ @Test
+ void findAll() {
+ // Arrange
+ Agendamento agendamento1 = criarAgendamento(LocalDate.now(), LocalTime.of(14, 0));
+ Agendamento agendamento2 = criarAgendamento(LocalDate.now(), LocalTime.of(9, 0));
+ Agendamento agendamento3 = criarAgendamento(LocalDate.now().plusDays(1), LocalTime.of(10, 0));
+
+ agendamentoRepository.save(agendamento1);
+ agendamentoRepository.save(agendamento2);
+ agendamentoRepository.save(agendamento3);
+
+ // Act
+ List agendamentos = agendamentoRepository.findAll();
+
+ // Assert
+ assertEquals(3, agendamentos.size());
+ assertTrue(agendamentos.get(0).getHorarioAgendamento().isBefore(agendamentos.get(1).getHorarioAgendamento()));
+ assertTrue(agendamentos.get(0).getDataAgendamento().isBefore(agendamentos.get(2).getDataAgendamento()) ||
+ agendamentos.get(0).getDataAgendamento().isEqual(agendamentos.get(2).getDataAgendamento()));
+ }
+
+ @Test
+ void deleteById() {
+ // Arrange
+ Agendamento agendamento = criarAgendamentoCompleto();
+ Agendamento savedAgendamento = agendamentoRepository.save(agendamento);
+
+ // Act
+ agendamentoRepository.deleteById(savedAgendamento.getId());
+
+ // Assert
+ assertThrows(NoResultException.class, () -> {
+ agendamentoRepository.findById(savedAgendamento.getId());
+ });
+ }
+
+ @Test
+ void verificarDisponibilidadeHorario() {
+ // Arrange
+ LocalDate data = LocalDate.now();
+ LocalTime horario = LocalTime.of(14, 0);
+ Agendamento agendamento = criarAgendamento(data, horario);
+ agendamentoRepository.save(agendamento);
+
+ // Act & Assert
+ assertFalse(agendamentoRepository.verificarDisponibilidadeHorario(data, horario));
+ assertTrue(agendamentoRepository.verificarDisponibilidadeHorario(data, horario.plusHours(1)));
+ }
+
+ @Test
+ void buscarAgendamentosPorData() {
+ // Arrange
+ LocalDate hoje = LocalDate.now();
+ LocalDate amanha = hoje.plusDays(1);
+
+ Agendamento agendamento1 = criarAgendamento(hoje, LocalTime.of(9, 0));
+ Agendamento agendamento2 = criarAgendamento(hoje, LocalTime.of(14, 0));
+ Agendamento agendamento3 = criarAgendamento(amanha, LocalTime.of(10, 0));
+
+ agendamentoRepository.save(agendamento1);
+ agendamentoRepository.save(agendamento2);
+ agendamentoRepository.save(agendamento3);
+
+ // Act
+ List agendamentosHoje = agendamentoRepository.buscarAgendamentosPorData(hoje);
+ List agendamentosAmanha = agendamentoRepository.buscarAgendamentosPorData(amanha);
+
+ // Assert
+ assertEquals(2, agendamentosHoje.size());
+ assertEquals(1, agendamentosAmanha.size());
+ }
+
+ private Agendamento criarAgendamentoCompleto() {
+ Cliente cliente = new Cliente();
+ cliente.setNome("Cliente Teste " + System.nanoTime());
+ cliente.setTelefone(gerarNumero11Digitos());
+
+ Animal animal = new Animal();
+ animal.setNome("Pet Teste");
+ animal.setEspecie(EspecieAnimal.CACHORRO);
+ animal.setDono(cliente);
+
+ Servico servico = new Servico();
+ servico.setNomeServico("Banho");
+ servico.setDescricao("Banho completo");
+ servico.setValorServico(BigDecimal.valueOf(50.0));
+
+ em.getTransaction().begin();
+ em.persist(cliente);
+ em.persist(animal);
+ em.persist(servico);
+ em.getTransaction().commit();
+
+ Agendamento agendamento = new Agendamento();
+ agendamento.setCliente(cliente);
+ agendamento.setAnimal(animal);
+ agendamento.setServico(servico);
+ agendamento.setDataAgendamento(LocalDate.now());
+ agendamento.setHorarioAgendamento(LocalTime.of(14, 0));
+ agendamento.setResponsavelAtendimento("Funcionário Teste");
+
+ return agendamento;
+ }
+
+ private Agendamento criarAgendamento(LocalDate data, LocalTime horario) {
+ Agendamento agendamento = criarAgendamentoCompleto();
+ agendamento.setDataAgendamento(data);
+ agendamento.setHorarioAgendamento(horario);
+ return agendamento;
+ }
+
+ private void limparBaseDeDados() {
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Agendamento").executeUpdate();
+ em.createQuery("DELETE FROM Animal").executeUpdate();
+ em.createQuery("DELETE FROM Cliente").executeUpdate();
+ em.createQuery("DELETE FROM Servico").executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private String gerarNumero11Digitos() {
+ Random random = new Random();
+
+ // Gera um número entre 10000000000L e 99999999999L (11 dígitos)
+ long minimo = 10000000000L;
+ long maximo = 99999999999L;
+
+ // Calcula um número aleatório dentro do intervalo
+ long numeroAleatorio = minimo + ((long)(random.nextDouble() * (maximo - minimo)));
+
+ return String.valueOf(numeroAleatorio);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepositoryTest.java b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepositoryTest.java
new file mode 100644
index 0000000..cf251e9
--- /dev/null
+++ b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/AnimalRepositoryTest.java
@@ -0,0 +1,121 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AnimalRepositoryTest {
+ private static EntityManagerFactory emf;
+ private EntityManager em;
+ private AnimalRepository animalRepository = new AnimalRepository();
+
+ @BeforeEach
+ void setUp() {
+ if (emf == null) {
+ emf = Persistence.createEntityManagerFactory("test"); // Definido em persistence.xml
+ }
+ em = JPAutil.getEntityManager();
+
+ limparBaseDeDados();
+ }
+
+ @Test
+ void save() {
+ Animal animal = criarAnimal();
+ Cliente cliente = animal.getDono();
+
+ em.getTransaction().begin();
+ em.persist(animal);
+ em.getTransaction().commit();
+
+ assertNotNull(animal.getId());
+ assertEquals("Scooby", animal.getNome());
+ assertEquals(EspecieAnimal.CACHORRO, animal.getEspecie());
+ assertEquals(cliente, animal.getDono());
+ }
+
+ @Test
+ void findById() {
+ Animal animal = criarAnimal();
+
+ em.getTransaction().begin();
+ em.persist(animal);
+ em.getTransaction().commit();
+
+ Animal foundAnimal = animalRepository.findById(animal.getId());
+
+ assertNotNull(foundAnimal);
+ assertEquals(animal.getId(), foundAnimal.getId());
+ }
+
+ @Test
+ void findAll() {
+ Animal animal1 = criarAnimal();
+ Animal animal2 = criarAnimal();
+
+ em.getTransaction().begin();
+ em.persist(animal1);
+ em.persist(animal2);
+ em.getTransaction().commit();
+
+ List animais = animalRepository.findAll();
+ assertEquals(2, animais.size());
+ }
+
+ @Test
+ void deleteById() {
+ Animal animal = criarAnimal();
+ Cliente cliente = animal.getDono();
+
+ em.getTransaction().begin();
+ em.persist(animal);
+ em.getTransaction().commit();
+
+ animalRepository.deleteById(animal.getId());
+
+ // Abrir um novo EntityManager para verificar
+ EntityManager em2 = emf.createEntityManager();
+ Animal foundAnimal = em2.find(Animal.class, cliente.getId());
+ assertNull(foundAnimal);
+ em2.close(); // Fechar o EntityManager após o uso
+ }
+
+ private void limparBaseDeDados() {
+ // Limpar a base de dados antes de cada teste
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Agendamento").executeUpdate();
+ em.createQuery("DELETE FROM Animal").executeUpdate();
+ em.createQuery("DELETE FROM Cliente").executeUpdate();
+ em.createQuery("DELETE FROM Servico").executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private Animal criarAnimal() {
+ Cliente cliente = criarCliente("João Silva " + System.nanoTime(), "12345" + System.currentTimeMillis());
+ Animal animal = new Animal();
+ animal.setNome("Scooby");
+ animal.setEspecie(EspecieAnimal.CACHORRO);
+ animal.setDono(cliente);
+ return animal;
+ }
+
+ private Cliente criarCliente(String nome, String telefone) {
+ Cliente cliente = new Cliente();
+ cliente.setNome(nome);
+ cliente.setTelefone(telefone);
+ em.getTransaction().begin();
+ em.persist(cliente);
+ em.getTransaction().commit();
+ return cliente;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepositoryTest.java b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepositoryTest.java
new file mode 100644
index 0000000..7c30f42
--- /dev/null
+++ b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ClienteRepositoryTest.java
@@ -0,0 +1,154 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.EspecieAnimal;
+import com.carvalhotechsolutions.mundoanimal.model.Agendamento;
+import com.carvalhotechsolutions.mundoanimal.model.Animal;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.model.Servico;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ClienteRepositoryTest {
+
+ private static EntityManagerFactory emf;
+ private EntityManager em;
+ private ClienteRepository clienteRepository = new ClienteRepository();
+
+ @BeforeEach
+ void setUp() {
+ if (emf == null) {
+ emf = Persistence.createEntityManagerFactory("test"); // Definido em persistence.xml
+ }
+ em = JPAutil.getEntityManager();
+
+ limparBaseDeDados();
+ }
+
+ @Test
+ void save() {
+ Cliente cliente = criarCliente("João", "(88) 88888-8888");
+
+ Cliente savedCliente = clienteRepository.save(cliente);
+
+ assertNotNull(savedCliente.getId());
+ assertEquals(cliente.getNome(), savedCliente.getNome());
+ assertEquals(cliente.getTelefone(), savedCliente.getTelefone());
+ }
+
+ @Test
+ void findById() {
+ Cliente cliente = criarCliente("João", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(cliente);
+ em.getTransaction().commit();
+
+ Cliente foundCliente = clienteRepository.findById(cliente.getId());
+
+ assertNotNull(foundCliente);
+ assertEquals(cliente.getId(), foundCliente.getId());
+ }
+
+ @Test
+ void findAll() {
+ Cliente cliente1 = criarCliente("João", "(88) 88888-8888");
+ Cliente cliente2 = criarCliente("Maria", "(99) 99999-9999");
+
+ em.getTransaction().begin();
+ em.persist(cliente1);
+ em.persist(cliente2);
+ em.getTransaction().commit();
+
+ List clientes = clienteRepository.findAll();
+ assertEquals(2, clientes.size());
+ }
+
+ @Test
+ void deleteById() {
+ Cliente cliente = criarCliente("João", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(cliente);
+ em.getTransaction().commit();
+
+ clienteRepository.deleteById(cliente.getId());
+
+ // Abrir um novo EntityManager para verificar
+ EntityManager em2 = emf.createEntityManager();
+ Cliente foundCliente = em2.find(Cliente.class, cliente.getId());
+ assertNull(foundCliente);
+ em2.close(); // Fechar o EntityManager após o uso
+ }
+
+ @Test
+ public void deveRetornarTrueQuandoClientePossuiAgendamentos() {
+ Cliente cliente = criarCliente("João", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(cliente);
+
+ Servico servico = new Servico();
+ servico.setNomeServico("Banho");
+ servico.setValorServico(BigDecimal.valueOf(100));
+ servico.setDescricao("Banho com água e sabão");
+ em.persist(servico);
+
+ Animal animal = new Animal();
+ animal.setNome("Scooby");
+ animal.setEspecie(EspecieAnimal.CACHORRO);
+ animal.setDono(cliente);
+ em.persist(animal);
+
+ Agendamento agendamento = new Agendamento();
+ agendamento.setCliente(cliente);
+ agendamento.setServico(servico);
+ agendamento.setAnimal(animal);
+ agendamento.setDataAgendamento(LocalDate.now());
+ agendamento.setHorarioAgendamento(LocalTime.of(14, 0));
+ em.persist(agendamento);
+
+ em.getTransaction().commit();
+
+ boolean resultado = clienteRepository.clientePossuiAgendamentos(cliente.getId());
+ assertTrue(resultado);
+ }
+
+ @Test
+ public void deveRetornarFalseQuandoClienteNaoPossuiAgendamentos() {
+ Cliente cliente = criarCliente("João Silva", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(cliente);
+ em.getTransaction().commit();
+
+ boolean resultado = clienteRepository.clientePossuiAgendamentos(cliente.getId());
+ assertFalse(resultado);
+ }
+
+ private void limparBaseDeDados() {
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Agendamento").executeUpdate();
+ em.createQuery("DELETE FROM Animal").executeUpdate();
+ em.createQuery("DELETE FROM Cliente").executeUpdate();
+ em.createQuery("DELETE FROM Servico").executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private Cliente criarCliente(String nome, String telefone) {
+ Cliente cliente = new Cliente();
+ cliente.setNome(nome);
+ cliente.setTelefone(telefone);
+ return cliente;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepositoryTest.java b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepositoryTest.java
new file mode 100644
index 0000000..e0ad04b
--- /dev/null
+++ b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/SecretarioRepositoryTest.java
@@ -0,0 +1,105 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.enums.TipoUsuario;
+import com.carvalhotechsolutions.mundoanimal.model.Cliente;
+import com.carvalhotechsolutions.mundoanimal.model.Secretario;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SecretarioRepositoryTest {
+
+ private static EntityManagerFactory emf;
+ private EntityManager em;
+ private SecretarioRepository secretarioRepository = new SecretarioRepository();
+
+ @BeforeEach
+ void setUp() {
+ if (emf == null) {
+ emf = Persistence.createEntityManagerFactory("test"); // Definido em persistence.xml
+ }
+ em = JPAutil.getEntityManager();
+
+ limparBaseDeDados();
+ }
+
+ @Test
+ void save() {
+ Secretario secretario = criarSecretario("user123", "(88) 88888-8888");
+
+ Secretario savedSecretario = secretarioRepository.save(secretario);
+
+ assertNotNull(savedSecretario.getId());
+ assertEquals(secretario.getNomeUsuario(), savedSecretario.getNomeUsuario());
+ assertEquals(secretario.getTelefone(), savedSecretario.getTelefone());
+ assertEquals(secretario.getTipoUsuario(), savedSecretario.getTipoUsuario());
+ }
+
+ @Test
+ void findById() {
+ Secretario secretario = criarSecretario("user123", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(secretario);
+ em.getTransaction().commit();
+
+ Secretario foundSecretario = secretarioRepository.findById(secretario.getId());
+
+ assertNotNull(foundSecretario);
+ assertEquals(secretario.getId(), foundSecretario.getId());
+ }
+
+ @Test
+ void findAll() {
+ Secretario secretario1 = criarSecretario("user123", "(88) 88888-8888");
+ Secretario secretario2 = criarSecretario("user321", "(99) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(secretario1);
+ em.persist(secretario2);
+ em.getTransaction().commit();
+
+ List secretarios = secretarioRepository.findAll();
+ assertEquals(2, secretarios.size());
+ }
+
+ @Test
+ void deleteById() {
+ Secretario secretario = criarSecretario("user123", "(88) 88888-8888");
+
+ em.getTransaction().begin();
+ em.persist(secretario);
+ em.getTransaction().commit();
+
+ secretarioRepository.deleteById(secretario.getId());
+
+ // Abrir um novo EntityManager para verificar
+ EntityManager em2 = emf.createEntityManager();
+ Secretario foundSecretario = em2.find(Secretario.class, secretario.getId());
+ assertNull(foundSecretario);
+ em2.close(); // Fechar o EntityManager após o uso
+ }
+
+ private void limparBaseDeDados() {
+ // Limpar a base de dados antes de cada teste
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Secretario ").executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private Secretario criarSecretario(String username, String telefone) {
+ Secretario secretario = new Secretario();
+ secretario.setNomeUsuario(username);
+ secretario.setTelefone(telefone);
+ secretario.setTipoUsuario(TipoUsuario.SECRETARIO);
+ secretario.setSenha("senha123");
+ return secretario;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepositoryTest.java b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepositoryTest.java
new file mode 100644
index 0000000..4677d7e
--- /dev/null
+++ b/src/test/java/com/carvalhotechsolutions/mundoanimal/repositories/ServicoRepositoryTest.java
@@ -0,0 +1,103 @@
+package com.carvalhotechsolutions.mundoanimal.repositories;
+
+import com.carvalhotechsolutions.mundoanimal.database.JPAutil;
+import com.carvalhotechsolutions.mundoanimal.model.Servico;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ServicoRepositoryTest {
+
+ private static EntityManagerFactory emf;
+ private EntityManager em;
+ private ServicoRepository servicoRepository = new ServicoRepository();
+
+ @BeforeEach
+ void setUp() {
+ if (emf == null) {
+ emf = Persistence.createEntityManagerFactory("test"); // Definido em persistence.xml
+ }
+ em = JPAutil.getEntityManager();
+
+ limparBaseDeDados();
+ }
+
+ @Test
+ void save() {
+ Servico servico = criarServico();
+
+ Servico savedServico = servicoRepository.save(servico);
+
+ assertNotNull(savedServico.getId());
+ assertEquals(servico.getNomeServico(), savedServico.getNomeServico());
+ assertEquals(servico.getValorServico(), savedServico.getValorServico());
+ assertEquals(servico.getDescricao(), savedServico.getDescricao());
+ }
+
+ @Test
+ void findById() {
+ Servico servico = criarServico();
+
+ em.getTransaction().begin();
+ em.persist(servico);
+ em.getTransaction().commit();
+
+ Servico foundServico = servicoRepository.findById(servico.getId());
+ assertNotNull(foundServico);
+ assertEquals(servico.getId(), foundServico.getId());
+ }
+
+ @Test
+ void findAll() {
+ Servico servico1 = criarServico();
+ Servico servico2 = criarServico();
+
+ em.getTransaction().begin();
+ em.persist(servico1);
+ em.persist(servico2);
+ em.getTransaction().commit();
+
+ List servicos = servicoRepository.findAll();
+ assertEquals(2, servicos.size());
+ }
+
+ @Test
+ void deleteById() {
+ Servico servico = criarServico();
+
+ em.getTransaction().begin();
+ em.persist(servico);
+ em.getTransaction().commit();
+
+ servicoRepository.deleteById(servico.getId());
+
+ // Abrir um novo EntityManager para verificar
+ EntityManager em2 = emf.createEntityManager();
+ Servico foundService = em2.find(Servico.class, servico.getId());
+ assertNull(foundService);
+ em2.close(); // Fechar o EntityManager após o uso
+ }
+
+ private void limparBaseDeDados() {
+ // Limpar a base de dados antes de cada teste
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Agendamento").executeUpdate();
+ em.createQuery("DELETE FROM Servico").executeUpdate();
+ em.getTransaction().commit();
+ }
+
+ private Servico criarServico() {
+ Servico servico = new Servico();
+ servico.setNomeServico("Banho");
+ servico.setValorServico(BigDecimal.valueOf(100));
+ servico.setDescricao("Banho com água e sabão");
+ return servico;
+ }
+}
\ No newline at end of file