Skip to content

Commit d24a15d

Browse files
authored
Merge pull request #40 from ICEI-PUC-Minas-PMV-ADS/notificacoes-final
Notificacoes final
2 parents 4a814a1 + a51ece0 commit d24a15d

10 files changed

Lines changed: 596 additions & 13 deletions

File tree

src/backend/Notificacoes.API/Controllers/NotificacoesController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using Microsoft.AspNetCore.Authorization;
55

66
namespace Notificacoes.API.Controllers;
7-
[Authorize]
7+
//[Authorize]
88
[ApiController]
99
[Route("api/[controller]")]
1010
public class NotificacoesController : ControllerBase

src/backend/Notificacoes.API/Notificacoes.API.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
1515
</ItemGroup>
1616

17+
1718
</Project>

src/frontend/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"@tailwindcss/vite": "^4.2.4",
14+
"axios": "^1.16.0",
1315
"react": "^19.2.5",
1416
"react-dom": "^19.2.5",
15-
"react-router-dom": "^7.14.2"
17+
"react-router-dom": "^7.14.2",
18+
"tailwindcss": "^4.2.4"
1619
},
1720
"devDependencies": {
1821
"@eslint/js": "^9.0.0",

src/frontend/src/App.jsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import ResetPassword from "./pages/ResetPassword";
99
import { isAuthenticated } from "./services/authService";
1010
import Dashboard from "./pages/Dashboard";
1111
import Emprestimos from "./pages/Emprestimos";
12+
import Configuracoes from "./pages/Configuracoes";
13+
import Notificacoes from "./pages/Notificacoes";
1214

1315
export default function App() {
1416
const location = useLocation();
@@ -54,7 +56,18 @@ export default function App() {
5456
<Route
5557
path="/emprestimos"
5658
element={authenticated ? <Emprestimos /> : <Navigate to="/login" replace />}
57-
/>
59+
/>
60+
61+
<Route
62+
path="/configuracoes"
63+
element={authenticated ? <Configuracoes /> : <Navigate to="/login" replace />}
64+
/>
65+
66+
<Route
67+
path="/notificacoes"
68+
element={authenticated ? <Notificacoes /> : <Navigate to="/login" replace />}
69+
/>
70+
5871
</Routes>
5972
</div>
6073
</div>

src/frontend/src/components/Sidebar.jsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const navItems = [
77
{ icon: "💳", label: "Empréstimos", path: "/emprestimos" },
88
{ icon: "📈", label: "Relatórios", path: "/relatorios" },
99
{ icon: "⚙️", label: "Configurações", path: "/configuracoes" },
10+
1011
];
1112

1213
export default function Sidebar() {
@@ -25,13 +26,15 @@ export default function Sidebar() {
2526
navigate("/login");
2627
}
2728

28-
return (
29-
<aside style={styles.sidebar}>
30-
{/* Logo */}
31-
<div style={styles.logoWrapper}>
32-
<div style={styles.logoIcon}>💰</div>
33-
<span style={styles.logoText}>Paga Aí</span>
34-
</div>
29+
30+
31+
return (
32+
<aside style={styles.sidebar}>
33+
{/* Logo */}
34+
<div style={styles.logoWrapper}>
35+
<div style={styles.logoIcon}>💰</div>
36+
<span style={styles.logoText}>Paga Aí</span>
37+
</div>
3538

3639
{/* Nav */}
3740
<nav style={styles.nav}>
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import { useState } from "react";
2+
import { getUsuarioLogado } from "../services/authService";
3+
import { useNavigate } from "react-router-dom";
4+
5+
6+
export default function Configuracoes() {
7+
const usuario = getUsuarioLogado();
8+
const navigate = useNavigate();
9+
10+
const [notif, setNotif] = useState({
11+
emailVencimento: true,
12+
emailPagamento: true,
13+
pushNovos: false,
14+
});
15+
16+
const [sistema, setSistema] = useState({
17+
diasAviso: 5,
18+
taxaPadrao: 30,
19+
moeda: "BRL",
20+
});
21+
22+
const [salvo, setSalvo] = useState(false);
23+
24+
function salvar() {
25+
setSalvo(true);
26+
setTimeout(() => setSalvo(false), 2500);
27+
}
28+
29+
return (
30+
<div style={s.page}>
31+
<div style={s.header}>
32+
<h1 style={s.titulo}>Configurações</h1>
33+
<p style={s.sub}>Ajustes do sistema e preferências</p>
34+
</div>
35+
36+
{/* Perfil resumido */}
37+
<section style={s.card}>
38+
<h2 style={s.cardTitulo}>👤 Conta</h2>
39+
<div style={s.perfilRow}>
40+
<div style={s.avatar}>{usuario?.nome?.split(" ").map(n => n[0]).join("").slice(0,2).toUpperCase() ?? "??"}</div>
41+
<div>
42+
<p style={s.perfilNome}>{usuario?.nome ?? "—"}</p>
43+
<p style={s.perfilEmail}>{usuario?.email ?? "—"}</p>
44+
</div>
45+
</div>
46+
</section>
47+
48+
{/* Notificações */}
49+
<section style={s.card}>
50+
<h2 style={s.cardTitulo}>🔔 Notificações</h2>
51+
{[
52+
{ key: "emailVencimento", label: "E-mail ao vencer empréstimo" },
53+
{ key: "emailPagamento", label: "E-mail ao receber pagamento" },
54+
{ key: "pushNovos", label: "Alertas de novos empréstimos" },
55+
].map(({ key, label }) => (
56+
<div key={key} style={s.toggleRow}>
57+
<span style={s.toggleLabel}>{label}</span>
58+
<button
59+
style={{ ...s.toggle, background: notif[key] ? "#7C3AED" : "#D1D5DB" }}
60+
onClick={() => setNotif(p => ({ ...p, [key]: !p[key] }))}
61+
>
62+
<span style={{ ...s.toggleDot, transform: notif[key] ? "translateX(20px)" : "translateX(2px)" }} />
63+
</button>
64+
</div>
65+
))}
66+
</section>
67+
68+
{/* Sistema */}
69+
<section style={s.card}>
70+
<h2 style={s.cardTitulo}>⚙️ Sistema</h2>
71+
72+
<div style={s.fieldRow}>
73+
<label style={s.label}>Dias de aviso antes do vencimento</label>
74+
<input
75+
type="number" min={1} max={30}
76+
value={sistema.diasAviso}
77+
onChange={e => setSistema(p => ({ ...p, diasAviso: e.target.value }))}
78+
style={s.input}
79+
/>
80+
</div>
81+
82+
<div style={s.fieldRow}>
83+
<label style={s.label}>Taxa de juros padrão (%/mês)</label>
84+
<input
85+
type="number" min={1} max={100}
86+
value={sistema.taxaPadrao}
87+
onChange={e => setSistema(p => ({ ...p, taxaPadrao: e.target.value }))}
88+
style={s.input}
89+
/>
90+
</div>
91+
</section>
92+
93+
<div style={s.rodape}>
94+
<button style={s.btnSalvar} onClick={salvar}>
95+
{salvo ? "✔ Salvo!" : "Salvar configurações"}
96+
</button>
97+
</div>
98+
</div>
99+
);
100+
}
101+
102+
const s = {
103+
page: {
104+
padding: "2rem",
105+
background: "#F5F3FF",
106+
minHeight: "100vh"
107+
},
108+
header: {
109+
marginBottom: "1.5rem"
110+
},
111+
titulo: {
112+
margin: 0,
113+
fontSize: "1.8rem",
114+
fontWeight: 700,
115+
color: "#1F2937"
116+
},
117+
sub: {
118+
margin: "0.25rem 0 0",
119+
color: "#6B7280",
120+
fontSize: "0.9rem"
121+
},
122+
card: {
123+
background: "#fff",
124+
borderRadius: 12,
125+
padding: "1.5rem",
126+
marginBottom: "1rem",
127+
boxShadow: "0 1px 4px rgba(0,0,0,0.06)"
128+
},
129+
cardTitulo: {
130+
margin: "0 0 1.25rem",
131+
fontSize: "1rem",
132+
fontWeight: 700,
133+
color: "#1F2937"
134+
},
135+
perfilRow: {
136+
display: "flex",
137+
alignItems: "center",
138+
gap: "1rem"
139+
},
140+
avatar: {
141+
width: 52,
142+
height: 52,
143+
borderRadius: "50%",
144+
background: "linear-gradient(143deg,#7C3AED,#6D28D9)",
145+
display: "flex",
146+
alignItems: "center",
147+
justifyContent: "center",
148+
color: "#fff",
149+
fontWeight: 700,
150+
fontSize: "1.1rem",
151+
flexShrink: 0
152+
},
153+
perfilNome: {
154+
margin: 0,
155+
fontWeight: 700,
156+
fontSize: "1rem",
157+
color: "#1F2937"
158+
},
159+
perfilEmail: {
160+
margin: "2px 0 0",
161+
fontSize: "0.85rem",
162+
color: "#6B7280"
163+
},
164+
toggleRow: {
165+
display: "flex",
166+
justifyContent: "space-between",
167+
alignItems: "center",
168+
padding: "0.6rem 0",
169+
borderBottom: "1px solid #F3F4F6"
170+
},
171+
toggleLabel: {
172+
fontSize: "0.9rem",
173+
color: "#374151"
174+
},
175+
toggle: {
176+
width: 44,
177+
height: 24,
178+
borderRadius: 12,
179+
border: "none",
180+
cursor: "pointer",
181+
position: "relative",
182+
transition: "background 0.2s",
183+
flexShrink: 0
184+
},
185+
toggleDot: {
186+
position: "absolute",
187+
top: 3,
188+
width: 18,
189+
height: 18,
190+
background: "#fff",
191+
borderRadius: "50%",
192+
transition: "transform 0.2s"
193+
},
194+
fieldRow: {
195+
marginBottom: "1rem"
196+
},
197+
label: {
198+
display: "block",
199+
fontSize: "0.85rem",
200+
fontWeight: 600,
201+
color: "#374151",
202+
marginBottom: 6
203+
},
204+
input: {
205+
width: "100%",
206+
padding: "0.5rem 0.75rem",
207+
borderRadius: 8,
208+
border: "1px solid #D1D5DB",
209+
fontSize: "0.95rem",
210+
boxSizing: "border-box"
211+
},
212+
rodape: {
213+
display: "flex",
214+
justifyContent: "flex-end"
215+
},
216+
btnSalvar: {
217+
background: "#7C3AED",
218+
color: "#fff",
219+
border: "none",
220+
borderRadius: 8,
221+
padding: "0.65rem 1.5rem",
222+
cursor: "pointer",
223+
fontWeight: 600,
224+
fontSize: "0.95rem"
225+
},
226+
};

src/frontend/src/pages/Dashboard.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const acoes = [
1212
{ icon: "💳", label: "Empréstimos", path: "/emprestimos", desc: "Controle de empréstimos", cor: "#2563EB" },
1313
{ icon: "📈", label: "Relatórios", path: "/relatorios", desc: "Visualizar relatórios", cor: "#16A34A" },
1414
{ icon: "⚙️", label: "Configurações", path: "/configuracoes", desc: "Ajustes do sistema", cor: "#F59E0B" },
15+
{ icon: "🔔", label: "Notificações", path: "/notificacoes", desc: "Notificacoes", cor: "#F59E0B" },
1516
];
1617

1718
function calcularStatus(e) {

0 commit comments

Comments
 (0)