Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 35 additions & 13 deletions Convive/src/main/java/com/EC6/Convive/Config/DataInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,54 +113,76 @@ private void seedOcorrencias() {
LocalDateTime agora = LocalDateTime.now();

salvarOcorrencia(moradores.get(0),
"Vazamento na garagem",
CategoriaOcorrencia.INFRAESTRUTURA,
"Vazamento no teto da garagem próximo à vaga 12.",
Prioridade.ALTA, StatusOcorrencia.REGISTRADA, agora.minusHours(3));
StatusOcorrencia.REGISTRADA, agora.minusHours(3));

salvarOcorrencia(moradores.get(1),
"Lâmpada queimada no corredor",
CategoriaOcorrencia.OUTRO,
"Lâmpada queimada no corredor do 2º andar.",
Prioridade.NAO_DEFINIDA, StatusOcorrencia.REGISTRADA, agora.minusDays(1));
StatusOcorrencia.REGISTRADA, agora.minusDays(1));

salvarOcorrencia(moradores.get(2),
"Barulho excessivo após 23h",
CategoriaOcorrencia.BARULHO,
"Barulho excessivo após 23h no apartamento 302.",
Prioridade.MEDIA, StatusOcorrencia.EM_ANALISE, agora.minusDays(2));
StatusOcorrencia.EM_ANALISE, agora.minusDays(2));

salvarOcorrencia(moradores.get(3),
"Portão da garagem com falha",
CategoriaOcorrencia.INFRAESTRUTURA,
"Portão da garagem com falha intermitente.",
Prioridade.ALTA, StatusOcorrencia.EM_ANALISE, agora.minusDays(4));
StatusOcorrencia.EM_ANALISE, agora.minusDays(4));

salvarOcorrencia(moradores.get(4),
"Animal solto nas áreas comuns",
CategoriaOcorrencia.REGRAS,
"Animal solto nas áreas comuns sem coleira.",
Prioridade.BAIXA, StatusOcorrencia.REGISTRADA, agora.minusDays(6));
StatusOcorrencia.REGISTRADA, agora.minusDays(6));

salvarOcorrencia(moradores.get(0),
"Uso indevido da churrasqueira",
CategoriaOcorrencia.REGRAS,
"Uso indevido da churrasqueira fora do horário permitido.",
Prioridade.MEDIA, StatusOcorrencia.RESOLVIDA, agora.minusDays(10));
StatusOcorrencia.RESOLVIDA, agora.minusDays(10));

salvarOcorrencia(moradores.get(1),
"Encomenda sem identificação",
CategoriaOcorrencia.REGRAS,
"Entrega de encomenda sem identificação na portaria.",
Prioridade.BAIXA, StatusOcorrencia.RESOLVIDA, agora.minusDays(15));
StatusOcorrencia.RESOLVIDA, agora.minusDays(15));

salvarOcorrencia(moradores.get(5),
"Limpeza da piscina",
CategoriaOcorrencia.LIMPEZA,
"Reclamação sobre limpeza da piscina.",
Prioridade.NAO_DEFINIDA, StatusOcorrencia.REGISTRADA, agora.minusDays(20));
StatusOcorrencia.REGISTRADA, agora.minusDays(20));

salvarOcorrencia(moradores.get(2),
"Revisão de multa por ruído",
CategoriaOcorrencia.BARULHO,
"Solicitação de revisão de multa por ruído.",
Prioridade.ALTA, StatusOcorrencia.REJEITADA, agora.minusDays(35));
StatusOcorrencia.REJEITADA, agora.minusDays(35));

salvarOcorrencia(moradores.get(3),
"Infiltração na unidade 408",
CategoriaOcorrencia.INFRAESTRUTURA,
"Infiltração na parede da unidade 408.",
Prioridade.MEDIA, StatusOcorrencia.RESOLVIDA, agora.minusDays(40));
StatusOcorrencia.RESOLVIDA, agora.minusDays(40));

