Skip to content

Commit 24381e8

Browse files
author
Andre Felipe de Barros Azevedo Nogueira
committed
feat: Create error message in angular.
1 parent b5d42bb commit 24381e8

File tree

10 files changed

+177
-20
lines changed

10 files changed

+177
-20
lines changed

securetimenotes-frontend/securetimenotes/src/app/components/home/home.component.css

+59-7
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,63 @@ p {
7272
border: 1px solid #ccc;
7373
}
7474

75+
.notes-container-plus {
76+
display: flex;
77+
flex-wrap: wrap;
78+
gap: 10px;
79+
justify-content: center;
80+
padding: 10px;
81+
}
82+
7583
/* Container que agrupa o cartão de criação e os cartões de nota */
84+
85+
.button-logout{
86+
background-color: transparent;
87+
display: flex;
88+
padding: 10px;
89+
margin: 10px 0;
90+
justify-content: flex-end;
91+
align-items: flex-end;
92+
}
93+
94+
.button-logout h1{
95+
cursor: pointer;
96+
width: 80px;
97+
height: 30px;
98+
border: none;
99+
border-radius: 5px;
100+
background-color: #007bff;
101+
color: white;
102+
font-size: 16px;
103+
padding-top: 10px;
104+
transition: background 0.3s;
105+
}
106+
107+
.button-logout h1:hover {
108+
background-color: #0056b3;
109+
}
110+
111+
.button-logout:hover{
112+
background-color: transparent;
113+
cursor: auto;
114+
}
115+
76116
.notes-container {
77117
display: flex;
78118
flex-wrap: wrap;
79119
gap: 10px;
80120
justify-content: flex-start;
81121
align-items: flex-start;
82122
padding: 10px;
123+
padding-left: 50px;
83124
}
84125

