From 5e1564dedb0af80dd8c580cb8dff0c0aeeecf243 Mon Sep 17 00:00:00 2001 From: GustavoRobs-11 Date: Thu, 7 May 2026 17:27:23 -0300 Subject: [PATCH] notificacoes-feitas --- frontend/src/assets/styles/navbar-footer.css | 115 ----- .../styles/notificacoes/notificacoes.css | 458 ++++++++++++++++++ .../src/components/common/NavbarDesktop.jsx | 161 ++---- .../common/Notifications/notifications.jsx | 394 +++++++++++++++ 4 files changed, 891 insertions(+), 237 deletions(-) create mode 100644 frontend/src/assets/styles/notificacoes/notificacoes.css create mode 100644 frontend/src/components/common/Notifications/notifications.jsx diff --git a/frontend/src/assets/styles/navbar-footer.css b/frontend/src/assets/styles/navbar-footer.css index 6ae1db1..0d44d33 100644 --- a/frontend/src/assets/styles/navbar-footer.css +++ b/frontend/src/assets/styles/navbar-footer.css @@ -145,130 +145,15 @@ a { } -/* ===== MODAL ===== */ -.notif-modal { - position: relative; - width: 420px; - max-height: 80vh; - overflow-y: auto; - background: #f3f3f3; - border-radius: 20px; - padding: 20px; - box-shadow: 0 15px 40px rgba(0, 0, 0, 0.25); -} - -/* botão fechar */ - -.notif-close { - position: absolute; - top: 12px; - right: 12px; - background: none; - border: none; - font-size: 24px; - cursor: pointer; - color: #333; - transition: .2s; -} - -.notif-close:hover { - transform: scale(1.1); - color: #000; -} - -/* titulo */ -.notif-title { - font-size: 22px; - font-weight: 600; - margin-bottom: 15px; -} -/* ===== MENSAGEM ===== */ -.notif-msg { - display: flex; - align-items: center; - gap: 12px; - background: #e7dfc7; - padding: 12px; - border-radius: 14px; - margin-bottom: 12px; -} -.notif-avatar { - width: 42px; - height: 42px; - border-radius: 50%; - object-fit: cover; -} -.notif-msg-text { - flex: 1; -} -.notif-msg-text strong { - font-size: 15px; - display: block; -} -.notif-msg-text p { - font-size: 14px; - margin: 2px 0 0; - color: #444; -} -.notif-hora { - font-size: 12px; - color: #555; -} - -/* ===== CONFIRMAÇÃO ===== */ - -.notif-confirm { - background: #9dd187; - padding: 14px; - border-radius: 14px; - margin-bottom: 12px; -} - -.notif-confirm-header { - display: flex; - align-items: center; - gap: 10px; - cursor: pointer; - font-weight: 500; - -} - -.notif-confirm-header svg { - font-size: 22px; -} - -.notif-confirm-header p { - flex: 1; - margin: 0; -} - -.notif-confirm-header span { - font-size: 18px; -} - -/* ===== BODY EXPANDIDO ===== */ - -.notif-confirm-body { - background: #cfe8c3; - margin-top: 12px; - padding: 14px; - border-radius: 12px; - font-size: 14px; - text-align: left; -} - -.notif-confirm-body p { - margin: 5px 0; -} /* ===== BOTÕES ===== */ diff --git a/frontend/src/assets/styles/notificacoes/notificacoes.css b/frontend/src/assets/styles/notificacoes/notificacoes.css new file mode 100644 index 0000000..503f641 --- /dev/null +++ b/frontend/src/assets/styles/notificacoes/notificacoes.css @@ -0,0 +1,458 @@ +.notif-modal { + position: relative; + width: 420px; + max-height: 80vh; + overflow-y: auto; + background: #f3f3f3; + border-radius: 20px; + padding: 20px; + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.25); +} + +.container-status { + display: flex; + align-items: start; + width: 100%; + padding-top: 10px; +} + +.status-notificacoes { + display: flex; +} + +/* botão fechar */ + +.notif-close { + position: absolute; + top: 12px; + right: 12px; + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: #333; + transition: .2s; +} + +.notif-close:hover { + transform: scale(1.1); + color: #000; +} + +/* titulo */ + +.notif-title { + font-size: 22px; + font-weight: 600; + margin-bottom: 15px; + width: 100%; + display: flex; +} + +/* ===== ICON SVG ===== */ + +.icon-svg { + width: 2rem; + height: 2rem; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.icon-svg svg { + width: 100%; + height: 100%; +} + +/* ===== MENSAGEM ===== */ + +.notif-msg { + display: flex; + align-items: center; + gap: 12px; + background: #e7dfc7; + padding: 12px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-avatar { + width: 3rem; + height: 3rem; + border-radius: 50%; + object-fit: cover; +} + +.notif-msg-text { + flex: 1; +} + +.notif-msg-text strong { + font-size: 15px; + display: block; + text-align: start; +} + +.notif-msg-text p { + font-size: 14px; + margin: 2px 0 0; + color: #444; + text-align: start; +} + +.notif-hora { + font-size: 12px; + color: #555; +} + +/* ===== CONFIRMAÇÃO ===== */ + +.notif-confirm { + background: #b8eda0; + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-confirm.active { + background: #d2edc5; +} + +.notif-confirm-header { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + font-weight: 500; +} + +.notif-confirm-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-confirm-header span { + font-size: 18px; +} + +.notif-confirm-body { + margin-top: 12px; + border-radius: 12px; + font-size: 14px; + text-align: left; + gap: 10px; +} + +.notif-confirm-body p { + margin: 5px 0; +} + +.container-info-icon { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + width: 100%; + background: #fff; + padding: 14px; + border-radius: 14px; +} + +.info-nofif-confirmmacao { + flex: 1; + text-align: left; +} + +/* ===== CANCELAMENTO DE SOLICITAÇÃO ===== */ + +.notif-cancelamento { + cursor: pointer; + background: var(--primary-orange-600); + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-cancelamento.active { + background: #f0c9a0; +} + +.notif-cancelamento-header { + display: flex; + align-items: center; + gap: 10px; + font-weight: 500; +} + +.notif-cancelamento-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-cancelamento-body { + margin-top: 12px; + border-radius: 12px; + font-size: 14px; + text-align: left; +} + +.notif-cancelamento-info { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + background: #F29863; + padding: 7px; + border-radius: 14px; + gap: 10px; +} +.notif-cancelamento-info svg { + width: 4rem; + height: 4rem; +} + +.notif-cancelamento-info p { + margin: 0; + text-align: start; + font-size: 13px; + font-weight: 400; +} + +.notif-link-termos { + display: inline-block; + margin-top: 10px; + color: #1a73e8; + font-size: 14px; + text-decoration: underline; +} + +/* ===== CANCELAMENTO DA AGENDA ===== */ + +.notif-cancelamento-agenda { + cursor: pointer; + background: var(--primary-orange-600); + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-cancelamento-agenda.active { + background: #f0c9a0; +} + +.notif-cancelamento-agenda-header { + display: flex; + align-items: center; + gap: 10px; + font-weight: 500; +} + +.notif-cancelamento-agenda-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-cancelamento-agenda-body { + margin-top: 12px; + border-radius: 12px; + font-size: 14px; + text-align: left; +} + +.notif-cancelamento-agenda-body .container-info-icon { + background: #fff; +} + +/* ===== REAGENDAMENTO REALIZADO ===== */ + +.notif-reagendamento { + background: #b8eda0; + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-reagendamento.active { + background: #d2edc5; +} + +.notif-reagendamento-header { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + font-weight: 500; +} + +.notif-reagendamento-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-reagendamento-body { + margin-top: 12px; + border-radius: 12px; + font-size: 14px; + text-align: left; + gap: 10px; +} + +.notif-reagendamento-body p { + margin: 5px 0; +} + +.notif-reagendamento-body .container-info-icon { + background: #fff; +} + +/* ===== SOLICITAÇÃO DE CONSULTA ===== */ + +.notif-solicitacao { + background: #b8eda0; + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-solicitacao.active { + background: #d2edc5; +} + +.notif-solicitacao-header { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + font-weight: 500; +} + +.notif-solicitacao-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-sub-text { + font-size: 13px; + font-weight: 400; + color: #555; +} + +.notif-solicitacao-body { + margin-top: 12px; + border-radius: 12px; + font-size: 14px; + text-align: left; + gap: 10px; +} + +.notif-solicitacao-body p { + margin: 5px 0; +} + +.notif-solicitacao-body .container-info-icon { + background: #fff; +} + +/* ===== RECUSA DE SOLICITAÇÃO ===== */ + +.notif-recusa { + cursor: pointer; + background: var(--primary-orange-600); + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-recusa.active { + background: #f0c9a0; +} + +.notif-recusa-header { + display: flex; + align-items: center; + gap: 10px; + font-weight: 500; +} + +.notif-recusa-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-recusa-body { + margin-top: 12px; + background: #fff; + padding: 14px; + border-radius: 14px; + font-size: 14px; + text-align: left; +} + +.notif-recusa-body p { + margin: 0; + text-align: start; +} + +/* ===== AGENDA DO DIA ===== */ + +.notif-agenda-do-dia { + cursor: pointer; + background: var(--tertiary-light-green-700); + padding: 14px; + border-radius: 14px; + margin-bottom: 12px; +} + +.notif-agenda-do-dia.active { + background: #c5e8b8; +} + +.notif-agenda-do-dia-header { + display: flex; + align-items: center; + gap: 10px; + font-weight: 500; +} + +.notif-agenda-do-dia-header p { + flex: 1; + margin: 0; + text-align: start; +} + +.notif-agenda-do-dia-body { + margin-top: 12px; + background: #e8f5e3; + padding: 14px; + border-radius: 14px; + font-size: 14px; + text-align: left; +} + +.notif-agenda-do-dia-body > p { + margin: 0 0 10px 0; + text-align: start; +} + +.notif-agenda-horarios { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; +} + +.notif-agenda-horario-item { + background: #d2edc5; + padding: 20px 14px; + border-radius: 20px; + font-size: 13px; + font-weight: 500; + color: #333; +} diff --git a/frontend/src/components/common/NavbarDesktop.jsx b/frontend/src/components/common/NavbarDesktop.jsx index 0a82916..93f469f 100644 --- a/frontend/src/components/common/NavbarDesktop.jsx +++ b/frontend/src/components/common/NavbarDesktop.jsx @@ -1,9 +1,10 @@ import { NavLink, useNavigate } from 'react-router-dom' import { Link } from 'react-router-dom' import { useState, useEffect, useRef } from 'react' -import { HiOutlineSearch, HiOutlineBell, HiChevronDown, HiChevronRight, HiOutlineX, HiOutlineUser } from "react-icons/hi"; +import { HiOutlineSearch, HiOutlineBell, HiOutlineUser } from "react-icons/hi"; import { useAuth } from '../../context/AuthContext'; import foto from '../../assets/img/perfil-default.png'; +import Notifications from './Notifications/notifications'; export default function NavDesktop() { @@ -34,7 +35,6 @@ export default function NavDesktop() { const [isNotifOpen, setNotifOpen] = useState(false); - const [openNotif, setOpenNotif] = useState(null); const notificacoes = [ { @@ -49,33 +49,56 @@ export default function NavDesktop() { id: 2, tipo: "confirmacao", nome: "Dra. Lucia Amaral", - data: "16/04/2026", + data: "06/04/2026", horario: "9:00h a.m", + status: "Confirmado", foto: "../../assets/img/perfil-default.png" }, { id: 3, - tipo: "mensagem", + tipo: "cancelamento", nome: "Daniel", - texto: "Esta ficando louco?", - hora: "19:29", - foto: foto + hora: "19:03", }, { id: 4, - tipo: "confirmacao", - nome: "Dra. Lucia Amaral", + tipo: "cancelamento-agenda", + nome: "Luigi", + data: "06 de Abril", + horario: "9:00", + hora: "19:03", + }, + { + id: 5, + tipo: "reagendamento", + nome: "Luigi", + dataAnterior: "06 de Abril", + dataNova: "10 de Abril", + data: "10/04/2026", + horario: "9:00h a.m", + status: "Pendente", + hora: "19:03", + }, + { + id: 6, + tipo: "solicitacao", + nome: "Luigi", data: "16/04/2026", horario: "9:00h a.m", - foto: "../../assets/img/perfil-default.png" + status: "Pendente", + hora: "19:03", }, { - id: 5, - tipo: "confirmacao", + id: 7, + tipo: "recusa", nome: "Dra. Lucia Amaral", - data: "16/04/2026", - horario: "19:00h p.m", - foto: "../../assets/img/perfil-default.png" + hora: "19:03", + }, + { + id: 8, + tipo: "agenda-do-dia", + hora: "19:03", + horarios: ["9:00", "10:30", "12:00", "16:30", "18:00", "19:30"], }, ]; return ( @@ -127,113 +150,7 @@ export default function NavDesktop() { {isNotifOpen && ( -
setNotifOpen(false)} - > - -
e.stopPropagation()} - > - - -