System.out.println("10 ocorrências de teste criadas.");
}

private void salvarOcorrencia(Morador morador, String descricao, Prioridade prioridade,
StatusOcorrencia status, LocalDateTime dataRegistro) {
private void salvarOcorrencia(Morador morador, String titulo, CategoriaOcorrencia categoria,
String descricao, StatusOcorrencia status, LocalDateTime dataRegistro) {
Ocorrencia ocorrencia = new Ocorrencia();
ocorrencia.setUsuario(morador);
ocorrencia.setTitulo(titulo);
ocorrencia.setCategoria(categoria);
ocorrencia.setDescricao(descricao);
ocorrencia.setPrioridade(prioridade);
ocorrencia.setPrioridade(categoria.getPrioridadePadrao());
ocorrencia.setStatus(status);
ocorrencia.setDataRegistro(dataRegistro);
ocorrencia.setProtocolo(gerarProtocolo());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,23 @@ public String carregarMais(
@PostMapping
public String registrarNovaOcorrencia(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestParam String titulo,
@RequestParam CategoriaOcorrencia categoria,
@RequestParam String descricao,
@RequestParam(value = "imagemEvidencia", required = false) MultipartFile imagemEvidencia,
RedirectAttributes redirectAttributes) {
try {
if (titulo == null || titulo.isBlank()) {
redirectAttributes.addFlashAttribute("erroOcorrencia", "O título é obrigatório.");
return "redirect:/morador/ocorrencias";
}

Usuario usuarioLogado = userDetails.getUsuario();

Ocorrencia novaOcorrencia = new Ocorrencia();
novaOcorrencia.setTitulo(titulo.trim());
novaOcorrencia.setCategoria(categoria);
novaOcorrencia.setDescricao(descricao);
novaOcorrencia.setPrioridade(Prioridade.NAO_DEFINIDA);
novaOcorrencia.setStatus(StatusOcorrencia.REGISTRADA);
novaOcorrencia.setUsuario(usuarioLogado);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
public record OcorrenciaCriadaEvent(
LocalDateTime dataRegistro,
String nomeMorador,
String titulo,
String categoria,
String descricao
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.EC6.Convive.Model;

public enum CategoriaOcorrencia {
BARULHO("Barulho", Prioridade.ALTA),
INFRAESTRUTURA("Infraestrutura", Prioridade.ALTA),
LIMPEZA("Limpeza", Prioridade.MEDIA),
REGRAS("Regras", Prioridade.MEDIA),
OUTRO("Outro", Prioridade.NAO_DEFINIDA);

private final String rotulo;
private final Prioridade prioridadePadrao;

CategoriaOcorrencia(String rotulo, Prioridade prioridadePadrao) {
this.rotulo = rotulo;
this.prioridadePadrao = prioridadePadrao;
}

public String getRotulo() {
return rotulo;
}

public Prioridade getPrioridadePadrao() {
return prioridadePadrao;
}
}
7 changes: 7 additions & 0 deletions Convive/src/main/java/com/EC6/Convive/Model/Ocorrencia.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ public class Ocorrencia {
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@Column(name = "titulo", length = 200, nullable = false)
private String titulo;

@Enumerated(EnumType.STRING)
@Column(name = "categoria", nullable = false)
private CategoriaOcorrencia categoria;

@Column(name = "descricao", length = 10000)
private String descricao;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public interface OcorrenciaRepository extends JpaRepository<Ocorrencia, UUID> {
SELECT o FROM Ocorrencia o
WHERE o.usuario.id = :moradorId
AND (:busca IS NULL OR LOWER(o.protocolo) LIKE LOWER(CONCAT('%', :busca, '%'))
OR LOWER(o.titulo) LIKE LOWER(CONCAT('%', :busca, '%'))
OR LOWER(o.descricao) LIKE LOWER(CONCAT('%', :busca, '%')))
AND (:status IS NULL OR o.status = :status)
AND (:prioridade IS NULL OR o.prioridade = :prioridade)
Expand All @@ -40,6 +41,7 @@ Page<Ocorrencia> findByUsuarioTriagem(@Param("moradorId") UUID moradorId,
@Query("""
SELECT o FROM Ocorrencia o
WHERE (:busca IS NULL OR LOWER(o.protocolo) LIKE LOWER(CONCAT('%', :busca, '%'))
OR LOWER(o.titulo) LIKE LOWER(CONCAT('%', :busca, '%'))
OR LOWER(o.descricao) LIKE LOWER(CONCAT('%', :busca, '%')))
AND (:status IS NULL OR o.status = :status)
AND (:prioridade IS NULL OR o.prioridade = :prioridade)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public RenderedEmail renderOcorrenciaNotification(String recipientName, Ocorrenc
context.setVariable("detailRows", List.of(
new EmailDetailRow("Data do registro", EmailDateFormatter.format(event.dataRegistro())),
new EmailDetailRow("Registrado por", event.nomeMorador()),
new EmailDetailRow("Título", event.titulo()),
new EmailDetailRow("Categoria", event.categoria()),
new EmailDetailRow("Descrição", event.descricao())
));

Expand All @@ -105,6 +107,8 @@ public RenderedEmail renderOcorrenciaNotification(String recipientName, Ocorrenc

Data do registro: %s
Registrado por: %s
Título: %s
Categoria: %s
Descrição: %s

Acesse: %s
Expand All @@ -115,6 +119,8 @@ public RenderedEmail renderOcorrenciaNotification(String recipientName, Ocorrenc
recipientName,
EmailDateFormatter.format(event.dataRegistro()),
event.nomeMorador(),
event.titulo(),
event.categoria(),
event.descricao(),
actionUrl
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@ public class OcorrenciaService {
private final OcorrenciaRepository ocorrenciaRepository;
private final ApplicationEventPublisher eventPublisher;

public void aplicarPrioridadePadrao(Ocorrencia ocorrencia) {
if (ocorrencia.getCategoria() == null) {
ocorrencia.setPrioridade(Prioridade.NAO_DEFINIDA);
return;
}
ocorrencia.setPrioridade(ocorrencia.getCategoria().getPrioridadePadrao());
}

public Ocorrencia insert(Ocorrencia ocorrencia) {
aplicarPrioridadePadrao(ocorrencia);
ocorrencia.setDataRegistro(LocalDateTime.now());

String anoAtual = String.valueOf(Year.now().getValue());
Expand All @@ -50,6 +59,8 @@ public Ocorrencia insert(Ocorrencia ocorrencia) {
eventPublisher.publishEvent(new OcorrenciaCriadaEvent(
saved.getDataRegistro(),
saved.getUsuario().getNome(),
saved.getTitulo(),
saved.getCategoria().getRotulo(),
saved.getDescricao()
));

Expand Down
6 changes: 6 additions & 0 deletions Convive/src/main/resources/static/js/ocorrencias.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ function abrirConsulta(elemento) {
const id = elemento.getAttribute('data-id');
const protocolo = elemento.getAttribute('data-protocolo');
const data = elemento.getAttribute('data-data');
const titulo = elemento.getAttribute('data-titulo');
const categoria = elemento.getAttribute('data-categoria');
const prioridade = elemento.getAttribute('data-prioridade');
const status = elemento.getAttribute('data-status').replace('_', ' ');
const descricao = elemento.getAttribute('data-descricao');
const comentarioModerador = elemento.getAttribute('data-comentario');

const campoProtocolo = document.getElementById('detalhe-protocolo');
const campoData = document.getElementById('detalhe-data');
const campoTitulo = document.getElementById('detalhe-titulo-ocorrencia');
const campoCategoria = document.getElementById('detalhe-categoria');
const campoPrioridade = document.getElementById('detalhe-prioridade');
const campoStatus = document.getElementById('detalhe-status');
const campoDescricao = document.getElementById('detalhe-descricao');
Expand All @@ -20,6 +24,8 @@ function abrirConsulta(elemento) {

if (campoProtocolo) campoProtocolo.innerText = '#' + protocolo;
if (campoData) campoData.innerText = data;
if (campoTitulo) campoTitulo.innerText = titulo || '';
if (campoCategoria) campoCategoria.innerText = categoria || '';
if (campoPrioridade) campoPrioridade.innerText = prioridade;
if (campoStatus) campoStatus.innerText = status;
if (campoDescricao) campoDescricao.innerText = descricao;
Expand Down
13 changes: 13 additions & 0 deletions Convive/src/main/resources/static/js/triagemOcorrencias.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ function aplicarEvidencia(urlEvidencia) {
function preencherDetalhes(card) {
var id = card.getAttribute('data-id');
var protocolo = card.getAttribute('data-protocolo');
var titulo = card.getAttribute('data-titulo');
var categoriaRotulo = card.getAttribute('data-categoria-rotulo');
var categoria = card.getAttribute('data-categoria');
var prioridade = card.getAttribute('data-prioridade');
var status = card.getAttribute('data-status');
var descricao = card.getAttribute('data-descricao');
Expand All @@ -60,11 +63,21 @@ function preencherDetalhes(card) {
setDetalheField('detalhe-protocolo', 'innerText', protocolo, function (p) { return '#' + p; });
setDetalheField('detalhe-morador', 'innerText', morador);
setDetalheField('detalhe-data', 'innerText', data);
setDetalheField('detalhe-titulo', 'innerText', titulo);
setDetalheField('detalhe-categoria', 'innerText', categoriaRotulo);
setDetalheField('detalhe-descricao', 'innerText', descricao);
setDetalheField('input-resposta', 'value', resposta);
setDetalheField('select-prioridade', 'value', prioridade);
setDetalheField('select-status', 'value', status);

var mostrarAviso = categoria === 'OUTRO' && prioridade === 'NAO_DEFINIDA';
['detalhe-aviso-prioridade', 'detalhe-aviso-prioridade-mobile'].forEach(function (id) {
var aviso = document.getElementById(id);
if (!aviso) return;
if (mostrarAviso) aviso.classList.remove('hidden');
else aviso.classList.add('hidden');
});

aplicarBadgePrioridade(prioridade);
aplicarEvidencia(urlEvidencia);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h1 class="text-h1 font-h1 text-on-surface">Triagem de Ocorrências</h1>
<div class="bg-surface-container-lowest px-4 sm:px-6 md:px-margin py-sm border-b border-outline-variant flex flex-wrap gap-md items-center shadow-sm z-0 relative shrink-0">
<div class="relative w-full md:w-64">
<span class="material-symbols-outlined absolute left-sm top-1/2 transform -translate-y-1/2 text-on-surface-variant">search</span>
<input id="filtro-busca" th:value="${busca}" onkeyup="debounceAplicarFiltros()" class="w-full pl-lg pr-sm py-sm bg-surface rounded-lg border border-outline-variant focus:border-primary focus:ring-1 focus:ring-primary text-body-sm font-body-sm text-on-surface placeholder:text-outline outline-none transition-colors" placeholder="Buscar por protocolo ou título..." type="text"/>
<input id="filtro-busca" th:value="${busca}" onkeyup="debounceAplicarFiltros()" class="w-full pl-lg pr-sm py-sm bg-surface rounded-lg border border-outline-variant focus:border-primary focus:ring-1 focus:ring-primary text-body-sm font-body-sm text-on-surface placeholder:text-outline outline-none transition-colors" placeholder="Buscar por protocolo, título ou descrição..." type="text"/>
</div>
<div class="flex items-center gap-sm">
<span class="text-label-md font-label-md text-on-surface-variant uppercase">Prioridade:</span>
Expand Down Expand Up @@ -92,6 +92,9 @@ <h2 class="text-h3 font-h3 text-on-surface shrink-0">Fila de Análise</h2>
th:data-protocolo="${ocorrencia.protocolo}"
th:data-prioridade="${ocorrencia.prioridade}"
th:data-status="${ocorrencia.status}"
th:data-titulo="${ocorrencia.titulo}"
th:data-categoria="${ocorrencia.categoria.name()}"
th:data-categoria-rotulo="${ocorrencia.categoria.rotulo}"
th:data-descricao="${ocorrencia.descricao}"
th:data-resposta="${ocorrencia.respostaModerador ?: ''}"
th:data-data-sort="${#temporals.format(ocorrencia.dataRegistro, 'yyyyMMddHHmmss')}"
Expand All @@ -108,6 +111,11 @@ <h2 class="text-h3 font-h3 text-on-surface shrink-0">Fila de Análise</h2>
</div>
<span class="text-body-sm font-body-sm text-outline" th:text="${#temporals.format(ocorrencia.dataRegistro, 'dd/MM HH:mm')}">Data</span>
</div>
<div class="mb-xs flex items-center gap-xs flex-wrap">
<span class="text-label-md font-label-md px-sm py-xs rounded-full bg-surface-container-low text-on-surface-variant border border-outline-variant uppercase"
th:text="${ocorrencia.categoria.rotulo}">Categoria</span>
</div>
<p class="text-body-md font-body-md text-on-surface font-medium mb-xs line-clamp-1" th:text="${ocorrencia.titulo}">Título...</p>
<p class="text-body-sm font-body-sm text-on-surface-variant mb-md line-clamp-2" th:text="${ocorrencia.descricao}">Descrição...</p>

<div class="flex justify-between items-center border-t border-outline-variant pt-sm mt-sm">
Expand Down Expand Up @@ -166,6 +174,13 @@ <h2 class="text-h2 font-h2 text-on-surface">Detalhes da Ocorrência</h2>

<div class="flex-1 min-h-0 overflow-y-auto p-md flex flex-col gap-lg">

<section>
<h4 class="text-label-md font-label-md text-on-surface-variant uppercase mb-sm">Título e Categoria</h4>
<p id="detalhe-titulo" class="text-body-md font-body-md text-on-surface font-medium mb-xs"></p>
<p id="detalhe-categoria" class="text-body-sm font-body-sm text-on-surface-variant mb-xs"></p>
<p id="detalhe-aviso-prioridade" class="text-body-sm font-body-sm text-outline hidden">Prioridade aguardando definição pelo moderador.</p>
</section>

<section>
<h4 class="text-label-md font-label-md text-on-surface-variant uppercase mb-sm">Descrição do Problema</h4>
<p id="detalhe-descricao" class="text-body-md font-body-md text-on-surface bg-surface p-md rounded-lg border border-outline-variant whitespace-pre-wrap max-h-48 overflow-y-auto"></p>
Expand Down Expand Up @@ -241,6 +256,12 @@ <h2 id="modal-detalhes-triagem-titulo" class="text-h2 font-h2 text-on-surface">D
</div>
</div>
<div class="p-md flex flex-col gap-md flex-1">
<section>
<h4 class="text-label-md font-label-md text-on-surface-variant uppercase mb-sm">Título e Categoria</h4>
<p id="detalhe-titulo-mobile" class="text-body-md font-body-md text-on-surface font-medium mb-xs"></p>
<p id="detalhe-categoria-mobile" class="text-body-sm font-body-sm text-on-surface-variant mb-xs"></p>
<p id="detalhe-aviso-prioridade-mobile" class="text-body-sm font-body-sm text-outline hidden">Prioridade aguardando definição pelo moderador.</p>
</section>
<section>
<h4 class="text-label-md font-label-md text-on-surface-variant uppercase mb-sm">Descrição do Problema</h4>
<p id="detalhe-descricao-mobile" class="text-body-md font-body-md text-on-surface bg-surface p-md rounded-lg border border-outline-variant whitespace-pre-wrap"></p>
Expand Down
Loading
Loading