72 changed files with 25437 additions and 16087 deletions
File diff suppressed because it is too large
@ -0,0 +1,52 @@ |
|||||
|
export interface DashSummary { |
||||
|
summary:Summary; |
||||
|
views:ProductViews[]; |
||||
|
recent:Transactions[]; |
||||
|
visitorsCurrent:MonthVisits[]; |
||||
|
visitorsPrevious:MonthVisits[]; |
||||
|
redemptions:MonthRates[]; |
||||
|
visits:MonthRates[]; |
||||
|
sales:MonthRates[]; |
||||
|
} |
||||
|
|
||||
|
export interface Summary { |
||||
|
totalVisits: number; |
||||
|
couponRedeemed: number; |
||||
|
totalSales: number; |
||||
|
totalFreebie: number; |
||||
|
totalProximity: number; |
||||
|
totalDiscount: number; |
||||
|
visitLastMonth:number; |
||||
|
redemptionsLastMonth:number; |
||||
|
salesLastMonth:number; |
||||
|
} |
||||
|
|
||||
|
export interface Transactions { |
||||
|
userGuid: String; |
||||
|
firstname: String; |
||||
|
surname: String; |
||||
|
timestamp: Date; |
||||
|
productName: String; |
||||
|
countId: number; |
||||
|
worth: number; |
||||
|
paid: number |
||||
|
} |
||||
|
export interface ProductViews { |
||||
|
userGuid: String; |
||||
|
firstname: String; |
||||
|
surname: String; |
||||
|
timesViewed: number; |
||||
|
pname: String; |
||||
|
productId: String; |
||||
|
picture: String; |
||||
|
} |
||||
|
export interface MonthVisits{ |
||||
|
evisits:number; |
||||
|
inshop:number; |
||||
|
month:number; |
||||
|
year:number; |
||||
|
} |
||||
|
export interface MonthRates{ |
||||
|
day:number; |
||||
|
rate:number; |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
.users-row { |
||||
|
cursor: pointer; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#circle { |
||||
|
background: #00a4be; |
||||
|
width: 45px; |
||||
|
height: 45px; |
||||
|
min-width: 45px; |
||||
|
border-radius: 64px; |
||||
|
color: #003445; |
||||
|
font-weight: bold; |
||||
|
text-align: center; |
||||
|
justify-content: center; |
||||
|
display: flex; |
||||
|
align-content: center; |
||||
|
align-items: center; |
||||
|
font-size: initial; |
||||
|
margin-right: 15px; |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,4 @@ |
|||||
|
<img [src]="image" class="productImage"> |
||||
|
<a class="btn btn-primary" [href]="image" download style="display: flex;justify-content: center;"> |
||||
|
<button mat-button style="background-color: #0152cc;color: white;" >Download</button> |
||||
|
</a> |
@ -0,0 +1,25 @@ |
|||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
|
||||
|
import { QrcodeDialogComponent } from './qrcode-dialog.component'; |
||||
|
|
||||
|
describe('QrcodeDialogComponent', () => { |
||||
|
let component: QrcodeDialogComponent; |
||||
|
let fixture: ComponentFixture<QrcodeDialogComponent>; |
||||
|
|
||||
|
beforeEach(async () => { |
||||
|
await TestBed.configureTestingModule({ |
||||
|
declarations: [ QrcodeDialogComponent ] |
||||
|
}) |
||||
|
.compileComponents(); |
||||
|
}); |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
fixture = TestBed.createComponent(QrcodeDialogComponent); |
||||
|
component = fixture.componentInstance; |
||||
|
fixture.detectChanges(); |
||||
|
}); |
||||
|
|
||||
|
it('should create', () => { |
||||
|
expect(component).toBeTruthy(); |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,20 @@ |
|||||
|
import { Component, Inject, OnInit } from '@angular/core'; |
||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; |
||||
|
import { DomSanitizer } from '@angular/platform-browser'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-qrcode-dialog', |
||||
|
templateUrl: './qrcode-dialog.component.html', |
||||
|
styleUrls: ['./qrcode-dialog.component.scss'] |
||||
|
}) |
||||
|
export class QrcodeDialogComponent implements OnInit { |
||||
|
image: any = ""; |
||||
|
constructor(@Inject(MAT_DIALOG_DATA) public data: { image: string }, private domSanitizer: DomSanitizer, |
||||
|
public dialogRef: MatDialogRef<QrcodeDialogComponent>) { |
||||
|
this.image = this.domSanitizer.bypassSecurityTrustUrl(data.image); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
} |
||||
|
|
||||
|
} |
@ -1,62 +0,0 @@ |
|||||
<div class="flex flex-col sm:flex-row items-center md:items-start sm:justify-center md:justify-start flex-auto min-w-0"> |
|
||||
<div class="md:flex md:items-center md:justify-end w-full sm:w-auto md:h-full md:w-1/2 py-8 px-4 sm:p-12 md:p-16 sm:rounded-2xl md:rounded-none sm:shadow md:shadow-none sm:bg-card"> |
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-12"> |
|
||||
<img src="assets/images/logo/logo.svg"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Confirmation required</div> |
|
||||
<div class="mt-4"> |
|
||||
A confirmation mail with instructions has been sent to your email address. Follow those instructions to confirm your email address and activate your account. |
|
||||
</div> |
|
||||
|
|
||||
<!-- Form footer --> |
|
||||
<div class="mt-8 text-md font-medium text-secondary"> |
|
||||
<span>Return to</span> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['/sign-in']">sign in |
|
||||
</a> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="relative hidden md:flex flex-auto items-center justify-center w-1/2 h-full p-16 lg:px-28 overflow-hidden bg-gray-800 dark:border-l"> |
|
||||
<!-- Background - @formatter:off --> |
|
||||
<!-- Rings --> |
|
||||
<svg class="absolute inset-0 pointer-events-none" viewBox="0 0 960 540" width="100%" height="100%" preserveAspectRatio="xMidYMax slice" xmlns="http://www.w3.org/2000/svg"> |
|
||||
<g class="text-gray-700 opacity-25" fill="none" stroke="currentColor" stroke-width="100"> |
|
||||
<circle r="234" cx="196" cy="23"></circle> |
|
||||
<circle r="234" cx="790" cy="491"></circle> |
|
||||
</g> |
|
||||
</svg> |
|
||||
<!-- Dots --> |
|
||||
<svg class="absolute -top-16 -right-16 text-gray-700" viewBox="0 0 220 192" width="220" height="192" fill="none"> |
|
||||
<defs> |
|
||||
<pattern id="837c3e70-6c3a-44e6-8854-cc48c737b659" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse"> |
|
||||
<rect x="0" y="0" width="4" height="4" fill="currentColor"></rect> |
|
||||
</pattern> |
|
||||
</defs> |
|
||||
<rect width="220" height="192" fill="url(#837c3e70-6c3a-44e6-8854-cc48c737b659)"></rect> |
|
||||
</svg> |
|
||||
<!-- @formatter:on --> |
|
||||
<!-- Content --> |
|
||||
<div class="z-10 relative w-full max-w-2xl"> |
|
||||
<div class="text-7xl font-bold leading-none text-gray-100"> |
|
||||
<div>Welcome to</div> |
|
||||
<div>our community</div> |
|
||||
</div> |
|
||||
<div class="mt-6 text-lg tracking-tight leading-6 text-gray-400"> |
|
||||
teso helps developers to build organized and well coded dashboards full of beautiful and rich modules. Join us and start building your application today. |
|
||||
</div> |
|
||||
<div class="flex items-center mt-8"> |
|
||||
<div class="flex flex-0 items-center -space-x-1.5"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-18.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-11.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-09.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-16.jpg"> |
|
||||
</div> |
|
||||
<div class="ml-4 font-medium tracking-tight text-gray-400">More than 17k people joined us, it's your turn</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
@ -1,18 +0,0 @@ |
|||||
import { Component, ViewEncapsulation } from '@angular/core'; |
|
||||
import { tesoAnimations } from '@teso/animations'; |
|
||||
|
|
||||
@Component({ |
|
||||
selector : 'auth-confirmation-required', |
|
||||
templateUrl : './confirmation-required.component.html', |
|
||||
encapsulation: ViewEncapsulation.None, |
|
||||
animations : tesoAnimations |
|
||||
}) |
|
||||
export class AuthConfirmationRequiredComponent |
|
||||
{ |
|
||||
/** |
|
||||
* Constructor |
|
||||
*/ |
|
||||
constructor() |
|
||||
{ |
|
||||
} |
|
||||
} |
|
@ -1,22 +0,0 @@ |
|||||
import { NgModule } from '@angular/core'; |
|
||||
import { RouterModule } from '@angular/router'; |
|
||||
import { MatButtonModule } from '@angular/material/button'; |
|
||||
import { tesoCardModule } from '@teso/components/card'; |
|
||||
import { SharedModule } from 'app/shared/shared.module'; |
|
||||
import { AuthConfirmationRequiredComponent } from 'app/pages/auth/confirmation-required/confirmation-required.component'; |
|
||||
import { authConfirmationRequiredRoutes } from 'app/pages/auth/confirmation-required/confirmation-required.routing'; |
|
||||
|
|
||||
@NgModule({ |
|
||||
declarations: [ |
|
||||
AuthConfirmationRequiredComponent |
|
||||
], |
|
||||
imports : [ |
|
||||
RouterModule.forChild(authConfirmationRequiredRoutes), |
|
||||
MatButtonModule, |
|
||||
tesoCardModule, |
|
||||
SharedModule |
|
||||
] |
|
||||
}) |
|
||||
export class AuthConfirmationRequiredModule |
|
||||
{ |
|
||||
} |
|
@ -1,9 +0,0 @@ |
|||||
import { Route } from '@angular/router'; |
|
||||
import { AuthConfirmationRequiredComponent } from 'app/pages/auth/confirmation-required/confirmation-required.component'; |
|
||||
|
|
||||
export const authConfirmationRequiredRoutes: Route[] = [ |
|
||||
{ |
|
||||
path : '', |
|
||||
component: AuthConfirmationRequiredComponent |
|
||||
} |
|
||||
]; |
|
@ -1,93 +0,0 @@ |
|||||
<div class="flex flex-col sm:flex-row items-center md:items-start sm:justify-center md:justify-start flex-auto min-w-0"> |
|
||||
<div class="md:flex md:items-center md:justify-end w-full sm:w-auto md:h-full md:w-1/2 py-8 px-4 sm:p-12 md:p-16 sm:rounded-2xl md:rounded-none sm:shadow md:shadow-none sm:bg-card"> |
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-12"> |
|
||||
<img src="assets/images/logo/logo.svg"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Forgot password?</div> |
|
||||
<div class="mt-0.5 font-medium">Fill the form to reset your password</div> |
|
||||
|
|
||||
<!-- Alert --> |
|
||||
<teso-alert class="mt-8 -mb-4" *ngIf="showAlert" [appearance]="'outline'" [showIcon]="false" [type]="alert.type" [@shake]="alert.type === 'error'"> |
|
||||
{{alert.message}} |
|
||||
</teso-alert> |
|
||||
|
|
||||
<!-- Forgot password form --> |
|
||||
<form class="mt-8" [formGroup]="forgotPasswordForm" #forgotPasswordNgForm="ngForm"> |
|
||||
|
|
||||
<!-- Email field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Email address</mat-label> |
|
||||
<input id="email" matInput [formControlName]="'email'"> |
|
||||
<mat-error *ngIf="forgotPasswordForm.get('email').hasError('required')"> |
|
||||
Email address is required |
|
||||
</mat-error> |
|
||||
<mat-error *ngIf="forgotPasswordForm.get('email').hasError('email')"> |
|
||||
Please enter a valid email address |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Submit button --> |
|
||||
<button class="teso-mat-button-large w-full mt-3" mat-flat-button [color]="'primary'" [disabled]="forgotPasswordForm.disabled" (click)="sendResetLink()"> |
|
||||
<span *ngIf="!forgotPasswordForm.disabled"> |
|
||||
Send reset link |
|
||||
</span> |
|
||||
<mat-progress-spinner |
|
||||
*ngIf="forgotPasswordForm.disabled" |
|
||||
[diameter]="24" |
|
||||
[mode]="'indeterminate'"></mat-progress-spinner> |
|
||||
</button> |
|
||||
|
|
||||
<!-- Form footer --> |
|
||||
<div class="mt-8 text-md font-medium text-secondary"> |
|
||||
<span>Return to</span> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['/sign-in']">sign in |
|
||||
</a> |
|
||||
</div> |
|
||||
|
|
||||
</form> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="relative hidden md:flex flex-auto items-center justify-center w-1/2 h-full p-16 lg:px-28 overflow-hidden bg-gray-800 dark:border-l"> |
|
||||
<!-- Background - @formatter:off --> |
|
||||
<!-- Rings --> |
|
||||
<svg class="absolute inset-0 pointer-events-none" viewBox="0 0 960 540" width="100%" height="100%" preserveAspectRatio="xMidYMax slice" xmlns="http://www.w3.org/2000/svg"> |
|
||||
<g class="text-gray-700 opacity-25" fill="none" stroke="currentColor" stroke-width="100"> |
|
||||
<circle r="234" cx="196" cy="23"></circle> |
|
||||
<circle r="234" cx="790" cy="491"></circle> |
|
||||
</g> |
|
||||
</svg> |
|
||||
<!-- Dots --> |
|
||||
<svg class="absolute -top-16 -right-16 text-gray-700" viewBox="0 0 220 192" width="220" height="192" fill="none"> |
|
||||
<defs> |
|
||||
<pattern id="837c3e70-6c3a-44e6-8854-cc48c737b659" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse"> |
|
||||
<rect x="0" y="0" width="4" height="4" fill="currentColor"></rect> |
|
||||
</pattern> |
|
||||
</defs> |
|
||||
<rect width="220" height="192" fill="url(#837c3e70-6c3a-44e6-8854-cc48c737b659)"></rect> |
|
||||
</svg> |
|
||||
<!-- @formatter:on --> |
|
||||
<!-- Content --> |
|
||||
<div class="z-10 relative w-full max-w-2xl"> |
|
||||
<div class="text-7xl font-bold leading-none text-gray-100"> |
|
||||
<div>Welcome to</div> |
|
||||
<div>our community</div> |
|
||||
</div> |
|
||||
<div class="mt-6 text-lg tracking-tight leading-6 text-gray-400"> |
|
||||
teso helps developers to build organized and well coded dashboards full of beautiful and rich modules. Join us and start building your application today. |
|
||||
</div> |
|
||||
<div class="flex items-center mt-8"> |
|
||||
<div class="flex flex-0 items-center -space-x-1.5"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-18.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-11.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-09.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-16.jpg"> |
|
||||
</div> |
|
||||
<div class="ml-4 font-medium tracking-tight text-gray-400">More than 17k people joined us, it's your turn</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
@ -1,105 +0,0 @@ |
|||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; |
|
||||
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; |
|
||||
import { finalize } from 'rxjs/operators'; |
|
||||
import { tesoAnimations } from '@teso/animations'; |
|
||||
import { tesoAlertType } from '@teso/components/alert'; |
|
||||
import { AuthService } from 'app/core/auth/auth.service'; |
|
||||
|
|
||||
@Component({ |
|
||||
selector : 'auth-forgot-password', |
|
||||
templateUrl : './forgot-password.component.html', |
|
||||
encapsulation: ViewEncapsulation.None, |
|
||||
animations : tesoAnimations |
|
||||
}) |
|
||||
export class AuthForgotPasswordComponent implements OnInit |
|
||||
{ |
|
||||
@ViewChild('forgotPasswordNgForm') forgotPasswordNgForm: NgForm; |
|
||||
|
|
||||
alert: { type: tesoAlertType; message: string } = { |
|
||||
type : 'success', |
|
||||
message: '' |
|
||||
}; |
|
||||
forgotPasswordForm: FormGroup; |
|
||||
showAlert: boolean = false; |
|
||||
|
|
||||
/** |
|
||||
* Constructor |
|
||||
*/ |
|
||||
constructor( |
|
||||
private _authService: AuthService, |
|
||||
private _formBuilder: FormBuilder |
|
||||
) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Lifecycle hooks
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* On init |
|
||||
*/ |
|
||||
ngOnInit(): void |
|
||||
{ |
|
||||
// Create the form
|
|
||||
this.forgotPasswordForm = this._formBuilder.group({ |
|
||||
email: ['', [Validators.required, Validators.email]] |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Public methods
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* Send the reset link |
|
||||
*/ |
|
||||
sendResetLink(): void |
|
||||
{ |
|
||||
// Return if the form is invalid
|
|
||||
if ( this.forgotPasswordForm.invalid ) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Disable the form
|
|
||||
this.forgotPasswordForm.disable(); |
|
||||
|
|
||||
// Hide the alert
|
|
||||
this.showAlert = false; |
|
||||
|
|
||||
// Forgot password
|
|
||||
this._authService.forgotPassword(this.forgotPasswordForm.get('email').value) |
|
||||
.pipe( |
|
||||
finalize(() => { |
|
||||
|
|
||||
// Re-enable the form
|
|
||||
this.forgotPasswordForm.enable(); |
|
||||
|
|
||||
// Reset the form
|
|
||||
this.forgotPasswordNgForm.resetForm(); |
|
||||
|
|
||||
// Show the alert
|
|
||||
this.showAlert = true; |
|
||||
}) |
|
||||
) |
|
||||
.subscribe( |
|
||||
(response) => { |
|
||||
|
|
||||
// Set the alert
|
|
||||
this.alert = { |
|
||||
type : 'success', |
|
||||
message: 'Password reset sent! You\'ll receive an email if you are registered on our system.' |
|
||||
}; |
|
||||
}, |
|
||||
(response) => { |
|
||||
|
|
||||
// Set the alert
|
|
||||
this.alert = { |
|
||||
type : 'error', |
|
||||
message: 'Email does not found! Are you sure you are already a member?' |
|
||||
}; |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -1,32 +0,0 @@ |
|||||
import { NgModule } from '@angular/core'; |
|
||||
import { RouterModule } from '@angular/router'; |
|
||||
import { MatButtonModule } from '@angular/material/button'; |
|
||||
import { MatFormFieldModule } from '@angular/material/form-field'; |
|
||||
import { MatIconModule } from '@angular/material/icon'; |
|
||||
import { MatInputModule } from '@angular/material/input'; |
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; |
|
||||
import { tesoCardModule } from '@teso/components/card'; |
|
||||
import { tesoAlertModule } from '@teso/components/alert'; |
|
||||
import { SharedModule } from 'app/shared/shared.module'; |
|
||||
import { AuthForgotPasswordComponent } from 'app/pages/auth/forgot-password/forgot-password.component'; |
|
||||
import { authForgotPasswordRoutes } from 'app/pages/auth/forgot-password/forgot-password.routing'; |
|
||||
|
|
||||
@NgModule({ |
|
||||
declarations: [ |
|
||||
AuthForgotPasswordComponent |
|
||||
], |
|
||||
imports : [ |
|
||||
RouterModule.forChild(authForgotPasswordRoutes), |
|
||||
MatButtonModule, |
|
||||
MatFormFieldModule, |
|
||||
MatIconModule, |
|
||||
MatInputModule, |
|
||||
MatProgressSpinnerModule, |
|
||||
tesoCardModule, |
|
||||
tesoAlertModule, |
|
||||
SharedModule |
|
||||
] |
|
||||
}) |
|
||||
export class AuthForgotPasswordModule |
|
||||
{ |
|
||||
} |
|
@ -1,9 +0,0 @@ |
|||||
import { Route } from '@angular/router'; |
|
||||
import { AuthForgotPasswordComponent } from 'app/pages/auth/forgot-password/forgot-password.component'; |
|
||||
|
|
||||
export const authForgotPasswordRoutes: Route[] = [ |
|
||||
{ |
|
||||
path : '', |
|
||||
component: AuthForgotPasswordComponent |
|
||||
} |
|
||||
]; |
|
@ -1,122 +0,0 @@ |
|||||
<div class="flex flex-col sm:flex-row items-center md:items-start sm:justify-center md:justify-start flex-auto min-w-0"> |
|
||||
<div class="md:flex md:items-center md:justify-end w-full sm:w-auto md:h-full md:w-1/2 py-8 px-4 sm:p-12 md:p-16 sm:rounded-2xl md:rounded-none sm:shadow md:shadow-none sm:bg-card"> |
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-12"> |
|
||||
<img src="assets/images/logo/logo.svg"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Reset your password</div> |
|
||||
<div class="mt-0.5 font-medium">Create a new password for your account</div> |
|
||||
|
|
||||
<!-- Alert --> |
|
||||
<teso-alert class="mt-8 -mb-4" *ngIf="showAlert" [appearance]="'outline'" [showIcon]="false" [type]="alert.type" [@shake]="alert.type === 'error'"> |
|
||||
{{alert.message}} |
|
||||
</teso-alert> |
|
||||
|
|
||||
<!-- Reset password form --> |
|
||||
<form class="mt-8" [formGroup]="resetPasswordForm" #resetPasswordNgForm="ngForm"> |
|
||||
|
|
||||
<!-- Password field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Password</mat-label> |
|
||||
<input id="password" matInput type="password" [formControlName]="'password'" #passwordField> |
|
||||
<button mat-icon-button type="button" (click)="passwordField.type === 'password' ? passwordField.type = 'text' : passwordField.type = 'password'" matSuffix> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordField.type === 'password'" |
|
||||
[svgIcon]="'heroicons_solid:eye'"></mat-icon> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordField.type === 'text'" |
|
||||
[svgIcon]="'heroicons_solid:eye-off'"></mat-icon> |
|
||||
</button> |
|
||||
<mat-error> |
|
||||
Password is required |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Password confirm field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Password (Confirm)</mat-label> |
|
||||
<input id="password-confirm" matInput type="password" [formControlName]="'passwordConfirm'" #passwordConfirmField> |
|
||||
<button mat-icon-button type="button" (click)="passwordConfirmField.type === 'password' ? passwordConfirmField.type = 'text' : passwordConfirmField.type = 'password'" matSuffix> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordConfirmField.type === 'password'" |
|
||||
[svgIcon]="'heroicons_solid:eye'"></mat-icon> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordConfirmField.type === 'text'" |
|
||||
[svgIcon]="'heroicons_solid:eye-off'"></mat-icon> |
|
||||
</button> |
|
||||
<mat-error *ngIf="resetPasswordForm.get('passwordConfirm').hasError('required')"> |
|
||||
Password confirmation is required |
|
||||
</mat-error> |
|
||||
<mat-error *ngIf="resetPasswordForm.get('passwordConfirm').hasError('mustMatch')"> |
|
||||
Passwords must match |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Submit button --> |
|
||||
<button class="teso-mat-button-large w-full mt-3" mat-flat-button [color]="'primary'" [disabled]="resetPasswordForm.disabled" (click)="resetPassword()"> |
|
||||
<span *ngIf="!resetPasswordForm.disabled"> |
|
||||
Reset your password |
|
||||
</span> |
|
||||
<mat-progress-spinner |
|
||||
*ngIf="resetPasswordForm.disabled" |
|
||||
[diameter]="24" |
|
||||
[mode]="'indeterminate'"></mat-progress-spinner> |
|
||||
</button> |
|
||||
|
|
||||
<!-- Form footer --> |
|
||||
<div class="mt-8 text-md font-medium text-secondary"> |
|
||||
<span>Return to</span> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['/sign-in']">sign in |
|
||||
</a> |
|
||||
</div> |
|
||||
|
|
||||
</form> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="relative hidden md:flex flex-auto items-center justify-center w-1/2 h-full p-16 lg:px-28 overflow-hidden bg-gray-800 dark:border-l"> |
|
||||
<!-- Background - @formatter:off --> |
|
||||
<!-- Rings --> |
|
||||
<svg class="absolute inset-0 pointer-events-none" viewBox="0 0 960 540" width="100%" height="100%" preserveAspectRatio="xMidYMax slice" xmlns="http://www.w3.org/2000/svg"> |
|
||||
<g class="text-gray-700 opacity-25" fill="none" stroke="currentColor" stroke-width="100"> |
|
||||
<circle r="234" cx="196" cy="23"></circle> |
|
||||
<circle r="234" cx="790" cy="491"></circle> |
|
||||
</g> |
|
||||
</svg> |
|
||||
<!-- Dots --> |
|
||||
<svg class="absolute -top-16 -right-16 text-gray-700" viewBox="0 0 220 192" width="220" height="192" fill="none"> |
|
||||
<defs> |
|
||||
<pattern id="837c3e70-6c3a-44e6-8854-cc48c737b659" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse"> |
|
||||
<rect x="0" y="0" width="4" height="4" fill="currentColor"></rect> |
|
||||
</pattern> |
|
||||
</defs> |
|
||||
<rect width="220" height="192" fill="url(#837c3e70-6c3a-44e6-8854-cc48c737b659)"></rect> |
|
||||
</svg> |
|
||||
<!-- @formatter:on --> |
|
||||
<!-- Content --> |
|
||||
<div class="z-10 relative w-full max-w-2xl"> |
|
||||
<div class="text-7xl font-bold leading-none text-gray-100"> |
|
||||
<div>Welcome to</div> |
|
||||
<div>our community</div> |
|
||||
</div> |
|
||||
<div class="mt-6 text-lg tracking-tight leading-6 text-gray-400"> |
|
||||
teso helps developers to build organized and well coded dashboards full of beautiful and rich modules. Join us and start building your application today. |
|
||||
</div> |
|
||||
<div class="flex items-center mt-8"> |
|
||||
<div class="flex flex-0 items-center -space-x-1.5"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-18.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-11.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-09.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-16.jpg"> |
|
||||
</div> |
|
||||
<div class="ml-4 font-medium tracking-tight text-gray-400">More than 17k people joined us, it's your turn</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
@ -1,111 +0,0 @@ |
|||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; |
|
||||
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; |
|
||||
import { finalize } from 'rxjs/operators'; |
|
||||
import { tesoAnimations } from '@teso/animations'; |
|
||||
import { tesoValidators } from '@teso/validators'; |
|
||||
import { tesoAlertType } from '@teso/components/alert'; |
|
||||
import { AuthService } from 'app/core/auth/auth.service'; |
|
||||
|
|
||||
@Component({ |
|
||||
selector : 'auth-reset-password', |
|
||||
templateUrl : './reset-password.component.html', |
|
||||
encapsulation: ViewEncapsulation.None, |
|
||||
animations : tesoAnimations |
|
||||
}) |
|
||||
export class AuthResetPasswordComponent implements OnInit |
|
||||
{ |
|
||||
@ViewChild('resetPasswordNgForm') resetPasswordNgForm: NgForm; |
|
||||
|
|
||||
alert: { type: tesoAlertType; message: string } = { |
|
||||
type : 'success', |
|
||||
message: '' |
|
||||
}; |
|
||||
resetPasswordForm: FormGroup; |
|
||||
showAlert: boolean = false; |
|
||||
|
|
||||
/** |
|
||||
* Constructor |
|
||||
*/ |
|
||||
constructor( |
|
||||
private _authService: AuthService, |
|
||||
private _formBuilder: FormBuilder |
|
||||
) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Lifecycle hooks
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* On init |
|
||||
*/ |
|
||||
ngOnInit(): void |
|
||||
{ |
|
||||
// Create the form
|
|
||||
this.resetPasswordForm = this._formBuilder.group({ |
|
||||
password : ['', Validators.required], |
|
||||
passwordConfirm: ['', Validators.required] |
|
||||
}, |
|
||||
{ |
|
||||
validators: tesoValidators.mustMatch('password', 'passwordConfirm') |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Public methods
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* Reset password |
|
||||
*/ |
|
||||
resetPassword(): void |
|
||||
{ |
|
||||
// Return if the form is invalid
|
|
||||
if ( this.resetPasswordForm.invalid ) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Disable the form
|
|
||||
this.resetPasswordForm.disable(); |
|
||||
|
|
||||
// Hide the alert
|
|
||||
this.showAlert = false; |
|
||||
|
|
||||
// Send the request to the server
|
|
||||
this._authService.resetPassword(this.resetPasswordForm.get('password').value) |
|
||||
.pipe( |
|
||||
finalize(() => { |
|
||||
|
|
||||
// Re-enable the form
|
|
||||
this.resetPasswordForm.enable(); |
|
||||
|
|
||||
// Reset the form
|
|
||||
this.resetPasswordNgForm.resetForm(); |
|
||||
|
|
||||
// Show the alert
|
|
||||
this.showAlert = true; |
|
||||
}) |
|
||||
) |
|
||||
.subscribe( |
|
||||
(response) => { |
|
||||
|
|
||||
// Set the alert
|
|
||||
this.alert = { |
|
||||
type : 'success', |
|
||||
message: 'Your password has been reset.' |
|
||||
}; |
|
||||
}, |
|
||||
(response) => { |
|
||||
|
|
||||
// Set the alert
|
|
||||
this.alert = { |
|
||||
type : 'error', |
|
||||
message: 'Something went wrong, please try again.' |
|
||||
}; |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -1,32 +0,0 @@ |
|||||
import { NgModule } from '@angular/core'; |
|
||||
import { RouterModule } from '@angular/router'; |
|
||||
import { MatButtonModule } from '@angular/material/button'; |
|
||||
import { MatFormFieldModule } from '@angular/material/form-field'; |
|
||||
import { MatIconModule } from '@angular/material/icon'; |
|
||||
import { MatInputModule } from '@angular/material/input'; |
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; |
|
||||
import { tesoCardModule } from '@teso/components/card'; |
|
||||
import { tesoAlertModule } from '@teso/components/alert'; |
|
||||
import { SharedModule } from 'app/shared/shared.module'; |
|
||||
import { AuthResetPasswordComponent } from 'app/pages/auth/reset-password/reset-password.component'; |
|
||||
import { authResetPasswordRoutes } from 'app/pages/auth/reset-password/reset-password.routing'; |
|
||||
|
|
||||
@NgModule({ |
|
||||
declarations: [ |
|
||||
AuthResetPasswordComponent |
|
||||
], |
|
||||
imports : [ |
|
||||
RouterModule.forChild(authResetPasswordRoutes), |
|
||||
MatButtonModule, |
|
||||
MatFormFieldModule, |
|
||||
MatIconModule, |
|
||||
MatInputModule, |
|
||||
MatProgressSpinnerModule, |
|
||||
tesoCardModule, |
|
||||
tesoAlertModule, |
|
||||
SharedModule |
|
||||
] |
|
||||
}) |
|
||||
export class AuthResetPasswordModule |
|
||||
{ |
|
||||
} |
|
@ -1,9 +0,0 @@ |
|||||
import { Route } from '@angular/router'; |
|
||||
import { AuthResetPasswordComponent } from 'app/pages/auth/reset-password/reset-password.component'; |
|
||||
|
|
||||
export const authResetPasswordRoutes: Route[] = [ |
|
||||
{ |
|
||||
path : '', |
|
||||
component: AuthResetPasswordComponent |
|
||||
} |
|
||||
]; |
|
@ -1,106 +0,0 @@ |
|||||
|
|
||||
<!-- <div class="flex flex-col sm:flex-row items-center md:items-start sm:justify-center md:justify-start flex-auto min-w-0"> |
|
||||
<div *ngIf="isScreenSmall" |
|
||||
class="md:flex md:items-center md:justify-end w-full sm:w-auto md:h-full md:w-1/2 py-8 px-4 sm:p-12 md:p-16 sm:rounded-2xl md:rounded-none sm:shadow md:shadow-none sm:bg-card"> |
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<div class="w-full sm:w-auto py-8 px-4 sm:p-12 sm:rounded-2xl sm:shadow sm:bg-card"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-20"> |
|
||||
<img src="assets/images/logo.png"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Sign in</div> |
|
||||
<div class="flex items-baseline mt-0.5 font-medium"> |
|
||||
<div>Enter phone number of business</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Alert --> |
|
||||
<teso-alert class="mt-8 -mb-4" *ngIf="showAlert" [appearance]="'outline'" [showIcon]="false" |
|
||||
[type]="alert.type" [@shake]="alert.type === 'error'"> |
|
||||
{{alert.message}} |
|
||||
</teso-alert> |
|
||||
|
|
||||
<!-- Sign in form --> |
|
||||
|
|
||||
<mat-form-field appearance="outline"> |
|
||||
|
|
||||
<ngx-mat-intl-tel-input [preferredCountries]="['gh', 'ng']" [onlyCountries]="['gh', 'ng']" |
|
||||
[enablePlaceholder]="true" [enableSearch]="false" name="phone"> |
|
||||
</ngx-mat-intl-tel-input> |
|
||||
<mat-hint>Standard call, message, or data rates may apply.</mat-hint> |
|
||||
</mat-form-field> |
|
||||
<!-- Actions --> |
|
||||
<div class="inline-flex items-end justify-between w-full mt-3.5"> |
|
||||
<mat-checkbox [color]="'primary'"> |
|
||||
Remember me |
|
||||
</mat-checkbox> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Submit button --> |
|
||||
<button class="teso-mat-button-large w-full mt-6" mat-flat-button [color]="'primary'" |
|
||||
(click)="signIn()"> |
|
||||
<span> |
|
||||
Sign in |
|
||||
</span> |
|
||||
<!-- <mat-progress-spinner |
|
||||
*ngIf="signInForm.disabled" |
|
||||
[diameter]="24" |
|
||||
[mode]="'indeterminate'"></mat-progress-spinner> --> |
|
||||
</button> |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</div> |
|
||||
<div id="welcomeBoard" |
|
||||
class="relative hidden md:flex flex-auto items-center justify-center w-1/2 h-full p-5 lg:px-20 overflow-hidden bg-gray-800 dark:border-l"> |
|
||||
|
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<div class="w-full sm:w-auto py-5 px-4 sm:p-8 sm:rounded-2xl sm:shadow sm:bg-card" style="background-color: #484444c4 !important;color: white !important;"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-30" style="width: 100%;justify-content: center;display: flex;"> |
|
||||
<img src="assets/images/logo.png"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Sign in</div> |
|
||||
<div class="flex items-baseline mt-0.5 font-medium"> |
|
||||
<div>Enter phone number of business</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Alert --> |
|
||||
<teso-alert class="mt-8 -mb-4" *ngIf="showAlert" [appearance]="'outline'" [showIcon]="false" |
|
||||
[type]="alert.type" [@shake]="alert.type === 'error'"> |
|
||||
{{alert.message}} |
|
||||
</teso-alert> |
|
||||
|
|
||||
<!-- Sign in form --> |
|
||||
|
|
||||
<mat-form-field appearance="outline"> |
|
||||
<ngx-mat-intl-tel-input [preferredCountries]="['gh', 'ng']" [onlyCountries]="['gh', 'ng']" |
|
||||
[enablePlaceholder]="true" [enableSearch]="false" name="phone"> |
|
||||
</ngx-mat-intl-tel-input> |
|
||||
<mat-hint style="color: white !important;">Standard call, message, or data rates may apply.</mat-hint> |
|
||||
</mat-form-field> |
|
||||
<!-- Actions --> |
|
||||
<div class="inline-flex items-end justify-between w-full mt-3.5"> |
|
||||
<mat-checkbox [color]="'primary'"> |
|
||||
Remember me |
|
||||
</mat-checkbox> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Submit button --> |
|
||||
<button class="teso-mat-button-large w-full mt-6" mat-flat-button [color]="'primary'" |
|
||||
(click)="signIn()"> |
|
||||
<span> |
|
||||
Sign in |
|
||||
</span> |
|
||||
<!-- <mat-progress-spinner |
|
||||
*ngIf="signInForm.disabled" |
|
||||
[diameter]="24" |
|
||||
[mode]="'indeterminate'"></mat-progress-spinner> --> |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> --> |
|
@ -1,136 +0,0 @@ |
|||||
<div class="flex flex-col sm:flex-row items-center md:items-start sm:justify-center md:justify-start flex-auto min-w-0"> |
|
||||
<div class="md:flex md:items-center md:justify-end w-full sm:w-auto md:h-full md:w-1/2 py-8 px-4 sm:p-12 md:p-16 sm:rounded-2xl md:rounded-none sm:shadow md:shadow-none sm:bg-card"> |
|
||||
<div class="w-full max-w-80 sm:w-80 mx-auto sm:mx-0"> |
|
||||
<!-- Logo --> |
|
||||
<div class="w-12"> |
|
||||
<img src="assets/images/logo/logo.svg"> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Title --> |
|
||||
<div class="mt-8 text-4xl font-extrabold tracking-tight leading-tight">Sign up</div> |
|
||||
<div class="flex items-baseline mt-0.5 font-medium"> |
|
||||
<div>Already have an account?</div> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['/pages/authentication/sign-in']">Sign in |
|
||||
</a> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Alert --> |
|
||||
<teso-alert class="mt-8 -mb-4" *ngIf="showAlert" [appearance]="'outline'" [showIcon]="false" [type]="alert.type" [@shake]="alert.type === 'error'"> |
|
||||
{{alert.message}} |
|
||||
</teso-alert> |
|
||||
|
|
||||
<!-- Sign Up form --> |
|
||||
<form class="mt-8" [formGroup]="signUpForm"> |
|
||||
|
|
||||
<!-- Name field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Full name</mat-label> |
|
||||
<input id="name" matInput [formControlName]="'name'"> |
|
||||
<mat-error *ngIf="signUpForm.get('name').hasError('required')"> |
|
||||
Full name is required |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Email field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Email address</mat-label> |
|
||||
<input id="email" matInput [formControlName]="'email'"> |
|
||||
<mat-error *ngIf="signUpForm.get('email').hasError('required')"> |
|
||||
Email address is required |
|
||||
</mat-error> |
|
||||
<mat-error *ngIf="signUpForm.get('email').hasError('email')"> |
|
||||
Please enter a valid email address |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Password field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Password</mat-label> |
|
||||
<input id="password" matInput type="password" [formControlName]="'password'" #passwordField> |
|
||||
<button mat-icon-button type="button" (click)="passwordField.type === 'password' ? passwordField.type = 'text' : passwordField.type = 'password'" matSuffix> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordField.type === 'password'" |
|
||||
[svgIcon]="'heroicons_solid:eye'"></mat-icon> |
|
||||
<mat-icon |
|
||||
class="icon-size-5" |
|
||||
*ngIf="passwordField.type === 'text'" |
|
||||
[svgIcon]="'heroicons_solid:eye-off'"></mat-icon> |
|
||||
</button> |
|
||||
<mat-error> |
|
||||
Password is required |
|
||||
</mat-error> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- Company field --> |
|
||||
<mat-form-field class="w-full"> |
|
||||
<mat-label>Company</mat-label> |
|
||||
<input id="company-confirm" matInput [formControlName]="'company'"> |
|
||||
</mat-form-field> |
|
||||
|
|
||||
<!-- ToS and PP --> |
|
||||
<div class="inline-flex items-end w-full mt-1.5"> |
|
||||
<mat-checkbox [color]="'primary'" [formControlName]="'agreements'"> |
|
||||
<span>I agree to the</span> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['./']">Terms of Service |
|
||||
</a> |
|
||||
<span>and</span> |
|
||||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['./']">Privacy Policy |
|
||||
</a> |
|
||||
</mat-checkbox> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Submit button --> |
|
||||
<button class="teso-mat-button-large w-full mt-6" mat-flat-button [color]="'primary'" [disabled]="signUpForm.disabled" (click)="signUp()"> |
|
||||
<span *ngIf="!signUpForm.disabled"> |
|
||||
Create your free account |
|
||||
</span> |
|
||||
<mat-progress-spinner |
|
||||
*ngIf="signUpForm.disabled" |
|
||||
[diameter]="24" |
|
||||
[mode]="'indeterminate'"></mat-progress-spinner> |
|
||||
</button> |
|
||||
|
|
||||
</form> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="relative hidden md:flex flex-auto items-center justify-center w-1/2 h-full p-16 lg:px-28 overflow-hidden bg-gray-800 dark:border-l"> |
|
||||
<!-- Background - @formatter:off --> |
|
||||
<!-- Rings --> |
|
||||
<svg class="absolute inset-0 pointer-events-none" viewBox="0 0 960 540" width="100%" height="100%" preserveAspectRatio="xMidYMax slice" xmlns="http://www.w3.org/2000/svg"> |
|
||||
<g class="text-gray-700 opacity-25" fill="none" stroke="currentColor" stroke-width="100"> |
|
||||
<circle r="234" cx="196" cy="23"></circle> |
|
||||
<circle r="234" cx="790" cy="491"></circle> |
|
||||
</g> |
|
||||
</svg> |
|
||||
<!-- Dots --> |
|
||||
<svg class="absolute -top-16 -right-16 text-gray-700" viewBox="0 0 220 192" width="220" height="192" fill="none"> |
|
||||
<defs> |
|
||||
<pattern id="837c3e70-6c3a-44e6-8854-cc48c737b659" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse"> |
|
||||
<rect x="0" y="0" width="4" height="4" fill="currentColor"></rect> |
|
||||
</pattern> |
|
||||
</defs> |
|
||||
<rect width="220" height="192" fill="url(#837c3e70-6c3a-44e6-8854-cc48c737b659)"></rect> |
|
||||
</svg> |
|
||||
<!-- @formatter:on --> |
|
||||
<!-- Content --> |
|
||||
<div class="z-10 relative w-full max-w-2xl"> |
|
||||
<div class="text-7xl font-bold leading-none text-gray-100"> |
|
||||
<div>Welcome to</div> |
|
||||
<div>our community</div> |
|
||||
</div> |
|
||||
<div class="mt-6 text-lg tracking-tight leading-6 text-gray-400"> |
|
||||
teso helps developers to build organized and well coded dashboards full of beautiful and rich modules. Join us and start building your application today. |
|
||||
</div> |
|
||||
<div class="flex items-center mt-8"> |
|
||||
<div class="flex flex-0 items-center -space-x-1.5"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-18.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/female-11.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-09.jpg"> |
|
||||
<img class="flex-0 w-10 h-10 rounded-full ring-4 ring-offset-1 ring-gray-800 ring-offset-gray-800 object-cover" src="assets/images/avatars/male-16.jpg"> |
|
||||
</div> |
|
||||
<div class="ml-4 font-medium tracking-tight text-gray-400">More than 17k people joined us, it's your turn</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
@ -1,104 +0,0 @@ |
|||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; |
|
||||
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; |
|
||||
import { Router } from '@angular/router'; |
|
||||
import { tesoAnimations } from '@teso/animations'; |
|
||||
import { tesoAlertType } from '@teso/components/alert'; |
|
||||
import { AuthService } from 'app/core/auth/auth.service'; |
|
||||
|
|
||||
@Component({ |
|
||||
selector : 'auth-sign-up', |
|
||||
templateUrl : './sign-up.component.html', |
|
||||
encapsulation: ViewEncapsulation.None, |
|
||||
animations : tesoAnimations |
|
||||
}) |
|
||||
export class AuthSignUpComponent implements OnInit |
|
||||
{ |
|
||||
@ViewChild('signUpNgForm') signUpNgForm: NgForm; |
|
||||
|
|
||||
alert: { type: tesoAlertType; message: string } = { |
|
||||
type : 'success', |
|
||||
message: '' |
|
||||
}; |
|
||||
signUpForm: FormGroup; |
|
||||
showAlert: boolean = false; |
|
||||
|
|
||||
/** |
|
||||
* Constructor |
|
||||
*/ |
|
||||
constructor( |
|
||||
private _authService: AuthService, |
|
||||
private _formBuilder: FormBuilder, |
|
||||
private _router: Router |
|
||||
) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Lifecycle hooks
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* On init |
|
||||
*/ |
|
||||
ngOnInit(): void |
|
||||
{ |
|
||||
// Create the form
|
|
||||
this.signUpForm = this._formBuilder.group({ |
|
||||
name : ['', Validators.required], |
|
||||
email : ['', [Validators.required, Validators.email]], |
|
||||
password : ['', Validators.required], |
|
||||
company : [''], |
|
||||
agreements: ['', Validators.requiredTrue] |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
// @ Public methods
|
|
||||
// -----------------------------------------------------------------------------------------------------
|
|
||||
|
|
||||
/** |
|
||||
* Sign up |
|
||||
*/ |
|
||||
signUp(): void |
|
||||
{ |
|
||||
// Do nothing if the form is invalid
|
|
||||
if ( this.signUpForm.invalid ) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Disable the form
|
|
||||
this.signUpForm.disable(); |
|
||||
|
|
||||
// Hide the alert
|
|
||||
this.showAlert = false; |
|
||||
|
|
||||
// Sign up
|
|
||||
this._authService.signUp(this.signUpForm.value) |
|
||||
.subscribe( |
|
||||
(response) => { |
|
||||
|
|
||||
// Navigate to the confirmation required page
|
|
||||
this._router.navigateByUrl('/confirmation-required'); |
|
||||
}, |
|
||||
(response) => { |
|
||||
|
|
||||
// Re-enable the form
|
|
||||
this.signUpForm.enable(); |
|
||||
|
|
||||
// Reset the form
|
|
||||
this.signUpNgForm.resetForm(); |
|
||||
|
|
||||
// Set the alert
|
|
||||
this.alert = { |
|
||||
type : 'error', |
|
||||
message: 'Something went wrong, please try again.' |
|
||||
}; |
|
||||
|
|
||||
// Show the alert
|
|
||||
this.showAlert = true; |
|
||||
} |
|
||||
); |
|
||||
} |
|
||||
} |
|
@ -1,34 +0,0 @@ |
|||||
import { NgModule } from '@angular/core'; |
|
||||
import { RouterModule } from '@angular/router'; |
|
||||
import { MatButtonModule } from '@angular/material/button'; |
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox'; |
|
||||
import { MatFormFieldModule } from '@angular/material/form-field'; |
|
||||
import { MatIconModule } from '@angular/material/icon'; |
|
||||
import { MatInputModule } from '@angular/material/input'; |
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; |
|
||||
import { tesoCardModule } from '@teso/components/card'; |
|
||||
import { tesoAlertModule } from '@teso/components/alert'; |
|
||||
import { SharedModule } from 'app/shared/shared.module'; |
|
||||
import { AuthSignUpComponent } from 'app/pages/auth/sign-up/sign-up.component'; |
|
||||
import { authSignupRoutes } from 'app/pages/auth/sign-up/sign-up.routing'; |
|
||||
|
|
||||
@NgModule({ |
|
||||
declarations: [ |
|
||||
AuthSignUpComponent |
|
||||
], |
|
||||
imports : [ |
|
||||
RouterModule.forChild(authSignupRoutes), |
|
||||
MatButtonModule, |
|
||||
MatCheckboxModule, |
|
||||
MatFormFieldModule, |
|
||||
MatIconModule, |
|
||||
MatInputModule, |
|
||||
MatProgressSpinnerModule, |
|
||||
tesoCardModule, |
|
||||
tesoAlertModule, |
|
||||
SharedModule |
|
||||
] |
|
||||
}) |
|
||||
export class AuthSignUpModule |
|
||||
{ |
|
||||
} |
|
@ -1,9 +0,0 @@ |
|||||
import { Route } from '@angular/router'; |
|
||||
import { AuthSignUpComponent } from 'app/pages/auth/sign-up/sign-up.component'; |
|
||||
|
|
||||
export const authSignupRoutes: Route[] = [ |
|
||||
{ |
|
||||
path : '', |
|
||||
component: AuthSignUpComponent |
|
||||
} |
|
||||
]; |
|
@ -0,0 +1,25 @@ |
|||||
|
<div class="d-flex justify-content-center align-items-center"> |
||||
|
<div class="position-relative"> |
||||
|
<div class="card p-2 text-center" style="display: contents;"> |
||||
|
<div class="w-30" style="width: 100% !important;justify-content: center;display: flex;"> |
||||
|
<img src="assets/images/logo.png" style="width:140px"> |
||||
|
</div> |
||||
|
<h6>Please enter the one time password <br> </h6> |
||||
|
<div> <span> sent to {{data.phone}}</span> </div> |
||||
|
<div id="otp" class="inputs d-flex flex-row justify-content-center mt-2"> |
||||
|
<ng-otp-input (onInputChange)="onOtpChange($event)" [config]="config"></ng-otp-input> |
||||
|
</div> |
||||
|
<div class="mt-4"> <button class="btn btn-danger px-4 validate" mat-flat-button (click)="verifyCode()" |
||||
|
*ngIf="!signInForm.disabled"> <span> |
||||
|
Verify |
||||
|
</span> |
||||
|
</button> </div> |
||||
|
<div class="lds-dual-ring" *ngIf="signInForm.disabled"></div> |
||||
|
<div class="mt-3 content flex justify-content-center align-items-center" |
||||
|
style="width: 100% !important;justify-content: space-between !important;"> |
||||
|
<span>Didn't get the code ? </span> |
||||
|
<a href="javascript:void(0)" class="text-decoration-none ms-3" (click)="closeDialog()">Try again</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
@ -0,0 +1,82 @@ |
|||||
|
|
||||
|
.height-100 { |
||||
|
height: 100vh |
||||
|
} |
||||
|
|
||||
|
.card { |
||||
|
width: 400px; |
||||
|
border: none; |
||||
|
height: 300px; |
||||
|
box-shadow: 0px 5px 20px 0px #252f3b; |
||||
|
z-index: 1; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center |
||||
|
} |
||||
|
|
||||
|
.card h6 { |
||||
|
color: #252f3b; |
||||
|
font-size: 20px |
||||
|
} |
||||
|
|
||||
|
.inputs input { |
||||
|
width: 40px; |
||||
|
height: 40px |
||||
|
} |
||||
|
|
||||
|
input[type=number]::-webkit-inner-spin-button, |
||||
|
input[type=number]::-webkit-outer-spin-button { |
||||
|
-webkit-appearance: none; |
||||
|
-moz-appearance: none; |
||||
|
appearance: none; |
||||
|
margin: 0 |
||||
|
} |
||||
|
|
||||
|
.form-control:focus { |
||||
|
box-shadow: none; |
||||
|
border: 2px solid #252f3b |
||||
|
} |
||||
|
|
||||
|
.validate { |
||||
|
border-radius: 20px; |
||||
|
height: 40px; |
||||
|
background-color: #252f3b; |
||||
|
border: 1px solid #252f3b; |
||||
|
width: 100%; |
||||
|
color:white; |
||||
|
} |
||||
|
|
||||
|
.content a { |
||||
|
color: royalblue; |
||||
|
transition: all 0.5s |
||||
|
} |
||||
|
|
||||
|
.content a:hover { |
||||
|
color: rgb(179, 155, 24) |
||||
|
} |
||||
|
|
||||
|
.lds-dual-ring { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
width: 100%; |
||||
|
height: 40px; |
||||
|
} |
||||
|
.lds-dual-ring:after { |
||||
|
content: " "; |
||||
|
display: block; |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
margin: 8px; |
||||
|
border-radius: 50%; |
||||
|
border: 6px solid #003445; |
||||
|
border-color: #003445 transparent #003445 transparent; |
||||
|
animation: lds-dual-ring 1.2s linear infinite; |
||||
|
} |
||||
|
@keyframes lds-dual-ring { |
||||
|
0% { |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
transform: rotate(360deg); |
||||
|
} |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
import { Component, Inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; |
||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; |
||||
|
import { AuthService } from 'app/core/auth/auth.service'; |
||||
|
import { WindowService } from 'app/window.service'; |
||||
|
import { NgOtpInputComponent, NgOtpInputConfig } from 'ng-otp-input'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-verification-dialog', |
||||
|
templateUrl: './verification-dialog.component.html', |
||||
|
styleUrls: ['./verification-dialog.component.scss'], |
||||
|
encapsulation: ViewEncapsulation.Emulated, |
||||
|
}) |
||||
|
export class VerificationDialogComponent implements OnInit { |
||||
|
@ViewChild(NgOtpInputComponent, { static: false }) ngOtpInput: NgOtpInputComponent; |
||||
|
config: NgOtpInputConfig = { |
||||
|
allowNumbersOnly: true, |
||||
|
length: 6, |
||||
|
isPasswordInput: false, |
||||
|
disableAutoFocus: false, |
||||
|
placeholder: '' |
||||
|
}; |
||||
|
otp: string; |
||||
|
showOtpComponent = true; |
||||
|
signInForm: FormGroup; |
||||
|
verificationCode; |
||||
|
errorString = "FirebaseError: Firebase: The SMS verification code used to create the phone auth credential is invalid. Please resend the verification code sms and be sure to use the verification code provided by the user" |
||||
|
constructor(@Inject(MAT_DIALOG_DATA) public data: { windowRef: any, phone: String }, |
||||
|
public dialogRef: MatDialogRef<VerificationDialogComponent>, |
||||
|
private _authService: AuthService, private fb: FormBuilder |
||||
|
) { |
||||
|
this.signInForm = this.fb.group({ |
||||
|
phone: [undefined, [Validators.required]], |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
// this.verifyCode();
|
||||
|
} |
||||
|
verifyCode() { |
||||
|
this.signInForm.disable(); |
||||
|
this.data.windowRef.confirmationResult |
||||
|
.confirm(this.verificationCode) |
||||
|
.then(result => { |
||||
|
if (result.user !== "") { |
||||
|
this._authService.authenticate(this.data.phone) |
||||
|
.subscribe( |
||||
|
() => { |
||||
|
this.dialogRef.close("verified") |
||||
|
|
||||
|
}, |
||||
|
(response) => { |
||||
|
if (response.error = "Unregistered") { |
||||
|
this.dialogRef.close("unregistered") |
||||
|
} else { |
||||
|
this.dialogRef.close("error") |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
}).catch((error) => { |
||||
|
if (error.toString().includes(this.errorString)) { |
||||
|
this.dialogRef.close("wrong verification code") |
||||
|
} else { |
||||
|
this.dialogRef.close("error") |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
closeDialog(){ |
||||
|
this.dialogRef.close("resend") |
||||
|
} |
||||
|
|
||||
|
onOtpChange(otp) { |
||||
|
this.otp = otp; |
||||
|
if (otp.toString().length == 6) |
||||
|
this.verificationCode = otp; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
toggleDisable() { |
||||
|
if (this.ngOtpInput.otpForm) { |
||||
|
if (this.ngOtpInput.otpForm.disabled) { |
||||
|
this.ngOtpInput.otpForm.enable(); |
||||
|
} else { |
||||
|
this.ngOtpInput.otpForm.disable(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
import { Pipe, PipeTransform } from '@angular/core'; |
||||
|
|
||||
|
@Pipe({ |
||||
|
name: 'percentage' |
||||
|
}) |
||||
|
export class PercentagePipe implements PipeTransform { |
||||
|
|
||||
|
transform(value: number): string { |
||||
|
let newvale = parseFloat((Math.round(value*10^2)).toString()); |
||||
|
return newvale + "%"; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class WindowService { |
||||
|
|
||||
|
get windowRef() { |
||||
|
return window |
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 339 KiB |
@ -1,5 +1,15 @@ |
|||||
export const environment = { |
export const environment = { |
||||
production: true, |
production: true, |
||||
apiURL:"https://test.tesoapp.com/v2/" |
apiURL:"https://test.tesoapp.com/v2/", |
||||
// apiURL:"https://localhost:7076/"
|
// apiURL:"https://localhost:7076/"
|
||||
|
firebaseConfig :{ |
||||
|
apiKey: "AIzaSyDrFGHgBJxi4EgCThwBZaT7IUtQUhbhS8s", |
||||
|
authDomain: "teso-ghana.firebaseapp.com", |
||||
|
databaseURL: "https://teso-ghana-default-rtdb.firebaseio.com", |
||||
|
projectId: "teso-ghana", |
||||
|
storageBucket: "teso-ghana.appspot.com", |
||||
|
messagingSenderId: "280510379185", |
||||
|
appId: "1:280510379185:web:7a3e0afbfd43e93d19de90", |
||||
|
measurementId: "G-82HYCB3QDE" |
||||
|
} |
||||
}; |
}; |
||||
|
Loading…
Reference in new issue