Merge pull request #1 from girik21/feat/nebular-firebase

Feat/nebular firebase
This commit is contained in:
girik21 2024-03-20 14:52:06 -07:00 committed by GitHub
commit 51759d8456
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 2523 additions and 1110 deletions

2762
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -42,8 +42,9 @@
"@angular/platform-browser-dynamic": "^15.2.10", "@angular/platform-browser-dynamic": "^15.2.10",
"@angular/router": "^15.2.10", "@angular/router": "^15.2.10",
"@asymmetrik/ngx-leaflet": "3.0.1", "@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "11.0.1", "@nebular/auth": "^11.0.1",
"@nebular/eva-icons": "11.0.1", "@nebular/eva-icons": "11.0.1",
"@nebular/firebase-auth": "^13.0.0",
"@nebular/security": "11.0.1", "@nebular/security": "11.0.1",
"@nebular/theme": "11.0.1", "@nebular/theme": "11.0.1",
"@swimlane/ngx-charts": "^14.0.0", "@swimlane/ngx-charts": "^14.0.0",

View file

@ -1,53 +1,18 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ExtraOptions, RouterModule, Routes } from '@angular/router'; import { ExtraOptions, RouterModule, Routes } from '@angular/router';
import { import { AuthGuard } from './service/auth-guard.service';
NbAuthComponent,
NbLoginComponent,
NbLogoutComponent,
NbRegisterComponent,
NbRequestPasswordComponent,
NbResetPasswordComponent,
} from '@nebular/auth';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: 'pages', path: 'pages',
canActivate: [AuthGuard],
loadChildren: () => import('./pages/pages.module') loadChildren: () => import('./pages/pages.module')
.then(m => m.PagesModule), .then(m => m.PagesModule),
}, },
{ {
path: 'auth', path: 'auth',
component: NbAuthComponent, loadChildren: () => import('./auth/auth.module').then(m => m.NgxAuthModule)
children: [
{
path: '',
redirectTo: 'login', // Redirect to login by default
pathMatch: 'full',
},
{
path: 'login',
component: NbLoginComponent,
},
{
path: 'register',
component: NbRegisterComponent,
},
{
path: 'logout',
component: NbLogoutComponent,
},
{
path: 'request-password',
component: NbRequestPasswordComponent,
},
{
path: 'reset-password',
component: NbResetPasswordComponent,
},
],
}, },
{ path: '', redirectTo: 'auth', pathMatch: 'full' },
{ path: '**', redirectTo: 'pages' }, { path: '**', redirectTo: 'pages' },
]; ];

View file