Notificações

- - {notificacoes.length === 0 && ( -

Sem notificações

- )} - - {notificacoes.map((notif) => { - - if (notif.tipo === "mensagem") { - - return ( - -
- - - -
- {notif.nome} -

{notif.texto}

-
- - - {notif.hora} - - -
- - ) - - } - - if (notif.tipo === "confirmacao") { - - return ( - -
- -
- setOpenNotif( - openNotif === notif.id - ? null - : notif.id - ) - } - > - - - -

- {notif.nome} confirmou seu agendamento -

- - - {openNotif === notif.id ? : } - - -
- - {openNotif === notif.id && ( -
-

- Nome: {notif.nome} -

-

- Data: {notif.data} -

-

- Horário: {notif.horario} -

- - - - -
- )} -
- ) - } - return null - })} -
-
+ )} )} diff --git a/frontend/src/components/common/Notifications/notifications.jsx b/frontend/src/components/common/Notifications/notifications.jsx new file mode 100644 index 0000000..feda087 --- /dev/null +++ b/frontend/src/components/common/Notifications/notifications.jsx @@ -0,0 +1,394 @@ +import React, { useState } from 'react'; +import '../../../assets/styles/notificacoes/notificacoes.css' +import { HiOutlineBell, HiChevronDown, HiOutlineStatusOffline, HiOutlineX, HiOutlineUser } from "react-icons/hi"; + +export default function Notifications({ setNotifOpen, notificacoes, user }) { + const [openNotif, setOpenNotif] = useState(null); + + const handleOpenProfile = () => { + if (user) { + window.location.href = `/${user.tipo.toLowerCase()}/perfil/${user.id}`; + } + }; + + return ( +
setNotifOpen(false)} + > +
e.stopPropagation()} + > + + +

