all done, need to fix routing to Dashboard

This commit is contained in:
marcusferl@weifer.de 2022-09-16 11:10:18 +02:00
parent 11a4b0fc86
commit ea41ebf364
35 changed files with 1203 additions and 134 deletions

View File

@ -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": []

View File

@ -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>

View File

@ -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();
});
});

View 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 {
}
}

View 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>

View 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();
}); });

View 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 {
}
}

View 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>

View 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();
}); });

View 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 {
}
}

View 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>

View 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();
});
});

View 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 {
}
}

View File

@ -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)],

View File

@ -1,5 +1 @@
<router-outlet></router-outlet>
<app-header>dfsfs</app-header>
<app-firebase-auth></app-firebase-auth>

View File

@ -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 { }

View 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>

View 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();
});
});

View 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 {
}
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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 {
}
}

View 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();
});
});

View 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;
}
}

View File

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

View File

@ -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 {
}
}

View 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();
});
});

View 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
View File

@ -0,0 +1,7 @@
export interface User {
uid: string;
email: string;
displayName: string;
photoURL: string;
emailVerified: boolean;
}

View File

@ -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;
}
}