@ -1,8 +1,3 @@
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { AngularFireModule } from '@angular/fire/compat'; import { AngularFireModule } from '@angular/fire/compat';
@ -22,6 +17,9 @@ import { CoreModule } from './@core/core.module';
import { ThemeModule } from './@theme/theme.module'; import { ThemeModule } from './@theme/theme.module';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AuthGuard } from './service/auth-guard.service';
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent],
@ -31,6 +29,7 @@ import { AppComponent } from './app.component';
HttpClientModule, HttpClientModule,
AppRoutingModule, AppRoutingModule,
AngularFireModule.initializeApp(environment.firebase), AngularFireModule.initializeApp(environment.firebase),
AngularFireAuthModule,
NbSidebarModule.forRoot(), NbSidebarModule.forRoot(),
NbMenuModule.forRoot(), NbMenuModule.forRoot(),
NbDatepickerModule.forRoot(), NbDatepickerModule.forRoot(),
@ -43,6 +42,9 @@ import { AppComponent } from './app.component';
CoreModule.forRoot(), CoreModule.forRoot(),
ThemeModule.forRoot(), ThemeModule.forRoot(),
], ],
providers: [
AuthGuard
],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })
export class AppModule { export class AppModule {

View file

@ -0,0 +1,72 @@
import { NbAuthStrategyOptions, NbAuthJWTToken, NbPasswordStrategyModule, NbPasswordStrategyMessage } from "@nebular/auth";
export class NbFirebasePasswordStrategyOptions extends NbAuthStrategyOptions {
name: string = 'email';
token = {
class: NbAuthJWTToken,
};
register?: boolean | NbPasswordStrategyModule = {
redirect: {
success: '/auth/login',
failure: null,
},
defaultErrors: ['Something went wrong, please try again.'],
defaultMessages: ['You have been successfully registered.'],
};
login?: boolean | NbPasswordStrategyModule = {
redirect: {
success: '/dashboard',
failure: null,
},
defaultErrors: ['Login/Email combination is not correct, please try again.'],
defaultMessages: ['You have been successfully logged in.'],
};
logout?: boolean | NbPasswordStrategyModule = {
redirect: {
success: '/',
failure: null,
},
defaultErrors: ['Something went wrong, please try again.'],
defaultMessages: ['You have been successfully logged out.'],
};
refreshToken?: boolean | NbPasswordStrategyModule = {
redirect: {
success: null,
failure: null,
},
defaultErrors: ['Something went wrong, please try again.'],
defaultMessages: ['Your token has been successfully refreshed.'],
};
// requestPassword?: boolean | NbPasswordStrategyModule = {
// redirect: {
// success: '/',
// failure: null,
// },
// defaultErrors: ['Something went wrong, please try again.'],
// defaultMessages: ['Reset password instructions have been sent to your email.'],
// };
// resetPassword?: boolean | NbPasswordStrategyModule = {
// redirect: {
// success: '/',
// failure: null,
// },
// defaultErrors: ['Something went wrong, please try again.'],
// defaultMessages: ['Your password has been successfully changed.'],
// };
// errors?: NbPasswordStrategyMessage = {
// key: 'message',
// getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject(
// res,
// options.errors.key,
// options[module].defaultErrors,
// ),
// };
// messages?: NbPasswordStrategyMessage = {
// key: 'messages',
// getter: (module: string, res, options: NbFirebasePasswordStrategyOptions) => getDeepFromObject(
// res.body,
// options.messages.key,
// options[module].defaultMessages,
// ),
// };
}

View file

@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { NbAuthComponent } from '@nebular/auth';
import { NgxLoginComponent } from './login/login.component';
import { NgxRegisterComponent } from './register/register.component';
export const routes: Routes = [
// .. here goes our components routes
{
path: '',
component: NbAuthComponent,
children: [
{
path: 'login',
component: NgxLoginComponent,
},
{
path: 'register',
component: NgxRegisterComponent,
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class NgxAuthRoutingModule {
}

View file

@ -0,0 +1,61 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { NgxAuthRoutingModule } from './auth-routing.module';
import { NbAuthModule, NbPasswordAuthStrategy } from '@nebular/auth';
import {
NbAlertModule,
NbButtonModule,
NbCheckboxModule,
NbInputModule
} from '@nebular/theme';
import { NgxLoginComponent } from './login/login.component';
import { NgxRegisterComponent } from './register/register.component';
import { NbFirebasePasswordStrategyOptions } from './auth-firebase.config';
@NgModule({
imports: [
CommonModule,
FormsModule,
RouterModule,
NbAlertModule,
NbInputModule,
NbButtonModule,
NbCheckboxModule,
NgxAuthRoutingModule,
NbAuthModule.forRoot({
strategies: [
NbPasswordAuthStrategy.setup({
name: 'email',
login: {
redirect: {
success: '/dashboard',
failure: null, // stay on the same page
},
},
register: {
redirect: {
success: '/auth/login',
failure: null, // stay on the same page
},
},
...new NbFirebasePasswordStrategyOptions()
}),
],
forms: {},
}),
],
declarations: [
// ... here goes our new components
NgxLoginComponent,
NgxRegisterComponent
],
})
export class NgxAuthModule {
}

View file

@ -0,0 +1,159 @@
<h1 id="title" class="title">Login</h1>
<p class="sub-title">Welcome to RESUME TAILOR!!!</p>
<!-- <nb-alert
*ngIf="showMessages.error && errors?.length && !submitted"
outline="danger"
role="alert"
>
<p class="alert-title"><b>Oh snap!</b></p>
<ul class="alert-message-list">
<li *ngFor="let error of errors" class="alert-message">{{ error }}</li>
</ul>
</nb-alert> -->
<!-- <nb-alert
*ngIf="showMessages.success && messages?.length && !submitted"
outline="success"
role="alert"
>
<p class="alert-title"><b>Hooray!</b></p>
<ul class="alert-message-list">
<li *ngFor="let message of messages" class="alert-message">
{{ message }}
</li>
</ul>
</nb-alert> -->
<form (ngSubmit)="login()" #form="ngForm" aria-labelledby="title">
<div class="form-control-group">
<label class="label" for="input-email">Email address:</label>
<input
nbInput
fullWidth
[(ngModel)]="user.email"
#email="ngModel"
name="email"
id="input-email"
pattern=".+@.+\..+"
placeholder="Email address"
fieldSize="large"
autofocus
[status]="email.dirty ? (email.invalid ? 'danger' : 'success') : 'basic'"
[required]="getConfigValue('forms.validation.email.required')"
[attr.aria-invalid]="email.invalid && email.touched ? true : null"
/>
<ng-container *ngIf="email.invalid && email.touched">
<p class="caption status-danger" *ngIf="email.errors?.required">
Email is required!
</p>
<p class="caption status-danger" *ngIf="email.errors?.pattern">
Email should be the real one!
</p>
</ng-container>
</div>
<div class="form-control-group">
<span class="label-with-link">
<label class="label" for="input-password">Password:</label>
<!-- <a class="forgot-password caption-2" routerLink="../request-password"
>Forgot Password?</a
> -->
</span>
<input
nbInput
fullWidth
[(ngModel)]="user.password"
#password="ngModel"
name="password"
type="password"
id="input-password"
placeholder="Password"
fieldSize="large"
[status]="
password.dirty ? (password.invalid ? 'danger' : 'success') : 'basic'
"
[required]="getConfigValue('forms.validation.password.required')"
[minlength]="getConfigValue('forms.validation.password.minLength')"
[maxlength]="getConfigValue('forms.validation.password.maxLength')"
[attr.aria-invalid]="password.invalid && password.touched ? true : null"
/>
<ng-container *ngIf="password.invalid && password.touched">
<p class="caption status-danger" *ngIf="password.errors?.required">
Password is required!
</p>
<p
class="caption status-danger"
*ngIf="password.errors?.minlength || password.errors?.maxlength"
>
Password should contain from
{{ getConfigValue("forms.validation.password.minLength") }} to
{{ getConfigValue("forms.validation.password.maxLength") }}
characters
</p>
</ng-container>
</div>
<div class="form-control-group accept-group">
<nb-checkbox
name="rememberMe"
[(ngModel)]="user.rememberMe"
*ngIf="rememberMe"
>Remember me</nb-checkbox
>
</div>
<button
nbButton
fullWidth
status="primary"
size="large"
[disabled]="submitted || !form.valid"
[class.btn-pulse]="submitted"
>
Log In
</button>
</form>
<!-- <section
*ngIf="socialLinks && socialLinks.length > 0"
class="links"
aria-label="Social sign in"
>
or enter with:
<div class="socials">
<ng-container *ngFor="let socialLink of socialLinks">
<a
*ngIf="socialLink.link"
[routerLink]="socialLink.link"
[attr.target]="socialLink.target"
[attr.class]="socialLink.icon"
[class.with-icon]="socialLink.icon"
>
<nb-icon
*ngIf="socialLink.icon; else title"
[icon]="socialLink.icon"
></nb-icon>
<ng-template #title>{{ socialLink.title }}</ng-template>
</a>
<a
*ngIf="socialLink.url"
[attr.href]="socialLink.url"
[attr.target]="socialLink.target"
[attr.class]="socialLink.icon"
[class.with-icon]="socialLink.icon"
>
<nb-icon
*ngIf="socialLink.icon; else title"
[icon]="socialLink.icon"
></nb-icon>
<ng-template #title>{{ socialLink.title }}</ng-template>
</a>
</ng-container>
</div>
</section> -->
<section class="another-action" aria-label="Register">
Don't have an account?
<a class="text-link" routerLink="../register">Register</a>
</section>

View file

@ -0,0 +1,71 @@
import { Component, ChangeDetectorRef } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router'; // Import Router from @angular/router
import { NbAuthService } from '@nebular/auth';
import { NbLoginComponent } from '@nebular/auth';
@Component({
selector: 'ngx-login',
templateUrl: './login.component.html',
})
export class NgxLoginComponent extends NbLoginComponent {
constructor(
private fireAuth: AngularFireAuth,
private authService: NbAuthService,
public cd: ChangeDetectorRef, // Change to public or protected if NbLoginComponent's cd is public or protected
public router: Router // Import Router from @angular/router
) {
super(authService, {}, cd, router);
}
async login() {
try {
await this.fireAuth.signInWithEmailAndPassword(this.user.email, this.user.password);
const user = await this.fireAuth.currentUser; // Get current user
if (user) {
const accessToken = await user.getIdToken(); // Get Firebase Authentication token (access token)
const expiresIn = new Date().getTime() + 3600 * 1000; // Token expiration time (1 hour)
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('accessTokenExpiresIn', expiresIn.toString()); // Store token expiration time
this.router.navigate(['dashboard']); // Redirect to dashboard
this.scheduleTokenRefresh(); // Schedule token refresh
}
console.log("Successfully Logged in.")
} catch (error) {
// Handle login errors here
console.error('Error signing in:', error);
// You can also display error messages to the user using this.errors array
this.errors = ['Error signing in. Please try again.'];
}
}
private async scheduleTokenRefresh(): Promise<void> {
const expiresInString = localStorage.getItem('accessTokenExpiresIn');
if (expiresInString) {
const expiresIn = +expiresInString;
const timeUntilRefresh = expiresIn - new Date().getTime() - 300000; // Refresh token 5 minutes before expiration
if (timeUntilRefresh > 0) {
setTimeout(async () => {
try {
const user = await this.fireAuth.currentUser;
if (user) {
const newAccessToken = await user.getIdToken();
localStorage.setItem('accessToken', newAccessToken);
const newExpiresIn = new Date().getTime() + 3600 * 1000; // Extend expiration time by 1 hour
localStorage.setItem('accessTokenExpiresIn', newExpiresIn.toString());
this.scheduleTokenRefresh();
}
} catch (error) {
console.error('Token refresh failed:', error);
}
}, timeUntilRefresh);
}
} else {
console.error('Access token expiration time is not available.');
}
}
getConfigValue(key: string): any {
// Implement this method based on your configuration retrieval logic
}
}

View file

@ -0,0 +1,227 @@
<h1 id="title" class="title">Register</h1>
<!-- <nb-alert
*ngIf="showMessages.error && errors?.length && !submitted"
outline="danger"
role="alert"
>
<p class="alert-title"><b>Oh snap!</b></p>
<ul class="alert-message-list">
<li *ngFor="let error of errors" class="alert-message">{{ error }}</li>
</ul>
</nb-alert>
<nb-alert
*ngIf="showMessages.success && messages?.length && !submitted"
outline="success"
role="alert"
>
<p class="alert-title"><b>Hooray!</b></p>
<ul class="alert-message-list">
<li *ngFor="let message of messages" class="alert-message">
{{ message }}
</li>
</ul>
</nb-alert> -->
<form (ngSubmit)="register()" #form="ngForm" aria-labelledby="title">
<div class="form-control-group">
<label class="label" for="input-name">Full name:</label>
<input
nbInput
[(ngModel)]="user.fullName"
#fullName="ngModel"
id="input-name"
name="fullName"
placeholder="Full name"
autofocus
fullWidth
fieldSize="large"
[status]="
fullName.dirty ? (fullName.invalid ? 'danger' : 'success') : 'basic'
"
[required]="getConfigValue('forms.validation.fullName.required')"
[minlength]="getConfigValue('forms.validation.fullName.minLength')"
[maxlength]="getConfigValue('forms.validation.fullName.maxLength')"
[attr.aria-invalid]="fullName.invalid && fullName.touched ? true : null"
/>
<ng-container *ngIf="fullName.invalid && fullName.touched">
<p class="caption status-danger" *ngIf="fullName.errors?.required">
Full name is required!
</p>
<p
class="caption status-danger"
*ngIf="fullName.errors?.minlength || fullName.errors?.maxlength"
>
Full name should contains from
{{ getConfigValue("forms.validation.fullName.minLength") }} to
{{ getConfigValue("forms.validation.fullName.maxLength") }}
characters
</p>
</ng-container>
</div>
<div class="form-control-group">
<label class="label" for="input-email">Email address:</label>
<input
nbInput
[(ngModel)]="user.email"
#email="ngModel"
id="input-email"
name="email"
pattern=".+@.+..+"
placeholder="Email address"
fullWidth
fieldSize="large"
[status]="email.dirty ? (email.invalid ? 'danger' : 'success') : 'basic'"
[required]="getConfigValue('forms.validation.email.required')"
[attr.aria-invalid]="email.invalid && email.touched ? true : null"
/>
<ng-container *ngIf="email.invalid && email.touched">
<p class="caption status-danger" *ngIf="email.errors?.required">
Email is required!
</p>
<p class="caption status-danger" *ngIf="email.errors?.pattern">
Email should be the real one!
</p>
</ng-container>
</div>
<div class="form-control-group">
<label class="label" for="input-password">Password:</label>
<input
nbInput
[(ngModel)]="user.password"
#password="ngModel"
type="password"
id="input-password"
name="password"
placeholder="Password"
fullWidth
fieldSize="large"
[status]="
password.dirty ? (password.invalid ? 'danger' : 'success') : 'basic'
"
[required]="getConfigValue('forms.validation.password.required')"
[minlength]="getConfigValue('forms.validation.password.minLength')"
[maxlength]="getConfigValue('forms.validation.password.maxLength')"
[attr.aria-invalid]="password.invalid && password.touched ? true : null"
/>
<ng-container *ngIf="password.invalid && password.touched">
<p class="caption status-danger" *ngIf="password.errors?.required">
Password is required!
</p>
<p
class="caption status-danger"
*ngIf="password.errors?.minlength || password.errors?.maxlength"
>
Password should contain from
{{ getConfigValue("forms.validation.password.minLength") }} to
{{ getConfigValue("forms.validation.password.maxLength") }}
characters
</p>
</ng-container>
</div>
<div class="form-control-group">
<label class="label" for="input-re-password">Confirm password:</label>
<input
nbInput
[(ngModel)]="user.confirmPassword"
#rePass="ngModel"
type="password"
id="input-re-password"
name="rePass"
placeholder="Confirm Password"
fullWidth
fieldSize="large"
[status]="
rePass.dirty
? rePass.invalid || password.value != rePass.value
? 'danger'
: 'success'
: 'basic'
"
[required]="getConfigValue('forms.validation.password.required')"
[attr.aria-invalid]="rePass.invalid && rePass.touched ? true : null"
/>
<ng-container *ngIf="rePass.invalid && rePass.touched">
<p class="caption status-danger" *ngIf="rePass.errors?.required">
Password confirmation is required!
</p>
<p
class="caption status-danger"
*ngIf="password.value != rePass.value && !rePass.errors?.required"
>
Password does not match the confirm password.
</p>
</ng-container>
</div>
<!-- <div
class="form-control-group accept-group"
*ngIf="getConfigValue('forms.register.terms')"
>
<nb-checkbox
name="terms"
[(ngModel)]="user.terms"
[required]="getConfigValue('forms.register.terms')"
>
Agree to
<a href="#" target="_blank"><strong>Terms & Conditions</strong></a>
</nb-checkbox>
</div> -->
<button
nbButton
fullWidth
status="primary"
size="large"
[disabled]="submitted || !form.valid"
[class.btn-pulse]="submitted"
>
Register
</button>
</form>
<!-- <section
*ngIf="socialLinks && socialLinks.length > 0"
class="links"
aria-label="Social sign in"
>
or enter with:
<div class="socials">
<ng-container *ngFor="let socialLink of socialLinks">
<a
*ngIf="socialLink.link"
[routerLink]="socialLink.link"
[attr.target]="socialLink.target"
[attr.class]="socialLink.icon"
[class.with-icon]="socialLink.icon"
>
<nb-icon
*ngIf="socialLink.icon; else title"
[icon]="socialLink.icon"
></nb-icon>
<ng-template #title>{{ socialLink.title }}</ng-template>
</a>
<a
*ngIf="socialLink.url"
[attr.href]="socialLink.url"
[attr.target]="socialLink.target"
[attr.class]="socialLink.icon"
[class.with-icon]="socialLink.icon"
>
<nb-icon
*ngIf="socialLink.icon; else title"
[icon]="socialLink.icon"
></nb-icon>
<ng-template #title>{{ socialLink.title }}</ng-template>
</a>
</ng-container>
</div>
</section> -->
<section class="another-action" aria-label="Sign in">
Already have an account? <a class="text-link" routerLink="../login">Log in</a>
</section>

View file

@ -0,0 +1,42 @@
import { Component } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router';
@Component({
selector: 'ngx-register',
templateUrl: './register.component.html',
})
export class NgxRegisterComponent {
user = {
fullName: '',
email: '',
password: '',
confirmPassword: ''
};
submitted = false;
errors: string[] = [];
constructor(private fireAuth: AngularFireAuth, private router: Router) {}
async register() {
this.submitted = true;
try {
if (this.user.password !== this.user.confirmPassword) {
throw new Error('Password does not match the confirm password.');
}
await this.fireAuth.createUserWithEmailAndPassword(this.user.email, this.user.password);
// Registration successful, redirect to login page or dashboard
this.router.navigate(['auth/login']);
} catch (error) {
// Handle registration errors
console.error('Error registering user:', error);
this.errors.push(error.message || 'An error occurred. Please try again later.');
}
this.submitted = false;
}
getConfigValue(key: string): any {
// Implement this method based on your configuration retrieval logic
}
}

View file

@ -1 +0,0 @@
<p>login works!</p>

View file

@ -1,27 +0,0 @@
import { Component } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router';
@Component({
selector: 'ngx-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent {
email: string = '';
password: string = '';
errorMessage: string = '';
constructor(private afAuth: AngularFireAuth, private router: Router) {}
async login() {
try {
const userCredential = await this.afAuth.signInWithEmailAndPassword(this.email, this.password);
// If login successful, navigate to the home page or any other desired route
this.router.navigate(['/home']);
} catch (error) {
// Handle authentication errors
this.errorMessage = error.message;
}
}
}

View file

@ -7,7 +7,6 @@ import { DashboardModule } from './dashboard/dashboard.module';
import { ECommerceModule } from './e-commerce/e-commerce.module'; import { ECommerceModule } from './e-commerce/e-commerce.module';
import { PagesRoutingModule } from './pages-routing.module'; import { PagesRoutingModule } from './pages-routing.module';
import { MiscellaneousModule } from './miscellaneous/miscellaneous.module'; import { MiscellaneousModule } from './miscellaneous/miscellaneous.module';
import { LoginComponent } from './login/login.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -20,7 +19,6 @@ import { LoginComponent } from './login/login.component';
], ],
declarations: [ declarations: [
PagesComponent, PagesComponent,
LoginComponent,
], ],
}) })
export class PagesModule { export class PagesModule {

View file

@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(): boolean {
const accessToken = localStorage.getItem('accessToken');
const accessTokenExpiresIn = localStorage.getItem('accessTokenExpiresIn');
// Check if access token and expiration time exist
if (accessToken && accessTokenExpiresIn) {
// Check if the access token is not expired
const currentTime = new Date().getTime();
const expiresIn = +accessTokenExpiresIn;
if (currentTime < expiresIn) {
return true; // Allow access to the route
}
}
// If access token is not found or expired, navigate to login page
this.router.navigate(['/auth/login']);
return false;
}
}

View file

@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
user$: Observable<firebase.default.User | null>;
constructor(private fireAuth: AngularFireAuth, private router: Router) {
this.user$ = this.fireAuth.authState;
}
// logout method
async logout(): Promise<void> {
try {
await this.fireAuth.signOut();
localStorage.removeItem('accessToken');
localStorage.removeItem('accessTokenExpiresIn');
this.router.navigate(['dashboard'], { queryParams: { logout: true } });
} catch (error: any) {
throw error;
}
}
}

View file

@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let service: AuthService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AuthService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View file

@ -1,41 +0,0 @@
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private fireauth: AngularFireAuth, private router: Router) { }
login(email: string, password: string) {
this.fireauth.signInWithEmailAndPassword(email, password).then(() => {
localStorage.setItem('token', 'true');
this.router.navigate(['/home']);
}, err => {
alert('Login Again')
this.router.navigate(['/login'])
})
}
//register
register(email: string, password: string) {
this.fireauth.createUserWithEmailAndPassword(email, password).then(() => {
alert('Registration Successful')
this.router.navigate(['/login']);
}, err => {
alert("Error Registering")
this.router.navigate(['/register'])
})
}
logout() {
this.fireauth.signOut().then( () => {
localStorage.removeItem('token');
this.router.navigate(['/login']);
}, err => {
alert(err.message)
})
}
}

View file

@ -0,0 +1,6 @@
export interface ResponseWrapper<T> {
success: boolean;
message: string;
data: T;
error?: any;
}