mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-16 15:40:11 +01:00
Merge c26e0c99f1 into 06776d15c4
This commit is contained in:
commit
26bdeb7336
19 changed files with 31923 additions and 520 deletions
|
|
@ -187,5 +187,8 @@
|
||||||
"@angular-eslint/schematics:library": {
|
"@angular-eslint/schematics:library": {
|
||||||
"setParserOptionsProject": true
|
"setParserOptionsProject": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31529
package-lock.json
generated
31529
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -35,14 +35,16 @@
|
||||||
"@angular/common": "^15.2.10",
|
"@angular/common": "^15.2.10",
|
||||||
"@angular/compiler": "^15.2.10",
|
"@angular/compiler": "^15.2.10",
|
||||||
"@angular/core": "^15.2.10",
|
"@angular/core": "^15.2.10",
|
||||||
|
"@angular/fire": "^7.6.1",
|
||||||
"@angular/forms": "^15.2.10",
|
"@angular/forms": "^15.2.10",
|
||||||
"@angular/google-maps": "^12.2.13",
|
"@angular/google-maps": "^12.2.13",
|
||||||
"@angular/platform-browser": "^15.2.10",
|
"@angular/platform-browser": "^15.2.10",
|
||||||
"@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",
|
||||||
|
|
@ -62,12 +64,12 @@
|
||||||
"ng2-completer": "^9.0.1",
|
"ng2-completer": "^9.0.1",
|
||||||
"ng2-smart-table": "^1.6.0",
|
"ng2-smart-table": "^1.6.0",
|
||||||
"ngx-echarts": "^4.2.2",
|
"ngx-echarts": "^4.2.2",
|
||||||
"node-sass": "^4.14.1",
|
|
||||||
"normalize.css": "6.0.0",
|
"normalize.css": "6.0.0",
|
||||||
"pace-js": "1.0.2",
|
"pace-js": "1.0.2",
|
||||||
"roboto-fontface": "0.8.0",
|
"roboto-fontface": "0.8.0",
|
||||||
"rxjs": "6.6.2",
|
"rxjs": "6.6.2",
|
||||||
"rxjs-compat": "6.3.0",
|
"rxjs-compat": "6.3.0",
|
||||||
|
"sass": "^1.49.0",
|
||||||
"socicon": "3.0.5",
|
"socicon": "3.0.5",
|
||||||
"style-loader": "^1.3.0",
|
"style-loader": "^1.3.0",
|
||||||
"tinymce": "4.5.7",
|
"tinymce": "4.5.7",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { of as observableOf, Observable } from 'rxjs';
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { Contacts, RecentUsers, UserData } from '../data/users';
|
import { Contacts, RecentUsers, UserData } from '../data/users';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
@ -8,7 +8,7 @@ export class UserService extends UserData {
|
||||||
private time: Date = new Date;
|
private time: Date = new Date;
|
||||||
|
|
||||||
private users = {
|
private users = {
|
||||||
nick: { name: 'Nick Jones', picture: 'assets/images/nick.png' },
|
nick: { name: 'Users', picture: 'assets/images/nick.png' },
|
||||||
eva: { name: 'Eva Moor', picture: 'assets/images/eva.png' },
|
eva: { name: 'Eva Moor', picture: 'assets/images/eva.png' },
|
||||||
jack: { name: 'Jack Williams', picture: 'assets/images/jack.png' },
|
jack: { name: 'Jack Williams', picture: 'assets/images/jack.png' },
|
||||||
lee: { name: 'Lee Wong', picture: 'assets/images/lee.png' },
|
lee: { name: 'Lee Wong', picture: 'assets/images/lee.png' },
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
|
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
|
||||||
<nb-icon icon="menu-2-outline"></nb-icon>
|
<nb-icon icon="menu-2-outline"></nb-icon>
|
||||||
</a>
|
</a>
|
||||||
<a class="logo" href="#" (click)="navigateHome()">ngx-<span>admin</span></a>
|
<a class="logo" href="#" (click)="navigateHome()">T<span>Resume</span></a>
|
||||||
</div>
|
</div>
|
||||||
<nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
|
<nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
|
||||||
<nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>
|
<nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>
|
||||||
|
|
@ -18,11 +18,8 @@
|
||||||
</nb-action>
|
</nb-action>
|
||||||
<nb-action class="control-item" icon="email-outline"></nb-action>
|
<nb-action class="control-item" icon="email-outline"></nb-action>
|
||||||
<nb-action class="control-item" icon="bell-outline"></nb-action>
|
<nb-action class="control-item" icon="bell-outline"></nb-action>
|
||||||
<nb-action class="user-action" *nbIsGranted="['view', 'user']" >
|
<nb-action class="user-action" *nbIsGranted="['view', 'user']">
|
||||||
<nb-user [nbContextMenu]="userMenu"
|
<nb-user [nbContextMenu]="userMenu" [onlyPicture]="userPictureOnly" [name]="user?.name" [picture]="user?.picture">
|
||||||
[onlyPicture]="userPictureOnly"
|
|
||||||
[name]="user?.name"
|
|
||||||
[picture]="user?.picture">
|
|
||||||
</nb-user>
|
</nb-user>
|
||||||
</nb-action>
|
</nb-action>
|
||||||
</nb-actions>
|
</nb-actions>
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,18 @@
|
||||||
import { ExtraOptions, RouterModule, Routes } from '@angular/router';
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import {
|
import { ExtraOptions, RouterModule, Routes } from '@angular/router';
|
||||||
NbAuthComponent,
|
import { AuthGuard } from './service/auth-guard.service';
|
||||||
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: '',
|
|
||||||
component: NbLoginComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'login',
|
|
||||||
component: NbLoginComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'register',
|
|
||||||
component: NbRegisterComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'logout',
|
|
||||||
component: NbLogoutComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'request-password',
|
|
||||||
component: NbRequestPasswordComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'reset-password',
|
|
||||||
component: NbResetPasswordComponent,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{ path: '', redirectTo: 'pages', pathMatch: 'full' },
|
|
||||||
{ path: '**', redirectTo: 'pages' },
|
{ path: '**', redirectTo: 'pages' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,8 @@
|
||||||
/**
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
* @license
|
import { NgModule } from '@angular/core';
|
||||||
* Copyright Akveo. All Rights Reserved.
|
import { AngularFireModule } from '@angular/fire/compat';
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*/
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
|
||||||
import { CoreModule } from './@core/core.module';
|
|
||||||
import { ThemeModule } from './@theme/theme.module';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
|
||||||
import {
|
import {
|
||||||
NbChatModule,
|
NbChatModule,
|
||||||
NbDatepickerModule,
|
NbDatepickerModule,
|
||||||
|
|
@ -20,6 +12,14 @@ import {
|
||||||
NbToastrModule,
|
NbToastrModule,
|
||||||
NbWindowModule,
|
NbWindowModule,
|
||||||
} from '@nebular/theme';
|
} from '@nebular/theme';
|
||||||
|
import { environment } from '../environments/environment';
|
||||||
|
import { CoreModule } from './@core/core.module';
|
||||||
|
import { ThemeModule } from './@theme/theme.module';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
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],
|
||||||
|
|
@ -28,6 +28,8 @@ import {
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
AngularFireModule.initializeApp(environment.firebase),
|
||||||
|
AngularFireAuthModule,
|
||||||
NbSidebarModule.forRoot(),
|
NbSidebarModule.forRoot(),
|
||||||
NbMenuModule.forRoot(),
|
NbMenuModule.forRoot(),
|
||||||
NbDatepickerModule.forRoot(),
|
NbDatepickerModule.forRoot(),
|
||||||
|
|
@ -40,6 +42,9 @@ import {
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
ThemeModule.forRoot(),
|
ThemeModule.forRoot(),
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
AuthGuard
|
||||||
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
|
|
||||||
72
src/app/auth/auth-firebase.config.ts
Normal file
72
src/app/auth/auth-firebase.config.ts
Normal 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,
|
||||||
|
// ),
|
||||||
|
// };
|
||||||
|
}
|
||||||
31
src/app/auth/auth-routing.module.ts
Normal file
31
src/app/auth/auth-routing.module.ts
Normal 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 {
|
||||||
|
}
|
||||||
61
src/app/auth/auth.module.ts
Normal file
61
src/app/auth/auth.module.ts
Normal 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 {
|
||||||
|
}
|
||||||
159
src/app/auth/login/login.component.html
Normal file
159
src/app/auth/login/login.component.html
Normal 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>
|
||||||
71
src/app/auth/login/login.component.ts
Normal file
71
src/app/auth/login/login.component.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
227
src/app/auth/register/register.component.html
Normal file
227
src/app/auth/register/register.component.html
Normal 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>
|
||||||
42
src/app/auth/register/register.component.ts
Normal file
42
src/app/auth/register/register.component.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,15 +2,11 @@ import { NbMenuItem } from '@nebular/theme';
|
||||||
|
|
||||||
export const MENU_ITEMS: NbMenuItem[] = [
|
export const MENU_ITEMS: NbMenuItem[] = [
|
||||||
{
|
{
|
||||||
title: 'E-commerce',
|
title: 'Home',
|
||||||
icon: 'shopping-cart-outline',
|
icon: 'home-outline',
|
||||||
link: '/pages/dashboard',
|
link: '/pages/dashboard',
|
||||||
home: true,
|
home: true,
|
||||||
},
|
hidden: true
|
||||||
{
|
|
||||||
title: 'IoT Dashboard',
|
|
||||||
icon: 'home-outline',
|
|
||||||
link: '/pages/iot-dashboard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'FEATURES',
|
title: 'FEATURES',
|
||||||
|
|
@ -144,74 +140,7 @@ export const MENU_ITEMS: NbMenuItem[] = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Maps',
|
|
||||||
icon: 'map-outline',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
title: 'Google Maps',
|
|
||||||
link: '/pages/maps/gmaps',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Leaflet Maps',
|
|
||||||
link: '/pages/maps/leaflet',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Bubble Maps',
|
|
||||||
link: '/pages/maps/bubble',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Search Maps',
|
|
||||||
link: '/pages/maps/searchmap',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Charts',
|
|
||||||
icon: 'pie-chart-outline',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
title: 'Echarts',
|
|
||||||
link: '/pages/charts/echarts',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Charts.js',
|
|
||||||
link: '/pages/charts/chartjs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'D3',
|
|
||||||
link: '/pages/charts/d3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Editors',
|
|
||||||
icon: 'text-outline',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
title: 'TinyMCE',
|
|
||||||
link: '/pages/editors/tinymce',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'CKEditor',
|
|
||||||
link: '/pages/editors/ckeditor',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Tables & Data',
|
|
||||||
icon: 'grid-outline',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
title: 'Smart Table',
|
|
||||||
link: '/pages/tables/smart-table',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Tree Grid',
|
|
||||||
link: '/pages/tables/tree-grid',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Miscellaneous',
|
title: 'Miscellaneous',
|
||||||
icon: 'shuffle-2-outline',
|
icon: 'shuffle-2-outline',
|
||||||
|
|
@ -234,14 +163,7 @@ export const MENU_ITEMS: NbMenuItem[] = [
|
||||||
title: 'Register',
|
title: 'Register',
|
||||||
link: '/auth/register',
|
link: '/auth/register',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Request Password',
|
|
||||||
link: '/auth/request-password',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Reset Password',
|
|
||||||
link: '/auth/reset-password',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
29
src/app/service/auth-guard.service.ts
Normal file
29
src/app/service/auth-guard.service.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/app/service/auth.service.ts
Normal file
30
src/app/service/auth.service.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/app/utils/response-wrapper.ts
Normal file
6
src/app/utils/response-wrapper.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export interface ResponseWrapper<T> {
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
data: T;
|
||||||
|
error?: any;
|
||||||
|
}
|
||||||
|
|
@ -10,4 +10,12 @@
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
|
firebase: {
|
||||||
|
apiKey: "AIzaSyCPFCMSkeRtJJhiu_yWLIggkRpFL_OM88M",
|
||||||
|
authDomain: "test-app-133d0.firebaseapp.com",
|
||||||
|
projectId: "test-app-133d0",
|
||||||
|
storageBucket: "test-app-133d0.appspot.com",
|
||||||
|
messagingSenderId: "166874967658",
|
||||||
|
appId: "1:166874967658:web:53ef3ec2bb8456d9e2a413"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue