all done, need to fix routing to Dashboard
This commit is contained in:
parent
11a4b0fc86
commit
ea41ebf364
|
@ -28,6 +28,7 @@
|
||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
"node_modules/bootstrap/dist/css/bootstrap.min.css",
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
|
@ -104,4 +105,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="displayTable">
|
||||||
|
<div class="displayTableCell">
|
||||||
|
<div class="authBlock">
|
||||||
|
<h3>Reset Password</h3>
|
||||||
|
<p class="text-center">Please enter your email address to request a password reset.</p>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="email" class="formControl" placeholder="Email Address" #passwordResetEmail required>
|
||||||
|
</div>
|
||||||
|
<!-- Calling ForgotPassword from AuthService Api -->
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="submit" class="btn btnPrimary" value="Reset Password"
|
||||||
|
(click)="authService.ForgotPassword(passwordResetEmail.value)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="redirectToLogin">
|
||||||
|
<span>Go back to ? <span class="redirect" routerLink="/sign-in">Log In</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ForgotPasswordComponent } from './forgot-password.component';
|
||||||
|
|
||||||
|
describe('ForgotPasswordComponent', () => {
|
||||||
|
let component: ForgotPasswordComponent;
|
||||||
|
let fixture: ComponentFixture<ForgotPasswordComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ForgotPasswordComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ForgotPasswordComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
16
src/app/account/forgot-password/forgot-password.component.ts
Normal file
16
src/app/account/forgot-password/forgot-password.component.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-forgot-password',
|
||||||
|
templateUrl: './forgot-password.component.html',
|
||||||
|
styleUrls: ['./forgot-password.component.scss']
|
||||||
|
})
|
||||||
|
export class ForgotPasswordComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
src/app/account/sign-in/sign-in.component.html
Normal file
34
src/app/account/sign-in/sign-in.component.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<div class="displayTable">
|
||||||
|
<div class="displayTableCell">
|
||||||
|
<div class="authBlock">
|
||||||
|
<h3>Sign In</h3>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="text" class="formControl" placeholder="Username" #userName required>
|
||||||
|
</div>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="password" class="formControl" placeholder="Password" #userPassword required>
|
||||||
|
</div>
|
||||||
|
<!-- Calling SignIn Api from AuthService -->
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="button" class="btn btnPrimary" value="Log in"
|
||||||
|
(click)="authService.SignIn(userName.value, userPassword.value)">
|
||||||
|
</div>
|
||||||
|
<div class="formGroup">
|
||||||
|
<span class="or"><span class="orInner">Or</span></span>
|
||||||
|
</div>
|
||||||
|
<!-- Calling GoogleAuth Api from AuthService -->
|
||||||
|
<div class="formGroup">
|
||||||
|
<button type="button" class="btn googleBtn" (click)="authService.GoogleAuth()">
|
||||||
|
<i class="fab fa-google-plus-g"></i>
|
||||||
|
Log in with Google
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="forgotPassword">
|
||||||
|
<span routerLink="/forgot-password">Forgot Password?</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="redirectToLogin">
|
||||||
|
<span>Don't have an account?<span class="redirect" routerLink="/register-user"> Sign Up</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
0
src/app/account/sign-in/sign-in.component.scss
Normal file
0
src/app/account/sign-in/sign-in.component.scss
Normal file
|
@ -1,18 +1,18 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { HeaderComponent } from './header.component';
|
import { SignInComponent } from './sign-in.component';
|
||||||
|
|
||||||
describe('HeaderComponent', () => {
|
describe('SignInComponent', () => {
|
||||||
let component: HeaderComponent;
|
let component: SignInComponent;
|
||||||
let fixture: ComponentFixture<HeaderComponent>;
|
let fixture: ComponentFixture<SignInComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ HeaderComponent ]
|
declarations: [ SignInComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HeaderComponent);
|
fixture = TestBed.createComponent(SignInComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
16
src/app/account/sign-in/sign-in.component.ts
Normal file
16
src/app/account/sign-in/sign-in.component.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-sign-in',
|
||||||
|
templateUrl: './sign-in.component.html',
|
||||||
|
styleUrls: ['./sign-in.component.scss']
|
||||||
|
})
|
||||||
|
export class SignInComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/app/account/sign-up/sign-up.component.html
Normal file
31
src/app/account/sign-up/sign-up.component.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<div class="displayTable">
|
||||||
|
<div class="displayTableCell">
|
||||||
|
<div class="authBlock">
|
||||||
|
<h3>Sign Up</h3>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="email" class="formControl" placeholder="Email Address" #userEmail required />
|
||||||
|
</div>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="password" class="formControl" placeholder="Password" #userPwd required />
|
||||||
|
</div>
|
||||||
|
<div class="formGroup">
|
||||||
|
<input type="button" class="btn btnPrimary" value="Sign Up"
|
||||||
|
(click)="authService.SignUp(userEmail.value, userPwd.value)" />
|
||||||
|
</div>
|
||||||
|
<div class="formGroup">
|
||||||
|
<span class="or"><span class="orInner">Or</span></span>
|
||||||
|
</div>
|
||||||
|
<!-- Continue with Google -->
|
||||||
|
<div class="formGroup">
|
||||||
|
<button type="button" class="btn googleBtn" (click)="authService.GoogleAuth()">
|
||||||
|
<i class="fab fa-google-plus-g"></i>
|
||||||
|
Continue with Google
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="redirectToLogin">
|
||||||
|
<span>Already have an account?
|
||||||
|
<span class="redirect" routerLink="/sign-in">Log In</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
0
src/app/account/sign-up/sign-up.component.scss
Normal file
0
src/app/account/sign-up/sign-up.component.scss
Normal file
|
@ -1,18 +1,18 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { FirebaseAuthComponent } from './firebase-auth.component';
|
import { SignUpComponent } from './sign-up.component';
|
||||||
|
|
||||||
describe('FirebaseAuthComponent', () => {
|
describe('SignUpComponent', () => {
|
||||||
let component: FirebaseAuthComponent;
|
let component: SignUpComponent;
|
||||||
let fixture: ComponentFixture<FirebaseAuthComponent>;
|
let fixture: ComponentFixture<SignUpComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ FirebaseAuthComponent ]
|
declarations: [ SignUpComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(FirebaseAuthComponent);
|
fixture = TestBed.createComponent(SignUpComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
16
src/app/account/sign-up/sign-up.component.ts
Normal file
16
src/app/account/sign-up/sign-up.component.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-sign-up',
|
||||||
|
templateUrl: './sign-up.component.html',
|
||||||
|
styleUrls: ['./sign-up.component.scss']
|
||||||
|
})
|
||||||
|
export class SignUpComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
src/app/account/verify-email/verify-email.component.html
Normal file
22
src/app/account/verify-email/verify-email.component.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="displayTable">
|
||||||
|
<div class="displayTableCell">
|
||||||
|
<div class="authBlock">
|
||||||
|
<h3>Thank You for Registering</h3>
|
||||||
|
<div class="formGroup" *ngIf="authService.userData as user">
|
||||||
|
<p class="text-center">We have sent a confirmation email to <strong>{{user.email}}</strong>.</p>
|
||||||
|
<p class="text-center">Please check your email and click on the link to verfiy your email address.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Calling SendVerificationMail() method using authService Api -->
|
||||||
|
<div class="formGroup">
|
||||||
|
<button type="button" class="btn btnPrimary" (click)="authService.SendVerificationMail()">
|
||||||
|
<i class="fas fa-redo-alt"></i>
|
||||||
|
Resend Verification Email
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="redirectToLogin">
|
||||||
|
<span>Go back to?<span class="redirect" routerLink="/sign-in"> Sign in</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
23
src/app/account/verify-email/verify-email.component.spec.ts
Normal file
23
src/app/account/verify-email/verify-email.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { VerifyEmailComponent } from './verify-email.component';
|
||||||
|
|
||||||
|
describe('VerifyEmailComponent', () => {
|
||||||
|
let component: VerifyEmailComponent;
|
||||||
|
let fixture: ComponentFixture<VerifyEmailComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ VerifyEmailComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(VerifyEmailComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
16
src/app/account/verify-email/verify-email.component.ts
Normal file
16
src/app/account/verify-email/verify-email.component.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-verify-email',
|
||||||
|
templateUrl: './verify-email.component.html',
|
||||||
|
styleUrls: ['./verify-email.component.scss']
|
||||||
|
})
|
||||||
|
export class VerifyEmailComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,26 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
const routes: Routes = [];
|
//Accounting
|
||||||
|
import { SignInComponent } from './account/sign-in/sign-in.component';
|
||||||
|
import { SignUpComponent } from './account/sign-up/sign-up.component';
|
||||||
|
import { ForgotPasswordComponent } from './account/forgot-password/forgot-password.component';
|
||||||
|
import { VerifyEmailComponent } from './account/verify-email/verify-email.component';
|
||||||
|
|
||||||
|
//Guard
|
||||||
|
import { AuthGuard } from './guard/auth.guard';
|
||||||
|
|
||||||
|
// Page
|
||||||
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: '', redirectTo: '/sign-in', pathMatch: 'full' },
|
||||||
|
{ path: 'sign-in', component: SignInComponent },
|
||||||
|
{ path: 'register-user', component: SignUpComponent },
|
||||||
|
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'forgot-password', component: ForgotPasswordComponent },
|
||||||
|
{ path: 'verify-email-address', component: VerifyEmailComponent },
|
||||||
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
|
|
@ -1,5 +1 @@
|
||||||
|
<router-outlet></router-outlet>
|
||||||
<app-header>dfsfs</app-header>
|
|
||||||
|
|
||||||
|
|
||||||
<app-firebase-auth></app-firebase-auth>
|
|
|
@ -8,21 +8,32 @@ import { MatButtonModule } from '@angular/material/button';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
// Firebase service
|
// Firebase service
|
||||||
import { FirebaseAuthComponent } from './firebase-auth/firebase-auth.component';
|
|
||||||
import { AngularFireModule } from '@angular/fire/compat';
|
import { AngularFireModule } from '@angular/fire/compat';
|
||||||
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
|
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
|
||||||
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
|
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
|
||||||
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
|
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
|
||||||
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
|
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
|
import { AuthService } from './services/auth.service';
|
||||||
|
|
||||||
|
|
||||||
|
import { SignInComponent } from './account/sign-in/sign-in.component';
|
||||||
|
import { SignUpComponent } from './account/sign-up/sign-up.component';
|
||||||
|
import { ForgotPasswordComponent } from './account/forgot-password/forgot-password.component';
|
||||||
|
import { VerifyEmailComponent } from './account/verify-email/verify-email.component';
|
||||||
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
|
||||||
|
|
||||||
import { HeaderComponent } from './header/header.component';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
FirebaseAuthComponent,
|
SignInComponent,
|
||||||
HeaderComponent
|
SignUpComponent,
|
||||||
|
ForgotPasswordComponent,
|
||||||
|
VerifyEmailComponent,
|
||||||
|
DashboardComponent,
|
||||||
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -36,7 +47,7 @@ import { HeaderComponent } from './header/header.component';
|
||||||
AngularFireStorageModule,
|
AngularFireStorageModule,
|
||||||
AngularFireDatabaseModule,
|
AngularFireDatabaseModule,
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [AuthService],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
52
src/app/dashboard/dashboard.component.html
Normal file
52
src/app/dashboard/dashboard.component.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<!-- Top navigation -->
|
||||||
|
<nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
|
||||||
|
<a class="navbar-brand col-sm-3 col-md-2 mr-0">
|
||||||
|
<img class="brand-logo" src="assets/logo-positronx-white.svg" alt="positronX.io Logo">
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
<!-- Sidebar navigation -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<nav class="col-md-2 d-md-block bg-light sidebar">
|
||||||
|
<div class="sidebar-sticky">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active">
|
||||||
|
<i class="fas fa-user"></i>User Profile
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<!-- Calling SignOut() Api from AuthService -->
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" (click)="authService.SignOut()">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>Log out
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<!-- Main content -->
|
||||||
|
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
|
||||||
|
<div class="inner-adjust">
|
||||||
|
<div class="pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h1 class="h2">User Profile</h1>
|
||||||
|
</div>
|
||||||
|
<!-- Show user data when logged in -->
|
||||||
|
<div class="row" *ngIf="authService.userData as user">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="media">
|
||||||
|
<img class="align-self-start mr-5 img-thumbnail rounded-circle"
|
||||||
|
src="{{(user.photoURL) ? user.photoURL : '/assets/dummy-user.png'}}"
|
||||||
|
alt="{{user.displayName}}">
|
||||||
|
<div class="media-body">
|
||||||
|
<h1>Hello: <strong>{{(user.displayName) ? user.displayName : 'User'}}</strong></h1>
|
||||||
|
<p>User ID: <strong>{{user.uid}}</strong></p>
|
||||||
|
<p>Email: <strong>{{user.email}}</strong></p>
|
||||||
|
<p>Email Verified: <strong>{{user.emailVerified}}</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
0
src/app/dashboard/dashboard.component.scss
Normal file
0
src/app/dashboard/dashboard.component.scss
Normal file
23
src/app/dashboard/dashboard.component.spec.ts
Normal file
23
src/app/dashboard/dashboard.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
|
||||||
|
describe('DashboardComponent', () => {
|
||||||
|
let component: DashboardComponent;
|
||||||
|
let fixture: ComponentFixture<DashboardComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ DashboardComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DashboardComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
16
src/app/dashboard/dashboard.component.ts
Normal file
16
src/app/dashboard/dashboard.component.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from '../services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dashboard',
|
||||||
|
templateUrl: './dashboard.component.html',
|
||||||
|
styleUrls: ['./dashboard.component.scss']
|
||||||
|
})
|
||||||
|
export class DashboardComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
<div class="main">
|
|
||||||
<div class="loginContainer">
|
|
||||||
<mat-form-field class="inputField" appearance="fill">
|
|
||||||
<mat-label>Username</mat-label>
|
|
||||||
<input matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="inputField" appearance="fill">
|
|
||||||
<mat-label>Password</mat-label>
|
|
||||||
<input matInput>
|
|
||||||
</mat-form-field>
|
|
||||||
<button mat-button color="primary">Login</button>
|
|
||||||
<button mat-button color="primary">Sign up</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,29 +0,0 @@
|
||||||
.main{
|
|
||||||
background-color: rgb(58, 104, 191);
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loginContainer{
|
|
||||||
background-color: cornflowerblue;
|
|
||||||
border: 2px solid rgb(121, 120, 120);
|
|
||||||
border-radius: 15px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 50%;
|
|
||||||
height: 50%;
|
|
||||||
padding:20px;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inputField{
|
|
||||||
background-color: transparent;
|
|
||||||
width: 80%;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";
|
|
||||||
import { initializeApp } from "firebase/app";
|
|
||||||
import { getAnalytics } from "firebase/analytics";
|
|
||||||
@Component({
|
|
||||||
selector: 'app-firebase-auth',
|
|
||||||
templateUrl: './firebase-auth.component.html',
|
|
||||||
styleUrls: ['./firebase-auth.component.scss']
|
|
||||||
})
|
|
||||||
export class FirebaseAuthComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
16
src/app/guard/auth.guard.spec.ts
Normal file
16
src/app/guard/auth.guard.spec.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AuthGuard } from './auth.guard';
|
||||||
|
|
||||||
|
describe('AuthGuard', () => {
|
||||||
|
let guard: AuthGuard;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
guard = TestBed.inject(AuthGuard);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(guard).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
22
src/app/guard/auth.guard.ts
Normal file
22
src/app/guard/auth.guard.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { AuthService } from '../services/auth.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(public authService: AuthService, public router: Router) { }
|
||||||
|
|
||||||
|
canActivate(
|
||||||
|
next: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
||||||
|
if (this.authService.isLoggetIn !== true) {
|
||||||
|
this.router.navigate(['sign-in'])
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<p>header works!</p>
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-header',
|
|
||||||
templateUrl: './header.component.html',
|
|
||||||
styleUrls: ['./header.component.scss']
|
|
||||||
})
|
|
||||||
export class HeaderComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
16
src/app/services/auth.service.spec.ts
Normal file
16
src/app/services/auth.service.spec.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
129
src/app/services/auth.service.ts
Normal file
129
src/app/services/auth.service.ts
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import { Injectable, NgZone } from '@angular/core';
|
||||||
|
import { AngularFireAuth } from '@angular/fire/compat/auth';
|
||||||
|
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/compat/firestore';
|
||||||
|
import * as auth from 'firebase/auth';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { User } from './user';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthService {
|
||||||
|
userData: any;
|
||||||
|
|
||||||
|
|
||||||
|
// Inject Firestore service, Firebase auth service, NgZone service to remove outside scope warning
|
||||||
|
constructor(public firestore: AngularFirestore, public authentication: AngularFireAuth, public router: Router, public ngZone: NgZone) {
|
||||||
|
/* Saving user data in localstorage when
|
||||||
|
logged in and setting up null when logged out */
|
||||||
|
|
||||||
|
this.authentication.authState.subscribe((user) => {
|
||||||
|
if (user) {
|
||||||
|
this.userData = user;
|
||||||
|
localStorage.setItem('user', JSON.stringify(this.userData));
|
||||||
|
JSON.parse(localStorage.getItem('user')!);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('user', 'null');
|
||||||
|
JSON.parse(localStorage.getItem('user')!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Sign in with email/password
|
||||||
|
SignIn(email: string, password: string) {
|
||||||
|
return this.authentication
|
||||||
|
.signInWithEmailAndPassword(email, password)
|
||||||
|
.then((result) => {
|
||||||
|
this.SetUserData(result.user);
|
||||||
|
this.authentication.authState.subscribe((user) => {
|
||||||
|
if (user) {
|
||||||
|
this.router.navigate(['dashboard']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
window.alert(error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Sign up with email/password
|
||||||
|
SignUp(email: string, password: string) {
|
||||||
|
return this.authentication
|
||||||
|
.createUserWithEmailAndPassword(email, password)
|
||||||
|
.then((result) => {
|
||||||
|
/* Call the SendVerificaitonMail() function when new user sign
|
||||||
|
up and returns promise */
|
||||||
|
this.SendVerificationMail();
|
||||||
|
this.SetUserData(result.user);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
window.alert(error.message)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send email verfificaiton when new user sign up
|
||||||
|
SendVerificationMail() {
|
||||||
|
return this.authentication.currentUser
|
||||||
|
.then((u: any) => u.sendEmailVerification())
|
||||||
|
.then(() => {
|
||||||
|
this.router.navigate(['verify-email-address']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Reset Forggot password
|
||||||
|
ForgotPassword(passwordResetEmail: string) {
|
||||||
|
return this.authentication
|
||||||
|
.sendPasswordResetEmail(passwordResetEmail)
|
||||||
|
.then(() => {
|
||||||
|
window.alert('Password reset mail sent, check your inbox.');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
window.alert(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Returns true when user is looged in and email is verified
|
||||||
|
get isLoggetIn(): boolean {
|
||||||
|
const user = JSON.parse(localStorage.getItem('user')!);
|
||||||
|
return (user !== null && user.emailVerified !== false) ? true : false;
|
||||||
|
}
|
||||||
|
// Sign in with Google
|
||||||
|
GoogleAuth() {
|
||||||
|
return this.AuthLogin(new auth.GoogleAuthProvider()).then((res: any) => {
|
||||||
|
this.router.navigate(['dashboard']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Auth logic to run auth providers
|
||||||
|
AuthLogin(provider: any) {
|
||||||
|
return this.authentication
|
||||||
|
.signInWithPopup(provider)
|
||||||
|
.then((result) => {
|
||||||
|
this.router.navigate(['dashboard']);
|
||||||
|
this.SetUserData(result.user);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
window.alert(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/* Setting up user data when sign in with username/password,
|
||||||
|
sign up with username/password and sign in with social auth
|
||||||
|
provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
|
||||||
|
SetUserData(user: any) {
|
||||||
|
const userRef: AngularFirestoreDocument<any> = this.firestore.doc(
|
||||||
|
`users/${user.uid}`
|
||||||
|
);
|
||||||
|
const userData: User = {
|
||||||
|
uid: user.uid,
|
||||||
|
email: user.email,
|
||||||
|
displayName: user.displayName,
|
||||||
|
photoURL: user.photoURL,
|
||||||
|
emailVerified: user.emailVerified,
|
||||||
|
};
|
||||||
|
return userRef.set(userData, {
|
||||||
|
merge: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SignOut() {
|
||||||
|
return this.authentication.signOut().then(() => {
|
||||||
|
localStorage.removeItem('user');
|
||||||
|
this.router.navigate(['sign-in'])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
7
src/app/services/user.ts
Normal file
7
src/app/services/user.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export interface User {
|
||||||
|
uid: string;
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
photoURL: string;
|
||||||
|
emailVerified: boolean;
|
||||||
|
}
|
686
src/styles.scss
686
src/styles.scss
|
@ -1,39 +1,663 @@
|
||||||
|
@import "https://use.fontawesome.com/releases/v5.5.0/css/all.css";
|
||||||
|
|
||||||
// Custom Theming for Angular Material
|
* {
|
||||||
// For more information: https://material.angular.io/guide/theming
|
-webkit-box-sizing: border-box;
|
||||||
@use '@angular/material' as mat;
|
-moz-box-sizing: border-box;
|
||||||
// Plus imports for other components in your app.
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
// Include the common styles for Angular Material. We include this here so that you only
|
html,
|
||||||
// have to load a single css file for Angular Material in your app.
|
body {
|
||||||
// Be sure that you only ever include this mixin once!
|
margin: 0;
|
||||||
@include mat.core();
|
padding: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
.feather {
|
||||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
width: 16px;
|
||||||
// hue. Available color palettes: https://material.io/design/color/
|
height: 16px;
|
||||||
$Angular_Firebase_Login-primary: mat.define-palette(mat.$indigo-palette);
|
vertical-align: text-bottom;
|
||||||
$Angular_Firebase_Login-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
|
}
|
||||||
|
|
||||||
// The warn palette is optional (defaults to red).
|
h1,
|
||||||
$Angular_Firebase_Login-warn: mat.define-palette(mat.$red-palette);
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the theme object. A theme consists of configurations for individual
|
.media-body h1 {
|
||||||
// theming systems such as "color" or "typography".
|
font-weight: 300;
|
||||||
$Angular_Firebase_Login-theme: mat.define-light-theme((
|
margin-bottom: 20px;
|
||||||
color: (
|
}
|
||||||
primary: $Angular_Firebase_Login-primary,
|
|
||||||
accent: $Angular_Firebase_Login-accent,
|
|
||||||
warn: $Angular_Firebase_Login-warn,
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
// Include theme styles for core and each component used in your app.
|
.media-body h1 strong {
|
||||||
// Alternatively, you can import and @include the theme mixins for each component
|
font-weight: 600;
|
||||||
// that you are using.
|
}
|
||||||
@include mat.all-component-themes($Angular_Firebase_Login-theme);
|
|
||||||
|
|
||||||
/* You can add global styles to this file, and also import other style files */
|
.media-body p {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
html, body { height: 100%; }
|
.media-body p strong {
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
margin-bottom: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-logo {
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
margin: 0 auto 20px;
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-logo a img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #12056d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTableCell {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22px;
|
||||||
|
margin: 0 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.authBlock {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 400px;
|
||||||
|
background: white;
|
||||||
|
padding: 30px 40px 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.04);
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formGroup {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formControl {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
padding: 15px 15px 14px;
|
||||||
|
border: 2px solid #e7e7e7;
|
||||||
|
outline: none;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #444444;
|
||||||
|
background: #fcfcfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formControl:focus {
|
||||||
|
border: 2px solid #d3d3d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
input::-webkit-input-placeholder {
|
||||||
|
color: #bbbbbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
input::-moz-placeholder {
|
||||||
|
color: #bbbbbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-ms-input-placeholder {
|
||||||
|
color: #bbbbbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-moz-placeholder {
|
||||||
|
color: #bbbbbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable .btn {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 15px 0;
|
||||||
|
background: #f96ea8;
|
||||||
|
color: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable .btn:hover {
|
||||||
|
opacity: 0.88;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable .btnSecondary {
|
||||||
|
background: #eeeeee;
|
||||||
|
color: #404040;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable .googleBtn {
|
||||||
|
background: #4dd5fe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable .facebookBtn {
|
||||||
|
background: #4dd5fe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.or {
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
color: #a0a0a0;
|
||||||
|
background: white;
|
||||||
|
position: relative;
|
||||||
|
margin: 5px 0 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orInner {
|
||||||
|
background: white;
|
||||||
|
display: inline-block;
|
||||||
|
z-index: 4;
|
||||||
|
position: relative;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.or:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
left: 0;
|
||||||
|
top: 11px;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background: #e2e2e2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.halfWidth {
|
||||||
|
width: 48.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgotPassword {
|
||||||
|
text-align: center;
|
||||||
|
margin: -12px 0 15px 0;
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgotPassword span {
|
||||||
|
color: #4dd5fe;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.redirectToLogin {
|
||||||
|
padding: 15px 0 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: block;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.redirectToLogin .redirect {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * Sidebar */
|
||||||
|
.sidebar {
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 48px 0 0;
|
||||||
|
box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
height: calc(100vh - 48px);
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports ((position: -webkit-sticky) or (position: sticky)) {
|
||||||
|
.sidebar-sticky {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link .feather {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-heading {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
padding: 1.5rem 1rem;
|
||||||
|
border-bottom: 1px solid #dde0e2;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .nav-link.active,
|
||||||
|
.sidebar a:hover,
|
||||||
|
a:not([href]):not([tabindex]):focus,
|
||||||
|
a:not([href]):not([tabindex]):hover {
|
||||||
|
color: #e91e63;
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * Content */
|
||||||
|
[role="main"] {
|
||||||
|
padding-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dasboard-text {
|
||||||
|
border-left: 1px solid rgb(255, 255, 255, 0.3);
|
||||||
|
color: rgb(255, 255, 255, 0.5);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0 0 14px;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-left: 15px;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* * Navbar */
|
||||||
|
.navbar-brand {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .form-control {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-width: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-dark:focus {
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
border-color: #00bcd4;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-dark {
|
||||||
|
background-color: #3f51b5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-right {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
width: 22px;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-adjust {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-block {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-block .fa-edit:hover {
|
||||||
|
color: #009688;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-block .fa-trash-alt:hover {
|
||||||
|
color: #e91e63;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary.focus,
|
||||||
|
.btn-primary:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pagination */
|
||||||
|
body pagination-template {
|
||||||
|
padding: 0;
|
||||||
|
margin: 8px 0 0;
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .ngx-pagination li:last-child {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .ngx-pagination .current {
|
||||||
|
background: #055af9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ngx-pagination a:hover,
|
||||||
|
.ngx-pagination button:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error */
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.ng-invalid.ng-touched {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success.disabled,
|
||||||
|
.btn-success:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav */
|
||||||
|
body .navbar {
|
||||||
|
padding: 6px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .navbar-brand {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-logo {
|
||||||
|
max-width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-3,
|
||||||
|
.py-3 {
|
||||||
|
padding-top: 2.4rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky {
|
||||||
|
padding-top: 1.2rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form */
|
||||||
|
label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
padding: 1.375rem 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc */
|
||||||
|
.no-data img {
|
||||||
|
max-width: 420px;
|
||||||
|
margin: 20px auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodata-msg {
|
||||||
|
margin: 25px 0 15px;
|
||||||
|
font-size: 28px;
|
||||||
|
color: #a9a6c5;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[role="main"] {
|
||||||
|
padding-top: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preloader {
|
||||||
|
min-height: 400px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #5f5f5f;
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-dark .navbar-brand {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-text strong {
|
||||||
|
color: #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-3,
|
||||||
|
.my-3 {
|
||||||
|
margin-bottom: 1.4rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-fa-plus {
|
||||||
|
margin: 0;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-image {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 50%;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 7px;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table thead th {
|
||||||
|
background: #f3f5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pricing-header {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userImage {
|
||||||
|
max-width: 125px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-dark .navbar-nav .nav-link {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
padding: 0 1.25rem 15px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-sign-out-alt {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logOutBtn {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-access {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26px;
|
||||||
|
padding: 70px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-circle {
|
||||||
|
max-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.sidebar {
|
||||||
|
position: static;
|
||||||
|
padding: 40px 0 10px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[role="main"] {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-adjust {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav.flex-column {
|
||||||
|
flex-direction: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-3,
|
||||||
|
.py-3 {
|
||||||
|
padding-top: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-logo {
|
||||||
|
max-width: 175px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dasboard-text {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky {
|
||||||
|
padding-top: 1.9rem !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky .nav li {
|
||||||
|
width: 50%;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 1px solid #c7ceff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-sticky .nav li:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data img {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodata-msg,
|
||||||
|
.h2,
|
||||||
|
h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-text {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-nav {
|
||||||
|
float: right;
|
||||||
|
width: 50%;
|
||||||
|
text-align: right;
|
||||||
|
display: inherit;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-dark .navbar-brand {
|
||||||
|
margin: 0;
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
padding: 40px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer br {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-circle {
|
||||||
|
max-width: 150px;
|
||||||
|
margin: 0 auto 20px !important;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayTable {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.authBlock {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user