diff --git a/backend/videoflix/auth/views.py b/backend/videoflix/auth/views.py index c112b1b..f8f531a 100644 --- a/backend/videoflix/auth/views.py +++ b/backend/videoflix/auth/views.py @@ -25,9 +25,9 @@ class LoginView(APIView): if user: if not user.is_active: - return Response({'password': 'Account is inactive, please check your mails'}, status=status.HTTP_403_FORBIDDEN) + return Response({'error': 'Account is inactive, please check your mails'}, status=status.HTTP_403_FORBIDDEN) return self._create_token_response(user) - return Response({'mail': 'Unable to login with provided credentials.'}, status=status.HTTP_401_UNAUTHORIZED) + return Response({'error': 'Unable to login with provided credentials.'}, status=status.HTTP_401_UNAUTHORIZED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -40,7 +40,7 @@ class RegisterView(APIView): email = request.data.get('email') password = request.data.get('password') if CustomUser.objects.filter(email=email).exists(): - return Response({'mail': 'A user with this email already exists.'}, status=status.HTTP_400_BAD_REQUEST) + return Response({'error': 'A user with this email already exists.'}, status=status.HTTP_400_BAD_REQUEST) serialized = UserSerializer(data=request.data) if serialized.is_valid(): @@ -93,7 +93,7 @@ class ForgotPasswordView(APIView): def post(self, request): email = request.data.get('email') if not email: - return Response({"mail": "Email required."}, status=status.HTTP_400_BAD_REQUEST) + return Response({"error": "Email required."}, status=status.HTTP_400_BAD_REQUEST) try: user = CustomUser.objects.get(email=email) @@ -101,7 +101,7 @@ class ForgotPasswordView(APIView): user.save() self.send_email(user) except CustomUser.DoesNotExist: - return Response({"mail": "This email does not exist."}, status=status.HTTP_400_BAD_REQUEST) + return Response({"error": "This email does not exist."}, status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_200_OK) def send_email(self, user): @@ -149,5 +149,5 @@ class AuthView(ObtainAuthToken): def post(self, request): email = request.data.get('email') if CustomUser.objects.filter(email=email).exists(): - return Response({'mail': 'A user with this email already exists.'}, status=status.HTTP_400_BAD_REQUEST) + return Response({'error': 'A user with this email already exists.'}, status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_200_OK) \ No newline at end of file diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 3c7c33b..67e7bd4 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,2 +1 @@ - - + diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 8cb1fac..4b631b0 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -5,7 +5,7 @@ import { ErrorToastComponent } from './shared/components/error-toast/error-toast @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet, ErrorToastComponent], + imports: [RouterOutlet], templateUrl: './app.component.html', styleUrl: './app.component.scss', }) diff --git a/frontend/src/app/components/auth/auth.component.html b/frontend/src/app/components/auth/auth.component.html index 5a77ea9..741d4ff 100644 --- a/frontend/src/app/components/auth/auth.component.html +++ b/frontend/src/app/components/auth/auth.component.html @@ -33,11 +33,11 @@ !isUserEmailValid(authData.mail.toLowerCase())) {

This is not a valid email format

}} -
+
This is not a valid email format

}} -
+
The passwords do not match

} -
+
This is not a valid email format

}} -
+
Password is too short, min 6 characters

} } -
+
-
+
diff --git a/frontend/src/app/components/auth/verify-email/verify-email.component.ts b/frontend/src/app/components/auth/verify-email/verify-email.component.ts index 460edcc..6ce68ad 100644 --- a/frontend/src/app/components/auth/verify-email/verify-email.component.ts +++ b/frontend/src/app/components/auth/verify-email/verify-email.component.ts @@ -45,20 +45,9 @@ export class VerifyEmailComponent { this.errorService.clearError(); } catch (error) { this.verified = false; - this.errorMsg(error); - } - } - - errorMsg(error: any) { - if (error instanceof HttpErrorResponse) { - const errorTypes = ['error']; - for (const type of errorTypes) { - if (error.error[type]) { - this.errorService.setError(type, error.error[type]); - return; - } - } - this.errorService.clearError(); + const errorMessage = + error instanceof Error ? error.message : 'An unknown error occurred'; + this.errorService.errorMsg(errorMessage); } } } diff --git a/frontend/src/app/components/home/home.component.html b/frontend/src/app/components/home/home.component.html index fc24b03..22e6d11 100644 --- a/frontend/src/app/components/home/home.component.html +++ b/frontend/src/app/components/home/home.component.html @@ -8,4 +8,5 @@ > + diff --git a/frontend/src/app/components/home/home.component.scss b/frontend/src/app/components/home/home.component.scss index 962e72e..7697209 100644 --- a/frontend/src/app/components/home/home.component.scss +++ b/frontend/src/app/components/home/home.component.scss @@ -2,11 +2,3 @@ section { width: 100vw; height: 100vh; } - -// .bg-home { -// background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)), -// url(./../../../assets/img/backgrounds/home.png); -// background-size: cover; -// background-position: center; -// background-repeat: no-repeat; -// } diff --git a/frontend/src/app/components/home/home.component.ts b/frontend/src/app/components/home/home.component.ts index 1921979..e187254 100644 --- a/frontend/src/app/components/home/home.component.ts +++ b/frontend/src/app/components/home/home.component.ts @@ -9,6 +9,8 @@ import { LoginComponent } from '../auth/login/login.component'; import { ForgotPasswordComponent } from '../auth/forgot-password/forgot-password.component'; import { BrowseComponent } from './browse/browse.component'; import { VerifyEmailComponent } from '../auth/verify-email/verify-email.component'; +import { ErrorToastComponent } from '../../shared/components/error-toast/error-toast.component'; +import { ErrorService } from '../../services/error.service'; @Component({ selector: 'app-home', @@ -23,14 +25,19 @@ import { VerifyEmailComponent } from '../auth/verify-email/verify-email.componen ForgotPasswordComponent, VerifyEmailComponent, BrowseComponent, + ErrorToastComponent, ], templateUrl: './home.component.html', styleUrl: './home.component.scss', }) export class HomeComponent implements OnInit { currentRoute: any; + displayErrorToast: boolean = false; - constructor(private route: ActivatedRoute) {} + constructor( + private route: ActivatedRoute, + public errorService: ErrorService + ) {} ngOnInit(): void { this.route.url.subscribe((url) => { diff --git a/frontend/src/app/services/error.service.ts b/frontend/src/app/services/error.service.ts index b4d8b7a..8e4038f 100644 --- a/frontend/src/app/services/error.service.ts +++ b/frontend/src/app/services/error.service.ts @@ -1,49 +1,31 @@ -import { HttpErrorResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -export interface ErrorDetail { - type: string; - message: string; -} +import { BehaviorSubject } from 'rxjs'; +import { HttpErrorResponse } from '@angular/common/http'; @Injectable({ providedIn: 'root', }) export class ErrorService { - private errorSubject = new BehaviorSubject(null); + private errorSubject = new BehaviorSubject(''); + errorText$ = this.errorSubject.asObservable(); + displayError = false; - error$: Observable<{ [key: string]: string } | null> = this.errorSubject - .asObservable() - .pipe( - map((errorDetail) => { - if (errorDetail) { - return { [errorDetail.type]: errorDetail.message }; - } - return null; - }) - ); - - setError(type: string, message: string) { - const errorDetail: ErrorDetail = { type, message }; - this.errorSubject.next(errorDetail); + errorMsg(message: string) { + this.errorSubject.next(message); + this.displayError = true; } clearError() { - this.errorSubject.next(null); + this.errorSubject.next(''); + this.displayError = false; } - errorMsg(error: any) { + handleError(error: unknown) { if (error instanceof HttpErrorResponse) { - const errorTypes = ['mail', 'password', 'error']; - for (const type of errorTypes) { - if (error.error[type]) { - this.setError(type, error.error[type]); - return; - } - } - this.clearError(); + const errorMessage = error.error.error || 'An unknown error occurred'; + this.errorMsg(errorMessage); + } else { + this.errorMsg('An unexpected error occurred'); } } } diff --git a/frontend/src/app/shared/components/error-toast/error-toast.component.html b/frontend/src/app/shared/components/error-toast/error-toast.component.html index a8fe40f..29e65c4 100644 --- a/frontend/src/app/shared/components/error-toast/error-toast.component.html +++ b/frontend/src/app/shared/components/error-toast/error-toast.component.html @@ -1,20 +1,21 @@ -
-
-
- -

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Provident aliquam - ex earum esse, totam placeat omnis sequi sint eveniet maiores explicabo - necessitatibus, est voluptatibus aperiam velit alias quae! Dicta aliquam - aspernatur libero maiores tenetur aut ratione et esse nesciunt nostrum, - cupiditate recusandae perferendis? Sapiente reprehenderit nemo repellendus - libero adipisci explicabo! -