85126
/* Cartão de criação minimalista */
86127
.create-document {
87-
width: 100px;
88-
height: 120px;
128+
width: 60px;
129+
height: 60px;
89130
border: 1px solid #007bff; /* Borda azul */
90-
border-radius: 6px;
131+
border-radius: 100%;
91132
display: flex;
92133
align-items: center;
93134
justify-content: center;
@@ -107,11 +148,11 @@ p {
107148

108149
/* Cartão de nota com altura igual ao cartão de criação */
109150
.note-card {
110-
width: 100px;
151+
width: 130px;
111152
height: 100px; /* Altura igual ao create-document */
112153
padding: 10px;
113154
border: 1px solid #007bff; /* Borda azul */
114-
border-radius: 6px;
155+
border-radius: 15px;
115156
display: flex;
116157
flex-direction: column;
117158
align-items: center;
@@ -140,15 +181,26 @@ p {
140181

141182
/* Responsivo */
142183
@media (max-width: 600px) {
184+
185+
.button-logout {
186+
justify-content: center;
187+
align-items: center;
188+
background-color: transparent;
189+
}
190+
143191
.notes-container {
144192
justify-content: center;
145193
}
146194

147-
.note-card,
148-
.create-document {
195+
.note-card{
149196
width: 100%;
150197
}
151198

199+
.notes-container{
200+
padding-left: 10%;
201+
padding-right: 10%;
202+
}
203+
152204
.note-form textarea {
153205
height: 200px;
154206
}

securetimenotes-frontend/securetimenotes/src/app/components/home/home.component.html

+16-12
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ <h2 *ngIf="!showTitlePrompt && !showNoteEditor">SecureTime</h2>
1010
<ng-template #loggedInTemplate>
1111
<!-- Header e Logout (apenas quando não estiver criando/editando) -->
1212
<div *ngIf="!showTitlePrompt && !showNoteEditor" class="header-info">
13-
<button (click)="logout()">Logout</button>
13+
<button class="button-logout" (click)="logout()"><h1>Logout</h1></button>
1414
</div>
1515

1616
<!-- Modal para o título da nota -->
1717
<div class="modal" *ngIf="showTitlePrompt">
1818
<h3>Digite o título da nota</h3>
1919
<input type="text" [(ngModel)]="newNoteTitle" placeholder="Título da nota" />
2020
<button (click)="confirmTitle()">Continuar</button>
21+
<button (click)="cancelEdit()">Cancelar</button>
2122
</div>
2223

2324
<!-- Editor da nota -->
@@ -30,19 +31,22 @@ <h3>{{ editingNote ? 'Editando' : 'Criando' }}: {{ newNoteTitle }}</h3>
3031
<button (click)="cancelEdit()">Cancelar</button>
3132
</div>
3233

33-
<!-- Container com o cartão de criação e os cartões de nota -->
34-
<div class="notes-container" *ngIf="!showTitlePrompt && !showNoteEditor">
35-
<!-- Cartão de criação minimalista (só o "+") -->
36-
<div class="create-document" (click)="openNoteTitlePrompt()">
37-
<span class="plus-symbol">+</span>
34+
<div class="notes-container-plus" *ngIf="!showTitlePrompt && !showNoteEditor">
35+
<!-- Cartão de criação minimalista (só o "+") -->
36+
<div class="create-document" (click)="openNoteTitlePrompt()">
37+
<span class="plus-symbol">+</span>
38+
</div>
3839
</div>
3940

40-
<!-- Cartões de nota existentes -->
41-
<div class="note-card" *ngFor="let note of notes" (click)="editNote(note)">
42-
<div class="note-icon">📄</div>
43-
<!-- Limita o título aos primeiros 15 caracteres -->
44-
<div class="note-title">{{ note.title | slice:0:9 }}</div>
45-
</div>
41+
<!-- Container com o cartão de criação e os cartões de nota -->
42+
<div class="notes-container" *ngIf="!showTitlePrompt && !showNoteEditor">
43+
<!-- Cartões de nota existentes -->
44+
<div class="note-card" *ngFor="let note of notes" (click)="editNote(note)">
45+
<div class="note-icon">📝</div>
46+
<!-- Limita o título aos primeiros 15 caracteres -->
47+
<div class="note-title">{{ note.title | slice:0:13 }}</div>
48+
</div>
4649
</div>
50+
4751
</ng-template>
4852
</div>

securetimenotes-frontend/securetimenotes/src/app/components/login/login.component.css

+8-1
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,11 @@ h2 {
6969
color: red;
7070
font-size: 0.8em;
7171
margin-top: 5px;
72-
}
72+
}
73+
74+
.error-message {
75+
color: #ff4d4d;
76+
font-weight: bold;
77+
margin-top: 10px;
78+
}
79+

securetimenotes-frontend/securetimenotes/src/app/components/login/login.component.html

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
33
<div>
44
<h2>LOGIN</h2>
5+
<div *ngIf="loginError" class="error-message">
6+
{{ loginError }}
7+
</div>
58
<label for="login">Login (E-mail)</label>
69
<input id="login" formControlName="login" type="email" />
710
<div *ngIf="loginForm.get('login')?.invalid && loginForm.get('login')?.touched">

securetimenotes-frontend/securetimenotes/src/app/components/login/login.component.ts

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Router } from '@angular/router';
1414
})
1515
export class LoginComponent {
1616
loginForm: FormGroup;
17+
loginError: string | null = null;
1718

1819
constructor(private fb: FormBuilder, private apiService: AuthService, private router: Router) {
1920
this.loginForm = this.fb.group({
@@ -34,11 +35,13 @@ export class LoginComponent {
3435
this.apiService.post('auth/login', requestPayload).subscribe({
3536
next: (response: any) => {
3637
console.log('Login bem-sucedido', response);
38+
this.loginError = null;
3739
localStorage.setItem('token', response.token); // Armazena o token no localStorage
3840
this.router.navigate(['/home']);
3941
},
4042
error: (error) => {
4143
console.error('Erro ao fazer login', error);
44+
this.loginError = 'Usuário ou senha inválidos';
4245
}
4346
});
4447
} else {

securetimenotes-frontend/securetimenotes/src/app/components/register/register.component.css

+6
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,9 @@ h2 {
161161
color: #fff;
162162
}
163163

164+
.error-message {
165+
color: #ff4d4d;
166+
font-weight: bold;
167+
margin-top: 10px;
168+
}
169+

securetimenotes-frontend/securetimenotes/src/app/components/register/register.component.html

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
33
<div>
44
<h2>REGISTER</h2>
5+
<div *ngIf="registrationError" class="error-message">
6+
{{ registrationError }}
7+
</div>
58
<label for="login">E-mail</label>
69
<input id="login" formControlName="login" type="email" />
710
<div *ngIf="registerForm.get('login')?.invalid && registerForm.get('login')?.touched">

securetimenotes-frontend/securetimenotes/src/app/components/register/register.component.ts

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class RegisterComponent {
1717
registerForm: FormGroup;
1818
passwordStrength: string = ''; // Armazenar o estado da força da senha
1919
passwordStrengthPercentage: number = 0; // Armazenar a porcentagem da força da senha
20+
registrationError: string | null = null;
2021

2122
// Armazenar o status dos requisitos de senha
2223
passwordRequirements = {
@@ -90,10 +91,12 @@ export class RegisterComponent {
9091
this.apiService.post('auth/register', requestPayload, 'text').subscribe({
9192
next: (response) => {
9293
console.log('Usuário registrado com sucesso', response);
94+
this.registrationError = null;
9395
this.router.navigate(['/login']);
9496
},
9597
error: (error) => {
9698
console.error('Erro ao registrar usuário', error);
99+
this.registrationError = 'Erro ao registrar. Tente novamente.';
97100
}
98101
});
99102
} else if (!this.validatePassword()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { NoteService } from './note.service';
4+
5+
describe('NoteService', () => {
6+
let service: NoteService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(NoteService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
2+
import { Injectable } from '@angular/core';
3+
import { Observable, throwError } from 'rxjs';
4+
import { catchError } from 'rxjs/operators';
5+
6+
@Injectable({
7+
providedIn: 'root'
8+
})
9+
export class NoteService {
10+
11+
private apiUrl = 'https://securetimenotes.up.railway.app/';
12+
13+
constructor(private http: HttpClient) {}
14+
15+
private getHeaders(): HttpHeaders {
16+
const token = localStorage.getItem('token'); // ou pegue de outro lugar, se preferir
17+
return new HttpHeaders({
18+
'Authorization': `Bearer ${token}`,
19+
'Content-Type': 'application/json'
20+
});
21+
}
22+
23+
getNotes(): Observable<any> {
24+
return this.http.get<any>(`${this.apiUrl}user/notes`, { headers: this.getHeaders() })
25+
.pipe(
26+
catchError(this.handleError)
27+
);
28+
}
29+
30+
createNote(note: any): Observable<any> {
31+
return this.http.post<any>(`${this.apiUrl}user/notes`, note, { headers: this.getHeaders() })
32+
.pipe(
33+
catchError(this.handleError)
34+
);
35+
}
36+
37+
updateNote(id: string, note: any): Observable<any> {
38+
return this.http.put<any>(`${this.apiUrl}user/notes/${id}`, note, { headers: this.getHeaders() })
39+
.pipe(
40+
catchError(this.handleError)
41+
);
42+
}
43+
44+
deleteNote(id: string): Observable<any> {
45+
return this.http.delete<any>(`${this.apiUrl}user/notes/${id}`, { headers: this.getHeaders() })
46+
.pipe(
47+
catchError(this.handleError)
48+
);
49+
}
50+
51+
private handleError(error: HttpErrorResponse) {
52+
let errorMessage = 'Erro desconhecido!';
53+
if (error.error instanceof ErrorEvent) {
54+
errorMessage = `Erro: ${error.error.message}`;
55+
} else {
56+
errorMessage = `Erro do servidor: ${error.status} - ${error.message}`;
57+
}
58+
return throwError(() => new Error(errorMessage));
59+
}
60+
}

0 commit comments

Comments
 (0)