Notificações

+ + {notificacoes.length === 0 && ( +

Sem notificações

+ )} + + {notificacoes.map((notif) => { + + {/* ===== MENSAGEM ===== */} + if (notif.tipo === "mensagem") { + return ( +
+ avatar +
+ {notif.nome} +

{notif.texto}

+
+ + {notif.hora} + +
+ ) + } + + {/* ===== CONFIRMAÇÃO ===== */} + if (notif.tipo === "confirmacao") { + const statusClass = notif.status ? notif.status.toLowerCase() : 'pendente'; + const statusText = notif.status ? notif.status : 'Pendente'; + + return ( +
+
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+ +
+ +

+ {notif.nome} confirmou seu agendamento +

+
+ + {openNotif === notif.id && ( +
+
+
+

+ Nome: {notif.nome} +

+

+ Data: {notif.data} +

+

+ Horário: {notif.horario} +

+
+ +
+
+
+ Status: {statusText} +
+
+
+ )} +
+ ) + } + + {/* ===== CANCELAMENTO DE SOLICITAÇÃO ===== */} + if (notif.tipo === "cancelamento") { + return ( +
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+
+ +
+

+ Cancelamento de solicitação pendente +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+
+ +

+ Agendamento cancelado automaticamente devido à + ausência de confirmação pelo psicólogo. +

+
+ Termos +
+ )} +
+ ) + } + + {/* ===== CANCELAMENTO DA AGENDA ===== */} + if (notif.tipo === "cancelamento-agenda") { + return ( +
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+
+ +
+

+ Cancelamento da agenda do dia {notif.data} ás {notif.horario} +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+
+
+

+ Nome: {notif.nome} +

+

+ Data: {notif.data} +

+

+ Horário: {notif.horario} +

+
+
+ Termos +
+ )} +
+ ) + } + + {/* ===== REAGENDAMENTO REALIZADO ===== */} + if (notif.tipo === "reagendamento") { + const statusClass = notif.status ? notif.status.toLowerCase() : 'pendente'; + const statusText = notif.status ? notif.status : 'Pendente'; + + return ( +
+
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+ +
+ +

+ Reagendamento realizado {notif.dataAnterior} → {notif.dataNova} +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+
+
+

+ Nome: {notif.nome} +

+

+ Data: {notif.dataNova} +

+

+ Horário: {notif.horario} +

+
+
+
+
+ Status: {statusText} +
+
+
+ )} +
+ ) + } + + {/* ===== SOLICITAÇÃO DE CONSULTA ===== */} + if (notif.tipo === "solicitacao") { + const statusClass = notif.status ? notif.status.toLowerCase() : 'pendente'; + const statusText = notif.status ? notif.status : 'Pendente'; + + return ( +
+
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+ +
+ +

+ Solicitação de consulta +
+ Status: {statusText}... +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+
+
+

+ Nome: {notif.nome} +

+

+ Data: {notif.data} +

+

+ Horário: {notif.horario} +

+
+
+
+
+ Status: {statusText} +
+
+
+ )} +
+ ) + } + + {/* ===== RECUSA DE SOLICITAÇÃO ===== */} + if (notif.tipo === "recusa") { + return ( +
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+
+ +
+

+ {notif.nome} recusou sua solicitação de agendamento +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+

+ Area de motivo de cancelamento em desenvolvimento +

+
+ )} +
+ ) + } + + {/* ===== AGENDA DO DIA ===== */} + if (notif.tipo === "agenda-do-dia") { + return ( +
+ setOpenNotif( + openNotif === notif.id ? null : notif.id + ) + } + > +
+
+ +
+

+ Agenda do dia +

+ + {notif.hora} + +
+ + {openNotif === notif.id && ( +
+

Sua agenda tem atendimentos marcados para hoje, acompanhe seus horários

+
+ {notif.horarios && notif.horarios.map((h, i) => ( + + {h} + + ))} +
+
+ )} +
+ ) + } + + return null; + })} +
+
+ ); +}