-
-
-
-
- +
+
+
+
+ +

+ {{ errorText }} +

-
-
+
+
+
+ +
+
+ + diff --git a/frontend/src/app/shared/components/error-toast/error-toast.component.scss b/frontend/src/app/shared/components/error-toast/error-toast.component.scss index 201880a..556cb94 100644 --- a/frontend/src/app/shared/components/error-toast/error-toast.component.scss +++ b/frontend/src/app/shared/components/error-toast/error-toast.component.scss @@ -8,6 +8,16 @@ section { border-radius: 20px; background-color: $purple; box-shadow: 1px 1px 3px rgba($black, 0.5); + opacity: 0; + transform: translateY(100vh); + animation: slide-in-bottom 500ms forwards; +} + +@keyframes slide-in-bottom { + to { + opacity: 1; + transform: translateY(0); + } } .left { @@ -26,6 +36,7 @@ section { display: flex; align-items: center; width: 82%; + min-height: 48px; margin-left: 24px; p { font-size: 18px; @@ -64,3 +75,19 @@ section { } } } + +.overlay { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100vw; + height: 100vh; + backdrop-filter: blur(5px); + background-color: rgba($color: #000000, $alpha: 0.2); + display: flex; + justify-content: center; + align-items: center; + z-index: 999; +} diff --git a/frontend/src/app/shared/components/error-toast/error-toast.component.ts b/frontend/src/app/shared/components/error-toast/error-toast.component.ts index e3b2283..0536bf2 100644 --- a/frontend/src/app/shared/components/error-toast/error-toast.component.ts +++ b/frontend/src/app/shared/components/error-toast/error-toast.component.ts @@ -1,4 +1,5 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; +import { ErrorService } from '../../../services/error.service'; @Component({ selector: 'app-error-toast', @@ -7,6 +8,18 @@ import { Component, Input } from '@angular/core'; templateUrl: './error-toast.component.html', styleUrl: './error-toast.component.scss', }) -export class ErrorToastComponent { - @Input() errorText: string = ''; +export class ErrorToastComponent implements OnInit { + errorText: string = ''; + + constructor(private errorService: ErrorService) {} + + ngOnInit(): void { + this.errorService.errorText$.subscribe((message: string) => { + this.errorText = message; + }); + } + + closeError() { + this.errorService.clearError(); + } }