98 changed files with 3081 additions and 1456 deletions
@ -1,6 +1,6 @@ |
|||
<!-- <button mat-icon-button> --> |
|||
<div style="display: flex;justify-content:space-around;" class="goldDiv"> |
|||
<img class="w-10" src="assets/images/gold1.png" alt="Logo image"> |
|||
<span style="padding-top: 9px;font-size: medium;font-weight: 700;color: #64738b;">+{{gold}}</span> |
|||
<span style="padding-top: 9px;font-size: medium;font-weight: 700;color: #64738b;">{{gold}}</span> |
|||
</div> |
|||
<!-- </button> --> |
@ -0,0 +1,25 @@ |
|||
export interface Finance { |
|||
businessID: string; |
|||
gold: number; |
|||
} |
|||
export interface TesoBusinessDetail { |
|||
businessId?: string, |
|||
Handle?: string, |
|||
businessName?: string, |
|||
businessEmail?: string, |
|||
businessTin?: string, |
|||
businessDescription?: string, |
|||
businessCategory?: string, |
|||
businessAddress?: string, |
|||
businessContact?: string, |
|||
businessLogo?: string, |
|||
dateOfEst?: Date, |
|||
businessDigitalAddress?: string, |
|||
businessLatitude?: string, |
|||
businessLongitude?: string, |
|||
} |
|||
|
|||
export interface BusinessCategory { |
|||
categoryCode: string, |
|||
categoryName: string, |
|||
} |
@ -0,0 +1,21 @@ |
|||
import { TesoBusinessDetail } from "./businessModel" |
|||
|
|||
export interface CouponsModel { |
|||
couponID: string, |
|||
businessID: string, |
|||
targetProduct: string, |
|||
type: string, |
|||
quantity: number, |
|||
lower: number, |
|||
condition: string, |
|||
upper: number, |
|||
numberClaimed: number, |
|||
status: string, |
|||
expiration: Date, |
|||
target?: TesoBusinessDetail, |
|||
} |
|||
|
|||
export interface CouponsType { |
|||
typeCode: string; |
|||
typeName: string; |
|||
} |
@ -0,0 +1,40 @@ |
|||
export interface ProductsModel { |
|||
productName: string; |
|||
businessID: string; |
|||
productDesc: string; |
|||
productID: string; |
|||
categoryID: string; |
|||
unitPrice: number; |
|||
productImage: string; |
|||
images: ProductImages[]; |
|||
|
|||
} |
|||
|
|||
export interface ProductImages { |
|||
id: string; |
|||
productID: string; |
|||
path: string; |
|||
} |
|||
|
|||
export interface ProductCategory { |
|||
catCode: string; |
|||
catName: string; |
|||
} |
|||
|
|||
export interface DesiredProduct{ |
|||
productID:string, |
|||
productName:string, |
|||
productImage:string, |
|||
cost:number, |
|||
category:string, |
|||
enlisted:boolean, |
|||
desires:number |
|||
} |
|||
|
|||
export interface DesiredList{ |
|||
mostWishedProduct?: DesiredProduct[], |
|||
mostWishedCategory?: DesiredProduct[], |
|||
availableProducts?: DesiredProduct[], |
|||
availableCategory?: DesiredProduct[], |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
export interface TesoUserDetails { |
|||
userGuid?: string; |
|||
username?: string; |
|||
firstname?: string; |
|||
surname?: string; |
|||
description?: string; |
|||
address?: string; |
|||
email?: string; |
|||
thumbnailDp?: string; |
|||
phonenumber?: string; |
|||
country?: string; |
|||
gender?: string; |
|||
dateOfBirth: Date; |
|||
} |
@ -1,22 +1,63 @@ |
|||
import { Component, Inject, OnInit } from '@angular/core'; |
|||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
|||
import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { TesoBusinessDetail } from 'app/models/businessModel'; |
|||
import { CouponsType } from 'app/models/couponsModel'; |
|||
import { ProductsModel } from 'app/models/productsModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { BusinessLookUpComponent } from '../../Products/BusinessLookUp/business-look-up.component'; |
|||
import { ProductsService } from '../../Products/products.service'; |
|||
import { CouponsService } from '../coupons.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-admin-new-coupons', |
|||
templateUrl: './admin-new-coupons.component.html', |
|||
styleUrls: ['./admin-new-coupons.component.scss'] |
|||
}) |
|||
export class AdminNewCouponsComponent implements OnInit { |
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { product: any }, public dialog: MatDialog,) { } |
|||
export class AdminNewCouponsComponent implements OnInit, OnDestroy { |
|||
businessTargetted: TesoBusinessDetail = {}; |
|||
products: ProductsModel[] = []; |
|||
fromWorth:number; |
|||
toWorth:number; |
|||
selectedProduct: any = {}; |
|||
selectedType: any = {}; |
|||
isLoading: boolean = false; |
|||
isScreenSmall: boolean; |
|||
couponTypes: CouponsType[] = []; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { product: any }, |
|||
public dialog: MatDialog, private _productService: ProductsService, |
|||
private _couponService: CouponsService, private _tesoMediaWatcherService: tesoMediaWatcherService,) { } |
|||
|
|||
ngOnInit(): void { |
|||
this._couponService.categories$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.couponTypes = d; |
|||
}); |
|||
this._productService.data$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.products = d; |
|||
}); |
|||
this._tesoMediaWatcherService.onMediaChange$ |
|||
.pipe(takeUntil(this._unsubscribeAll)) |
|||
.subscribe(({ matchingAliases }) => { |
|||
|
|||
// Check if the screen is small
|
|||
this.isScreenSmall = !matchingAliases.includes('md'); |
|||
}); |
|||
} |
|||
lookupBusiness() { |
|||
const dialogRef = this.dialog.open(BusinessLookUpComponent, { |
|||
disableClose: true, |
|||
hasBackdrop: true, |
|||
}); |
|||
|
|||
dialogRef.afterClosed().subscribe((result) => { |
|||
this.businessTargetted = result; |
|||
}); |
|||
} |
|||
ngOnDestroy(): void { |
|||
// Unsubscribe from all subscriptions
|
|||
this._unsubscribeAll.next(); |
|||
this._unsubscribeAll.complete(); |
|||
} |
|||
} |
|||
|
@ -1,15 +1,50 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
|||
import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { CouponsType } from 'app/models/couponsModel'; |
|||
import { ProductsModel } from 'app/models/productsModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { ProductsService } from '../../Products/products.service'; |
|||
import { CouponsService } from '../coupons.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-new-coupons', |
|||
templateUrl: './new-coupons.component.html', |
|||
styleUrls: ['./new-coupons.component.scss'] |
|||
}) |
|||
export class NewCouponsComponent implements OnInit { |
|||
|
|||
constructor() { } |
|||
export class NewCouponsComponent implements OnInit,OnDestroy { |
|||
products: ProductsModel[] = []; |
|||
selectedProduct:any={}; |
|||
selectedType:any={}; |
|||
isLoading: boolean = false; |
|||
couponTypes:CouponsType[]=[]; |
|||
fromWorth:number; |
|||
toWorth:number; |
|||
isScreenSmall:boolean; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { product: any }, |
|||
public dialog: MatDialog, private _productService: ProductsService, |
|||
private _couponService: CouponsService, private _tesoMediaWatcherService: tesoMediaWatcherService,) { } |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
this._couponService.categories$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.couponTypes = d; |
|||
}); |
|||
this._productService.data$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.products = d; |
|||
}); |
|||
this._tesoMediaWatcherService.onMediaChange$ |
|||
.pipe(takeUntil(this._unsubscribeAll)) |
|||
.subscribe(({ matchingAliases }) => { |
|||
|
|||
// Check if the screen is small
|
|||
this.isScreenSmall = !matchingAliases.includes('md'); |
|||
}); |
|||
} |
|||
ngOnDestroy(): void { |
|||
// Unsubscribe from all subscriptions
|
|||
this._unsubscribeAll.next(); |
|||
this._unsubscribeAll.complete(); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,59 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { analytics as analyticsData } from 'app/mock-api/dashboards/analytics/data'; |
|||
import { environment } from 'environments/environment'; |
|||
import { CouponsModel, CouponsType } from 'app/models/couponsModel'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class CouponsService { |
|||
private _data: BehaviorSubject<any> = new BehaviorSubject(null); |
|||
private _couponCategory: BehaviorSubject<CouponsType[]> = new BehaviorSubject(null); |
|||
|
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor(private _httpClient: HttpClient) { |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Accessors
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Getter for data |
|||
*/ |
|||
get data$(): Observable<any> { |
|||
return this._data.asObservable(); |
|||
} |
|||
|
|||
get categories$(): Observable<CouponsType[]> { |
|||
return this._couponCategory.asObservable(); |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Get data |
|||
*/ |
|||
getData(): Observable<any> { |
|||
return this._httpClient.get(environment.apiURL + `allcoupons`).pipe( |
|||
tap((response: any) => { |
|||
this._data.next(response); |
|||
}) |
|||
); |
|||
} |
|||
|
|||
getCategory(): Observable<CouponsType[]> { |
|||
return this._httpClient.get(environment.apiURL + `api/CouponTypes`).pipe( |
|||
tap((response: CouponsType[]) => { |
|||
this._couponCategory.next(response); |
|||
}) |
|||
); |
|||
} |
|||
} |
@ -0,0 +1,139 @@ |
|||
<div class="row" style="display: flex;justify-content:space-between"> |
|||
<div class="row" style="display: flex;justify-content:center;width: 100%;"> |
|||
<h2 mat-dialog-title style="text-align: center;">Send a coupon to {{data.subscriber.firstname}} |
|||
{{data.subscriber.surname}}</h2> |
|||
</div> |
|||
<!-- <button mat-button mat-dialog-close>Cancel</button> --> |
|||
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>x</button> |
|||
</div> |
|||
<mat-dialog-content class="mat-typography"> |
|||
<div class=" py-2 pl-3 pr-3 sm:py-4 md:pl-4 md:pr-6"> |
|||
<!-- <div class="flex flex-col flex-auto w-full p-8 text-center"> |
|||
<div class="w-32 h-32 mx-auto rounded-full overflow-hidden"> |
|||
<img class="w-full h-full object-cover" [src]="imageLoader(data.subscriber.thumbnailDp)"> |
|||
</div> |
|||
</div> --> |
|||
<div class="columns" style="display: flex;align-items: center" *ngIf="tesoGhana"> |
|||
<div class="column" style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Target Business </strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
{{businessTargetted.businessName}} |
|||
</mat-label> |
|||
<button style="background-color: blue;color:white;margin-right:20px;" mat-button |
|||
(click)="lookupBusiness()">Search</button> |
|||
</div> |
|||
</div> |
|||
<hr *ngIf="tesoGhana" /> |
|||
<div class="columns" style="display: flex;align-items: center"> |
|||
<div class="column" style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Product Name </strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<mat-form-field appearance="fill" style="min-width: 200px;"> |
|||
<mat-select [(ngModel)]="selectedProduct"> |
|||
<mat-option *ngFor="let product of products" [value]="product"> |
|||
{{product.productName}} |
|||
</mat-option> |
|||
</mat-select> |
|||
|
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
<div class="columns" style="display: flex;align-items: center;margin-top: 15px;"> |
|||
<div class="column" style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Original Price </strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
{{selectedProduct.unitPrice | currency:"GHS "}} |
|||
</mat-label> |
|||
</div> |
|||
</div> |
|||
<div class="columns" style="display: flex;align-items: center;margin-top: 15px;"> |
|||
<div class="column" style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong class="tileHead">Coupon Type</strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<mat-form-field appearance="fill" style="min-width: 200px;"> |
|||
<mat-select [(ngModel)]="selectedType"> |
|||
<mat-option value="TESCP005">DISCOUNT </mat-option> |
|||
<mat-option value="TESCP006">FREEBIE </mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="columns" style="display: flex;align-items: center"> |
|||
<div class="column"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Coupon Condition</strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<textarea name="" id="" cols="30" rows="5" style="border: 1px solid #cbd5e1;"></textarea> |
|||
</div> |
|||
</div> |
|||
<div class="columns" style="display: flex;align-items: center"> |
|||
<div class="column" style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Number Of Coupons</strong> |
|||
</mat-label> |
|||
</div> |
|||
<div class="column"> |
|||
<mat-form-field appearance="fill" style="min-width: 200px;"> |
|||
<input matInput style="margin-left:10px;" type="number"> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
</div> |
|||
<div style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Percentage Off </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="margin-right:10px;"> |
|||
<span matPrefix>From </span> |
|||
<input matInput type="number"> |
|||
<span matSuffix>% </span> |
|||
</mat-form-field> |
|||
<mat-form-field appearance="fill" style="margin-left:10px;"> |
|||
<span matPrefix>To </span> |
|||
<input matInput type="number"> |
|||
<span matSuffix>% </span> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;align-items: baseline"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Coupon Worth </strong> |
|||
</mat-label> |
|||
<mat-label> |
|||
From GH¢200 To GH¢800 |
|||
</mat-label> |
|||
</div> |
|||
<div style="display: flex;align-items: baseline;margin-top: 20px;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Date Of Expiration </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="outline"> |
|||
<input matInput style="margin-left:10px;" type="date"> |
|||
</mat-form-field> |
|||
<mat-form-field appearance="fill"> |
|||
<span matPrefix>Time </span> |
|||
<input matInput type="time"> |
|||
</mat-form-field> |
|||
</div> |
|||
<div class="row" style="display: flex;justify-content:space-around;width:100%;"> |
|||
<button style="background-color: blue;color:white;margin-right:20px;" mat-button>Generate Coupons</button> |
|||
|
|||
</div> |
|||
</div> |
|||
</mat-dialog-content> |
@ -0,0 +1,11 @@ |
|||
.columns { |
|||
display: flex; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
width: 100%; |
|||
} |
|||
|
|||
.column { |
|||
flex: 50%; |
|||
font-size: medium; |
|||
} |
@ -0,0 +1,25 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { PersonalizedCouponsComponent } from './personalized-coupons.component'; |
|||
|
|||
describe('PersonalizedCouponsComponent', () => { |
|||
let component: PersonalizedCouponsComponent; |
|||
let fixture: ComponentFixture<PersonalizedCouponsComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ PersonalizedCouponsComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(PersonalizedCouponsComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,50 @@ |
|||
import { Component, Inject, OnInit } from '@angular/core'; |
|||
import { MatDialog, MAT_DIALOG_DATA } from '@angular/material/dialog'; |
|||
import { TesoBusinessDetail } from 'app/models/businessModel'; |
|||
import { CouponsType } from 'app/models/couponsModel'; |
|||
import { ProductsModel } from 'app/models/productsModel'; |
|||
import { TesoUserDetails } from 'app/models/userModel'; |
|||
import { environment } from 'environments/environment'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { CouponsService } from '../../Coupons/coupons.service'; |
|||
import { BusinessLookUpComponent } from '../../Products/BusinessLookUp/business-look-up.component'; |
|||
import { ProductsService } from '../../Products/products.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-personalized-coupons', |
|||
templateUrl: './personalized-coupons.component.html', |
|||
styleUrls: ['./personalized-coupons.component.scss'] |
|||
}) |
|||
export class PersonalizedCouponsComponent implements OnInit { |
|||
tesoGhana:boolean = false; |
|||
businessTargetted: TesoBusinessDetail = {}; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
isLoading: boolean = false; |
|||
products: ProductsModel[] = []; |
|||
selectedProduct: any = {}; |
|||
selectedType: string; |
|||
couponTypes: CouponsType[] = []; |
|||
constructor(private _productService: ProductsService, |
|||
@Inject(MAT_DIALOG_DATA) public data: { subscriber: TesoUserDetails }, |
|||
public dialog: MatDialog,) { } |
|||
|
|||
ngOnInit(): void { |
|||
this._productService.data$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.products = d; |
|||
}); |
|||
} |
|||
imageLoader(path: string): string { |
|||
return environment.apiURL + `followeruserdp/${path}`; |
|||
} |
|||
lookupBusiness() { |
|||
const dialogRef = this.dialog.open(BusinessLookUpComponent, { |
|||
disableClose: true, |
|||
hasBackdrop: true, |
|||
}); |
|||
|
|||
dialogRef.afterClosed().subscribe((result) => { |
|||
this.businessTargetted = result; |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; |
|||
import { Observable } from 'rxjs'; |
|||
import { DesiresService } from './desires.service'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class DesiresResolver implements Resolve<any> |
|||
{ |
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor(private _desiresService: DesiresService) |
|||
{ |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Resolver |
|||
* |
|||
* @param route |
|||
* @param state |
|||
*/ |
|||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> |
|||
{ |
|||
return this._desiresService.getData(); |
|||
} |
|||
} |
@ -0,0 +1,49 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { analytics as analyticsData } from 'app/mock-api/dashboards/analytics/data'; |
|||
import { environment } from 'environments/environment'; |
|||
import { DesiredList, DesiredProduct, ProductCategory, ProductsModel } from 'app/models/productsModel'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class DesiresService { |
|||
private _data: BehaviorSubject<any> = new BehaviorSubject(null); |
|||
|
|||
|
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor(private _httpClient: HttpClient) { |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Accessors
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Getter for data |
|||
*/ |
|||
get data$(): Observable<DesiredList> { |
|||
return this._data.asObservable(); |
|||
} |
|||
|
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Get data |
|||
*/ |
|||
getData(): Observable<DesiredList> { |
|||
return this._httpClient.get(environment.apiURL + `desires/pull-monthly`).pipe( |
|||
tap((response: DesiredList) => { |
|||
this._data.next(response); |
|||
|
|||
}) |
|||
); |
|||
} |
|||
} |
@ -1,16 +1,47 @@ |
|||
import { Component, Inject, OnInit } from '@angular/core'; |
|||
import { MAT_DIALOG_DATA } from '@angular/material/dialog'; |
|||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
|||
import { MatDialog, MAT_DIALOG_DATA } from '@angular/material/dialog'; |
|||
import { ConfirmBoxEvokeService } from '@costlydeveloper/ngx-awesome-popup'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { CouponsType } from 'app/models/couponsModel'; |
|||
import { ProductsModel } from 'app/models/productsModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { CouponsService } from '../../Coupons/coupons.service'; |
|||
import { ProductsService } from '../products.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-coupon-dialog', |
|||
templateUrl: './coupon-dialog.component.html', |
|||
styleUrls: ['./coupon-dialog.component.scss'] |
|||
}) |
|||
export class CouponDialogComponent implements OnInit { |
|||
|
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { product: any },) { } |
|||
export class CouponDialogComponent implements OnInit,OnDestroy { |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
isLoading:boolean=false; |
|||
selectedProduct:any={}; |
|||
selectedType:any={}; |
|||
couponTypes:CouponsType[]=[]; |
|||
isScreenSmall: boolean; |
|||
constructor( |
|||
private _couponService: CouponsService,@Inject(MAT_DIALOG_DATA) public data: { product: ProductsModel }, |
|||
public dialog: MatDialog,private _productService: ProductsService,private _tesoMediaWatcherService: tesoMediaWatcherService, |
|||
private confirmBoxEvokeService: ConfirmBoxEvokeService,) { } |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
this._couponService.categories$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.couponTypes = d; |
|||
}); |
|||
this._tesoMediaWatcherService.onMediaChange$ |
|||
.pipe(takeUntil(this._unsubscribeAll)) |
|||
.subscribe(({ matchingAliases }) => { |
|||
|
|||
// Check if the screen is small
|
|||
this.isScreenSmall = !matchingAliases.includes('md'); |
|||
}); |
|||
|
|||
} |
|||
ngOnDestroy(): void { |
|||
// Unsubscribe from all subscriptions
|
|||
this._unsubscribeAll.next(); |
|||
this._unsubscribeAll.complete(); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,201 @@ |
|||
<div class="absolute inset-0 flex flex-col min-w-0 " *ngIf="!isScreenSmall"> |
|||
|
|||
<mat-drawer-container class="flex-auto h-full"> |
|||
<!-- Drawer content --> |
|||
<mat-drawer-content class="flex flex-col"> |
|||
<!-- Header --> |
|||
<div |
|||
class="flex flex-0 items-center py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 border-b lg:border-b-0 bg-card dark:bg-transparent"> |
|||
<!-- Title & Actions --> |
|||
<button mat-icon-button [routerLink]="['../../']"> |
|||
<mat-icon [svgIcon]="'heroicons_outline:arrow-sm-left'"></mat-icon> |
|||
</button> |
|||
<h2 class="ml-2.5 text-md sm:text-xl font-medium tracking-tight truncate"> |
|||
Product # {{product.productID}} |
|||
</h2> |
|||
</div> |
|||
<div |
|||
class=" flex flex-0 items-center py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 border-b lg:border-b-0 bg-card dark:bg-transparent"> |
|||
<div class="flex-auto" cdkScrollable> |
|||
<div class="min-h-180 border-2 border-dashed border-gray-300 rounded-2xl py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 mx-auto" |
|||
style="max-width: 780px;"> |
|||
<mat-tab-group mat-align-tabs="center"> |
|||
<mat-tab label="Product Information"> |
|||
<div class=" py-2 pl-3 pr-3 sm:py-4 md:pl-4 md:pr-6" |
|||
style="overflow-y: hidden !important;"> |
|||
<div style="display: flex;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Product Name </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input disabled matInput style="margin-left:10px;" type="text" |
|||
value="{{product.productName}}"> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display:flex;"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong class="tileHead">Product Category</strong> |
|||
</mat-label> |
|||
<mat-label style="width: 350px;"> |
|||
<span class="tileHead">{{product.categoryID}}</span> |
|||
</mat-label> |
|||
</div> |
|||
<div style="display: flex;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Original Price </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<span matPrefix>GH¢ </span> |
|||
<input disabled matInput style="margin-left:10px;" type="number" |
|||
value={{product.unitPrice}}> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
<div class="columns" style="display: flex;justify-content:space-around;"> |
|||
<div class="column"> |
|||
<div> |
|||
<strong class="tileHead">Product Description :</strong> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="column"> |
|||
<quill-editor [modules]="quillConfig" [(ngModel)]=product.productDesc |
|||
placeholder="Further details"> |
|||
|
|||
</quill-editor> |
|||
</div> |
|||
|
|||
</div> |
|||
</mat-tab> |
|||
<mat-tab label="Images"> |
|||
<div class="py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8" |
|||
style="min-height: 550px !important;"> |
|||
<div class="flex justify-between"> |
|||
<div> |
|||
<div class="font-medium tracking-tight text-secondary">Add up to 10 high |
|||
quality images of the product |
|||
</div> |
|||
<div class="font-medium tracking-tight text-secondary"> |
|||
{{productImages.length}} out of |
|||
<strong>10</strong> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
<div class="imageList"> |
|||
<div class="imageHolder" *ngFor="let images of product.images"> |
|||
<img src="{{images.imageSRC}}" class="productImage"> |
|||
<button class="deleteelement" style="border:none;" |
|||
(click)="removeImage(images)"> |
|||
<mat-icon [svgIcon]="'heroicons_outline:trash'" style="color: red;"> |
|||
</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
</mat-tab-group> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-drawer-content> |
|||
</mat-drawer-container> |
|||
</div> |
|||
<div class="absolute inset-0 flex flex-col min-w-0 " *ngIf="isScreenSmall"> |
|||
|
|||
<mat-drawer-container class="flex-auto h-full"> |
|||
<!-- Drawer content --> |
|||
<mat-drawer-content class="flex flex-col"> |
|||
<!-- Header --> |
|||
<div |
|||
class="flex flex-0 items-center py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 border-b lg:border-b-0 bg-card dark:bg-transparent"> |
|||
<!-- Title & Actions --> |
|||
<button mat-icon-button [routerLink]="['../../']"> |
|||
<mat-icon [svgIcon]="'heroicons_outline:arrow-sm-left'"></mat-icon> |
|||
</button> |
|||
<h2 class="ml-2.5 text-md sm:text-xl font-medium tracking-tight truncate"> |
|||
Product # {{product.productID}} |
|||
</h2> |
|||
</div> |
|||
<div |
|||
class=" flex flex-0 items-center py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 border-b lg:border-b-0 bg-card dark:bg-transparent"> |
|||
<div class="flex-auto overflow-y-auto" cdkScrollable> |
|||
<div class="min-h-180 border-2 border-dashed border-gray-300 rounded-2xl py-2 pl-4 pr-6 sm:py-4 md:pl-6 md:pr-8 mx-auto" |
|||
style="max-width: 780px;"> |
|||
<mat-tab-group mat-align-tabs="center"> |
|||
<mat-tab label="Product Information"> |
|||
<div class=" py-2 pl-3 pr-3 sm:py-4 md:pl-4 md:pr-6" |
|||
style="overflow-y: hidden !important;"> |
|||
<div style="display: flex;"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong>Product Name </strong> |
|||
</mat-label> |
|||
<mat-label>{{product.productName}}</mat-label> |
|||
</div> |
|||
<hr/> |
|||
<div style="display:flex;"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong>Product Category</strong> |
|||
</mat-label> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<span style="font-size: 13px;">{{product.categoryID}}</span> |
|||
</mat-label> |
|||
</div> |
|||
<hr/> |
|||
<div style="display: flex;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong>Original Price </strong> |
|||
</mat-label> |
|||
<mat-label> |
|||
{{product.unitPrice | currency:"GHS "}} |
|||
</mat-label> |
|||
</div> |
|||
<hr/> |
|||
<div class="columns" style="display: flex;justify-content:space-around;"> |
|||
<div class="column"> |
|||
<div> |
|||
<strong>Product Description :</strong> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="column"> |
|||
<quill-editor [modules]="quillConfig" [(ngModel)]="product.productDesc" |
|||
placeholder="Further details"> |
|||
|
|||
</quill-editor> |
|||
</div> |
|||
|
|||
</div> |
|||
</mat-tab> |
|||
<mat-tab label="Images"> |
|||
<div class="py-2 pl-2 pr-2 sm:py-4 md:pl-6 md:pr-8"> |
|||
<div class="flex justify-between"> |
|||
<div> |
|||
<div class="font-medium tracking-tight text-secondary">Add up to 10 high |
|||
quality images of the product |
|||
</div> |
|||
<div class="font-medium tracking-tight text-secondary">0 out of |
|||
<strong>10</strong> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="imageList"> |
|||
<div class="imageHolder" *ngFor="let images of productImages"> |
|||
<img src="{{images.imageSRC}}" class="productImage"> |
|||
<button class="deleteelement" style="border:none;" |
|||
(click)="removeImage(images)"> |
|||
<mat-icon [svgIcon]="'heroicons_outline:trash'" style="color: red;"> |
|||
</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-tab> |
|||
</mat-tab-group> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</mat-drawer-content> |
|||
</mat-drawer-container> |
|||
</div> |
@ -0,0 +1,78 @@ |
|||
.columns { |
|||
display: flex; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
width: 100%; |
|||
} |
|||
|
|||
.column { |
|||
flex: 50%; |
|||
font-size: medium; |
|||
} |
|||
|
|||
.tileHead { |
|||
font-size: 17px; |
|||
color: #003445; |
|||
font-family: Roboto, "Helvetica Neue", sans-serif; |
|||
line-height: 3rem; |
|||
} |
|||
|
|||
.ticketLine > a:hover { |
|||
color: cornflowerblue; |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
.ticketLine > a { |
|||
color: cornflowerblue; |
|||
font-style: italic; |
|||
} |
|||
|
|||
::ng-deep { |
|||
@media screen and (min-width: 992px) { |
|||
.ql-container .ql-editor { |
|||
min-height: 160px; |
|||
max-height: 270px; |
|||
height: 270px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.imageList { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.imageHolder { |
|||
flex-grow: 1; |
|||
width: 22%; |
|||
max-width: 180px; |
|||
height: 180px; |
|||
margin: 10px; |
|||
border: 3px solid #003445; |
|||
padding: 5px; |
|||
position: relative; |
|||
} |
|||
.productImage{ |
|||
max-width: 130px; |
|||
margin: 10px; |
|||
} |
|||
.deleteelement { |
|||
position: absolute; |
|||
top: 5px; |
|||
right: 5px; |
|||
|
|||
} |
|||
|
|||
@media screen and (max-width: 992px) { |
|||
.imageHolder { |
|||
flex-grow: 1; |
|||
width: 22%; |
|||
max-width: 180px; |
|||
min-width: 180px; |
|||
height: 180px; |
|||
margin: 10px; |
|||
border: 3px solid #003445; |
|||
padding: 5px; |
|||
position: relative; |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { DetailsProductComponent } from './details-product.component'; |
|||
|
|||
describe('DetailsProductComponent', () => { |
|||
let component: DetailsProductComponent; |
|||
let fixture: ComponentFixture<DetailsProductComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ DetailsProductComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(DetailsProductComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,151 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { MatDialog } from '@angular/material/dialog'; |
|||
import { Router, ActivatedRoute } from '@angular/router'; |
|||
import { ConfirmBoxEvokeService } from '@costlydeveloper/ngx-awesome-popup'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { ProductUpload } from 'app/models/generalModel'; |
|||
import { ProductsModel } from 'app/models/productsModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { ProductsService } from '../products.service'; |
|||
const modules = { |
|||
toolbar: [ |
|||
[], |
|||
[], |
|||
|
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
|
|||
[], |
|||
[], |
|||
|
|||
[], |
|||
[], |
|||
[], |
|||
|
|||
[], |
|||
|
|||
|
|||
] |
|||
}; |
|||
|
|||
@Component({ |
|||
selector: 'app-details-product', |
|||
templateUrl: './details-product.component.html', |
|||
styleUrls: ['./details-product.component.scss'] |
|||
}) |
|||
export class DetailsProductComponent implements OnInit { |
|||
productID: string; |
|||
title: string; |
|||
status: string = "Status"; |
|||
htmlRequest: string; |
|||
transferType: string; |
|||
placeHolder: string = ""; |
|||
selected: any; |
|||
isScreenSmall: boolean; |
|||
productImages: ProductUpload[] = []; |
|||
product: ProductsModel; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(private _tesoMediaWatcherService: tesoMediaWatcherService, |
|||
private confirmBoxEvokeService: ConfirmBoxEvokeService, |
|||
private router: Router, private route: ActivatedRoute, private productServie: ProductsService) { |
|||
var snapshot = route.snapshot; |
|||
this.productID = snapshot.paramMap.get('id'); |
|||
this.product = productServie.getProduct(this.productID); |
|||
if(this.product == null){ |
|||
this.router.navigate(['products']); |
|||
} |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this._tesoMediaWatcherService.onMediaChange$ |
|||
.pipe(takeUntil(this._unsubscribeAll)) |
|||
.subscribe(({ matchingAliases }) => { |
|||
|
|||
// Check if the screen is small
|
|||
this.isScreenSmall = !matchingAliases.includes('md'); |
|||
}); |
|||
} |
|||
quillConfig = modules; |
|||
items = [ |
|||
{ id: 1, name: 'Python' }, |
|||
{ id: 2, name: 'Node Js' }, |
|||
{ id: 3, name: 'Java' }, |
|||
{ id: 4, name: 'PHP', disabled: true }, |
|||
{ id: 5, name: 'Django' }, |
|||
{ id: 6, name: 'Angular' }, |
|||
{ id: 7, name: 'Vue' }, |
|||
{ id: 8, name: 'ReactJs' }, |
|||
]; |
|||
ngOnDestroy(): void { |
|||
// Unsubscribe from all subscriptions
|
|||
this._unsubscribeAll.next(); |
|||
this._unsubscribeAll.complete(); |
|||
} |
|||
|
|||
// readURL(event: Event): void {
|
|||
// if (event.target.files && event.target.files[0]) {
|
|||
// const file = event.target.files[0];
|
|||
|
|||
// const reader = new FileReader();
|
|||
// reader.onload = e => this.imageSrc = reader.result;
|
|||
|
|||
// reader.readAsDataURL(file);
|
|||
// }
|
|||
// }
|
|||
onFileSelected(event) { |
|||
|
|||
const file: File = event.target.files[0]; |
|||
if (file.type.includes("image")) { |
|||
console.log(file) |
|||
if (this.productImages.length == 0) { |
|||
var productImage: ProductUpload = { |
|||
file: file, |
|||
highlight: true, |
|||
imageSRC: "", |
|||
}; |
|||
let reader = new FileReader(); |
|||
reader.onload = (event: any) => { |
|||
productImage.imageSRC = event.target.result; |
|||
} |
|||
reader.readAsDataURL(file); |
|||
|
|||
this.productImages.push(productImage); |
|||
|
|||
} else { |
|||
var productImage: ProductUpload = { |
|||
file: file, |
|||
highlight: false, |
|||
imageSRC: "", |
|||
}; |
|||
|
|||
let reader = new FileReader(); |
|||
reader.onload = (event: any) => { |
|||
productImage.imageSRC = event.target.result; |
|||
} |
|||
reader.readAsDataURL(file); |
|||
|
|||
this.productImages.push(productImage); |
|||
} |
|||
} else { |
|||
this.confirmBoxEvokeService.danger("Incompatible File", "Only images can be added", "OK").subscribe(); |
|||
} |
|||
} |
|||
|
|||
removeImage(item: ProductUpload) { |
|||
this.productImages = this.productImages.filter((e) => e != item); |
|||
} |
|||
|
|||
submit() { |
|||
if (this.productImages.length == 0) { |
|||
this.confirmBoxEvokeService.warning("Add Product Images", "To add a new product, you must add at least one image to support it", "OK").subscribe(); |
|||
} else { |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,73 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { analytics as analyticsData } from 'app/mock-api/dashboards/analytics/data'; |
|||
import { environment } from 'environments/environment'; |
|||
import { ProductsModule } from './products.module'; |
|||
import { ProductCategory, ProductsModel } from 'app/models/productsModel'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class ProductsService { |
|||
private _data: BehaviorSubject<any> = new BehaviorSubject(null); |
|||
private _dataFilterable: BehaviorSubject<any> = new BehaviorSubject(null); |
|||
private products: ProductsModel[] = []; |
|||
private _productsCategory: BehaviorSubject<ProductCategory[]> = new BehaviorSubject(null); |
|||
|
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor(private _httpClient: HttpClient) { |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Accessors
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Getter for data |
|||
*/ |
|||
get data$(): Observable<ProductsModel[]> { |
|||
return this._dataFilterable.asObservable(); |
|||
} |
|||
get dataProductsPageOnly$(): Observable<ProductsModel[]> { |
|||
return this._data.asObservable(); |
|||
} |
|||
get categories$(): Observable<ProductCategory[]> { |
|||
return this._productsCategory.asObservable(); |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Get data |
|||
*/ |
|||
getData(): Observable<ProductsModel[]> { |
|||
return this._httpClient.get(environment.apiURL + `products/allproducts`).pipe( |
|||
tap((response: ProductsModel[]) => { |
|||
this._data.next(response); |
|||
this._dataFilterable.next(response); |
|||
this.products = response; |
|||
}) |
|||
); |
|||
} |
|||
filterProducts(productName: string): ProductsModel[] { |
|||
return this._dataFilterable.getValue().filter(p => p.productName.toLowerCase().includes(productName)); |
|||
// this.products = response;
|
|||
} |
|||
getProduct(id: string): ProductsModel { |
|||
const found = this.products.find(item => item.productID === id); |
|||
return found; |
|||
} |
|||
|
|||
getCategories(): Observable<ProductCategory[]> { |
|||
return this._httpClient.get(environment.apiURL + `productcategories`).pipe( |
|||
tap((response: ProductCategory[]) => { |
|||
this._productsCategory.next(response); |
|||
})); |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
<div class="row" style="display: flex;justify-content:space-between"> |
|||
<div class="row" style="display: flex;justify-content:center;width: 100%;"> |
|||
<h2 mat-dialog-title style="text-align: center;">Shop Description</h2> |
|||
</div> |
|||
<button mat-button [mat-dialog-close]="data.details" cdkFocusInitial>x</button> |
|||
</div> |
|||
<mat-dialog-content class="mat-typography"> |
|||
<quill-editor [modules]="quillConfig" [(ngModel)]="data.details" |
|||
placeholder="Further details"> |
|||
|
|||
</quill-editor> |
|||
</mat-dialog-content> |
@ -0,0 +1,25 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { DescriptionDialogComponent } from './description-dialog.component'; |
|||
|
|||
describe('DescriptionDialogComponent', () => { |
|||
let component: DescriptionDialogComponent; |
|||
let fixture: ComponentFixture<DescriptionDialogComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ DescriptionDialogComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(DescriptionDialogComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,44 @@ |
|||
import { Component, Inject, OnInit } from '@angular/core'; |
|||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; |
|||
import { TesoBusinessDetail } from 'app/models/businessModel'; |
|||
const modules = { |
|||
toolbar: [ |
|||
['bold', 'italic', 'underline', 'strike'], |
|||
['blockquote', 'code-block'], |
|||
|
|||
[{ 'header': 1 }, { 'header': 2 }], |
|||
[{ 'list': 'ordered' }, { 'list': 'bullet' }], |
|||
[{ 'script': 'sub' }, { 'script': 'super' }], |
|||
[{ 'indent': '-1' }, { 'indent': '+1' }], |
|||
[{ 'direction': 'rtl' }], |
|||
|
|||
[{ 'size': ['small', false, 'large', 'huge'] }], |
|||
[{ 'header': [1, 2, 3, 4, 5, 6, false] }], |
|||
|
|||
[{ 'color': [] }, { 'background': [] }], |
|||
[{ 'font': [] }], |
|||
[{ 'align': [] }], |
|||
|
|||
['clean'], |
|||
['link'] |
|||
|
|||
] |
|||
}; |
|||
|
|||
|
|||
@Component({ |
|||
selector: 'app-description-dialog', |
|||
templateUrl: './description-dialog.component.html', |
|||
styleUrls: ['./description-dialog.component.scss'] |
|||
}) |
|||
export class DescriptionDialogComponent implements OnInit { |
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { details: string }, |
|||
public dialogRef: MatDialogRef<DescriptionDialogComponent>,) { } |
|||
quillConfig = modules; |
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
closeDialog() { |
|||
this.dialogRef.close(this.data.details); |
|||
} |
|||
} |
@ -0,0 +1,83 @@ |
|||
<div class="row" style="display: flex;justify-content:space-between;"> |
|||
<div class="row" style="display: flex;justify-content:center;width: 100%;"> |
|||
<h3 mat-dialog-title style="text-align: center;">Business Information</h3> |
|||
</div> |
|||
<button mat-button [mat-dialog-close]="data.details" cdkFocusInitial>x</button> |
|||
</div> |
|||
<mat-dialog-content class="mat-typography"> |
|||
<div class=" py-2 pl-3 pr-3 sm:py-4 md:pl-4 md:pr-6" style="overflow-y: hidden !important;"> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Shop Name </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input matInput style="margin-left:10px;" type="text" [(ngModel)]="data.details.businessName"> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong class="tileHead">Shop Category</strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<mat-select [(ngModel)]="selectedCategory"> |
|||
<mat-option *ngFor="let category of businessCategories" [value]="category"> |
|||
{{category.categoryName}} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Physical Address </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input matInput style="margin-left:10px;" type="text" [(ngModel)]="data.details.businessAddress"> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Digital Address </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<span matPrefix> |
|||
<a href="https://ghanapostgps.com/map/" target="blank"> |
|||
<mat-icon class="icon-size-5" [svgIcon]="'heroicons_solid:information-circle'" |
|||
style="color: #0152cc;" matTooltip="visit https://ghanapostgps.com/map/"> |
|||
</mat-icon> |
|||
</a> |
|||
</span> |
|||
<input matInput style="margin-left:10px;" type="text" [(ngModel)]="data.details.businessDigitalAddress"> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Date Of Establishment </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input matInput style="margin-left:10px;" type="date" [(ngModel)]="data.details.dateOfEst"> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Telephone </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input matInput style="margin-left:10px;" type="text" [(ngModel)]="data.details.businessContact" |
|||
disabled> |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Email Address </strong> |
|||
</mat-label> |
|||
<mat-form-field appearance="fill" style="width: 350px;"> |
|||
<input matInput style="margin-left:10px;" type="text" [(ngModel)]="data.details.businessEmail" disabled> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
<div style="display: flex;justify-content:center;width: 100%;"> |
|||
<button mat-button style="background-color: green;color: white;">Confirm Changes</button> |
|||
</div> |
|||
</div> |
|||
</mat-dialog-content> |
@ -0,0 +1,28 @@ |
|||
.columns { |
|||
display: flex; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
width: 100%; |
|||
} |
|||
|
|||
.column { |
|||
flex: 50%; |
|||
font-size: medium; |
|||
} |
|||
|
|||
.tileHead { |
|||
font-size: 17px; |
|||
color: #003445; |
|||
font-family: Roboto, "Helvetica Neue", sans-serif; |
|||
line-height: 3rem; |
|||
} |
|||
|
|||
.ticketLine > a:hover { |
|||
color: cornflowerblue; |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
.ticketLine > a { |
|||
color: cornflowerblue; |
|||
font-style: italic; |
|||
} |
@ -0,0 +1,25 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { InformationDialogComponent } from './information-dialog.component'; |
|||
|
|||
describe('InformationDialogComponent', () => { |
|||
let component: InformationDialogComponent; |
|||
let fixture: ComponentFixture<InformationDialogComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ InformationDialogComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(InformationDialogComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
|||
|
|||
it('should create', () => { |
|||
expect(component).toBeTruthy(); |
|||
}); |
|||
}); |
@ -0,0 +1,35 @@ |
|||
import { Component, Inject, OnInit } from '@angular/core'; |
|||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
|||
import { UserService } from 'app/core/user/user.service'; |
|||
import { BusinessCategory, TesoBusinessDetail } from 'app/models/businessModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { ProfileService } from '../profile.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-information-dialog', |
|||
templateUrl: './information-dialog.component.html', |
|||
styleUrls: ['./information-dialog.component.scss'] |
|||
}) |
|||
export class InformationDialogComponent implements OnInit { |
|||
businessCategories: BusinessCategory[] = []; |
|||
selectedCategory: BusinessCategory; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(@Inject(MAT_DIALOG_DATA) public data: { details: TesoBusinessDetail }, |
|||
public dialogRef: MatDialogRef<InformationDialogComponent>, private _profileService: ProfileService, |
|||
private _userService:UserService) { } |
|||
ngOnInit(): void { |
|||
this._profileService.categories$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.businessCategories = d; |
|||
this.selectedCategory = this.businessCategories.find((c)=> c.categoryCode.toLowerCase() == this.data.details.businessCategory.toLowerCase()); |
|||
}); |
|||
} |
|||
|
|||
closeDialog() { |
|||
this.data.details.businessCategory = this.selectedCategory.categoryCode; |
|||
|
|||
this._userService.update(this.data.details); |
|||
this.dialogRef.close(true); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,53 @@ |
|||
<div class="InfoHold"> |
|||
<div style="display: flex;justify-content: space-between;max-height: 46px;align-items: center;"> |
|||
<div> |
|||
<h4> |
|||
<mat-icon class="icon-size-5" [svgIcon]="'heroicons_solid:information-circle'"></mat-icon> Business |
|||
Information |
|||
</h4> |
|||
</div> |
|||
<div> |
|||
<button mat-button style="background-color: #0152cc;color: white;" (click)="editShopInformation()">Edit Information</button> |
|||
</div> |
|||
</div> |
|||
<mat-divider class="my-2"></mat-divider> |
|||
<table style="width: 100%;" > |
|||
<tbody> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Shop Name: </th> |
|||
<td id="business-name-id">{{details.businessName}}</td> |
|||
</tr> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Shop Category: </th> |
|||
<td id="shop-category1">{{currentCategory}}</td> |
|||
</tr> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Physical Address: </th> |
|||
<td id="physicaladdress1">{{details.businessAddress}}</td> |
|||
</tr> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Digital Address: </th> |
|||
<td id="digitaladdress1">{{details.businessDigitalAddress}}</td> |
|||
</tr> |
|||
|
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Date of Establishment: </th> |
|||
<td id="dateest1"> |
|||
{{details.dateOfEst | date}}</td> |
|||
</tr> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Phone Number: </th> |
|||
<td id="tel-id">{{details.businessContact}}</td> |
|||
</tr> |
|||
<tr class="tableau"> |
|||
<th scope="row" class="text-dark">Email Address: </th> |
|||
<td id="email-id">{{details.businessEmail}}</td> |
|||
</tr> |
|||
|
|||
|
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
<div class="text-center" style="margin-top:10px;"> |
|||
<!-- <RadzenButton Text="Save Changes" Click="editProduct" Style="background-color:forestgreen !important;" /> --> |
|||
</div> |
@ -0,0 +1,12 @@ |
|||
.InfoHold{ |
|||
padding-left: 5%; |
|||
padding-right: 5%; |
|||
} |
|||
.tableau{ |
|||
margin: 20px; |
|||
height: 45px; |
|||
padding: 20px; |
|||
border-bottom: 1px solid gray; |
|||
text-align: start; |
|||
align-items: flex-start; |
|||
} |
@ -1,20 +1,20 @@ |
|||
import { ComponentFixture, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { EditProductComponent } from './edit-product.component'; |
|||
import { InformationComponent } from './information.component'; |
|||
|
|||
describe('EditProductComponent', () => { |
|||
let component: EditProductComponent; |
|||
let fixture: ComponentFixture<EditProductComponent>; |
|||
describe('InformationComponent', () => { |
|||
let component: InformationComponent; |
|||
let fixture: ComponentFixture<InformationComponent>; |
|||
|
|||
beforeEach(async () => { |
|||
await TestBed.configureTestingModule({ |
|||
declarations: [ EditProductComponent ] |
|||
declarations: [ InformationComponent ] |
|||
}) |
|||
.compileComponents(); |
|||
}); |
|||
|
|||
beforeEach(() => { |
|||
fixture = TestBed.createComponent(EditProductComponent); |
|||
fixture = TestBed.createComponent(InformationComponent); |
|||
component = fixture.componentInstance; |
|||
fixture.detectChanges(); |
|||
}); |
@ -0,0 +1,51 @@ |
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; |
|||
import { MatDialog } from '@angular/material/dialog'; |
|||
import { MatTableDataSource } from '@angular/material/table'; |
|||
import { Router } from '@angular/router'; |
|||
import { ConfirmBoxEvokeService } from '@costlydeveloper/ngx-awesome-popup'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { UserService } from 'app/core/user/user.service'; |
|||
import { BusinessCategory, TesoBusinessDetail } from 'app/models/businessModel'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { FollowersService } from '../../Followers/followers.service'; |
|||
import { DescriptionDialogComponent } from '../DescriptionDialog/description-dialog.component'; |
|||
import { InformationDialogComponent } from '../InfoDialog/information-dialog.component'; |
|||
import { ProfileService } from '../profile.service'; |
|||
|
|||
@Component({ |
|||
selector: 'business-information', |
|||
templateUrl: './information.component.html', |
|||
styleUrls: ['./information.component.scss'], |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
exportAs: 'business-information' |
|||
}) |
|||
export class InformationComponent implements OnInit { |
|||
@Input() details: TesoBusinessDetail; |
|||
currentCategory: string; |
|||
categories: BusinessCategory[] = []; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(private router: Router, private _tesoMediaWatcherService: tesoMediaWatcherService, |
|||
private _profileService: ProfileService, private _changeRef: ChangeDetectorRef, |
|||
public dialog: MatDialog, |
|||
private confirmBoxEvokeService: ConfirmBoxEvokeService, private _userService: UserService) { } |
|||
|
|||
ngOnInit(): void { |
|||
this._profileService.categories$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.categories = d; |
|||
this.currentCategory = d.find(c => c.categoryCode == this.details.businessCategory).categoryName; |
|||
}); |
|||
} |
|||
editShopInformation() { |
|||
const dialogReference = this.dialog.open(InformationDialogComponent, { |
|||
disableClose: true, |
|||
hasBackdrop: true, |
|||
data: { details: this.details }, |
|||
}); |
|||
|
|||
dialogReference.afterClosed().subscribe((d) => { |
|||
if (d) |
|||
this._userService.get(); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
<mat-dialog-content class="mat-typography"> |
|||
<div class=" py-2 pl-3 pr-3 sm:py-4 md:pl-4 md:pr-6" style="overflow-y: hidden !important;"> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-form-field appearance="outline" style="width: 350px;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Old Password </strong> |
|||
</mat-label> |
|||
<input matInput style="margin-left:10px;" type="password" > |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-form-field appearance="outline" style="width: 350px;"> |
|||
<mat-label style="margin-right: 20px;"> |
|||
<strong class="tileHead">New Password</strong> |
|||
</mat-label> |
|||
<input matInput style="margin-left:10px;" type="password" > |
|||
</mat-form-field> |
|||
</div> |
|||
<div style="display: flex;justify-content:space-between;"> |
|||
<mat-form-field appearance="outline" style="width: 350px;"> |
|||
<mat-label style="margin-right: 48px;"> |
|||
<strong class="tileHead">Confirm Password </strong> |
|||
</mat-label> |
|||
<input matInput style="margin-left:10px;" type="password"> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
<div style="display: flex;justify-content:space-between;width: 100%;"> |
|||
<button mat-button style="background-color: green;color: white;">Confirm</button> |
|||
<button mat-button style="background-color: maroon;color: white;" [mat-dialog-close]="true" cdkFocusInitial>Cancel</button> |
|||
</div> |
|||
</div> |
|||
</mat-dialog-content> |
@ -0,0 +1,17 @@ |
|||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'settings', |
|||
templateUrl: './settings.component.html', |
|||
styleUrls: ['./settings.component.scss'], |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
exportAs: 'settings' |
|||
}) |
|||
export class SettingsComponent implements OnInit { |
|||
|
|||
constructor() { } |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
} |
@ -1 +1,66 @@ |
|||
<p>profile works!</p> |
|||
<!-- <div class="flex flex-col flex-auto w-full"> |
|||
<div class="flex flex-wrap w-full max-w-screen-xl mx-auto p-6 md:p-8"> --> |
|||
<div class="columns"> |
|||
<div class="col-md-3"> |
|||
<div class="card card-primary card-outline"> |
|||
<div class="card-body box-profile"> |
|||
<form> |
|||
<input style="display: none" type="file" (change)="onFileSelected($event)" |
|||
#fileInput accept="image/*"> |
|||
<div class="text-center"> |
|||
<img id="logo" class="profile-user-img img-fluid img-circle" [src]="imageLoader(profile.businessLogo)" |
|||
style="height:150px;width:150px;" *ngIf="newProfilePicture === undefined"> |
|||
<img id="logo" class="profile-user-img img-fluid img-circle" src="{{newProfilePicture.imageSRC}}" |
|||
style="height:150px;width:150px;" *ngIf="newProfilePicture != undefined"> |
|||
</div> |
|||
<div class="text-center" style="margin-top:10px;"> |
|||
<button mat-button style="background-color: #0152cc;color: white;" |
|||
(click)="fileInput.click()" *ngIf="newProfilePicture === undefined">Select</button> |
|||
<button mat-button style="background-color: rgb(163, 35, 35);color: white;" |
|||
(click)="clear()" *ngIf="newProfilePicture != undefined">Clear</button> |
|||
</div> |
|||
|
|||
</form> |
|||
|
|||
<h3 class="profile-username text-center">{{profile.businessName}}</h3> |
|||
<ul class="list-group list-group-unbordered mb-3"> |
|||
<li class="list-group-item"> |
|||
<b style="margin-right: 10px;">Followers : </b> |
|||
<a href="followers" class="float-right" style="text-decoration: none;color: #0152cc;"> {{subscribers.length}}</a> |
|||
</li> |
|||
<li class="list-group-item"> |
|||
<button class=" sm:inline-flex" mat-flat-button style="background-color: #0152cc;margin-right:10px;"> |
|||
<a href="javascript:void(0)" style="color: #fff;text-decoration: none;margin-right:10px;" >Generate QR-Code</a> |
|||
</button> |
|||
<!-- <a class="btn btn-secondary btn-lg" onclick="generateCode"></a> --> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
<div class="card card-primary"> |
|||
<div class="card-header" style="display: flex;justify-content: space-between;"> |
|||
<h3 class="card-title">Shop Description</h3> |
|||
<!-- <div class="card-tools" (click)="openEdit()"> --> |
|||
<button mat-button style="background: transparent;" (click)="editShopDescription()"> |
|||
<mat-icon class="icon-size-3" [svgIcon]="'heroicons_solid:pencil-alt'" style="color: #fff;"></mat-icon> |
|||
</button> |
|||
<!-- </div> --> |
|||
</div> |
|||
<div class="card-body"> |
|||
<p class="text-muted"> |
|||
<strong><i class="fas fa-book mr-1"></i> </strong> |
|||
<span id="shop-desc">{{profile.businessDescription}}</span> |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-9"> |
|||
<div class="card"> |
|||
<business-information [details]="profile"></business-information> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- </div> |
|||
</div> --> |
@ -0,0 +1,173 @@ |
|||
.card-primary.card-outline { |
|||
border-top: 3px solid #0152cc; |
|||
} |
|||
.card-primary:not(.card-outline) > .card-header, .card-primary:not(.card-outline) > .card-header a { |
|||
color: #fff; |
|||
} |
|||
.card-primary:not(.card-outline) > .card-header { |
|||
background-color: #0152cc; |
|||
} |
|||
|
|||
.card { |
|||
box-shadow: 0 0 1px rgb(0 0 0 / 13%), 0 1px 3px rgb(0 0 0 / 20%); |
|||
margin-bottom: 1rem; |
|||
} |
|||
.card-header { |
|||
background-color: transparent; |
|||
border-bottom: 1px solid rgba(0,0,0,.125); |
|||
padding: .75rem 1.25rem; |
|||
position: relative; |
|||
border-top-left-radius: .25rem; |
|||
border-top-right-radius: .25rem; |
|||
} |
|||
|
|||
.list-group-unbordered > .list-group-item { |
|||
border-left: 0; |
|||
border-radius: 0; |
|||
border-right: 0; |
|||
padding-left: 0; |
|||
padding-right: 0; |
|||
} |
|||
.list-group-item { |
|||
position: relative; |
|||
display: block; |
|||
padding: .75rem 1.25rem; |
|||
background-color: #fff; |
|||
border: 1px solid rgba(0,0,0,.125); |
|||
} |
|||
|
|||
|
|||
|
|||
.card-body { |
|||
-ms-flex: 1 1 auto; |
|||
flex: 1 1 auto; |
|||
min-height: 1px; |
|||
padding: 1.25rem; |
|||
} |
|||
|
|||
|
|||
.card-body { |
|||
-ms-flex: 1 1 auto; |
|||
flex: 1 1 auto; |
|||
min-height: 1px; |
|||
padding: 1.25rem; |
|||
} |
|||
form { |
|||
display: block; |
|||
margin-top: 0em; |
|||
} |
|||
.img-circle { |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
.profile-user-img { |
|||
border: 3px solid #adb5bd; |
|||
margin: 0 auto; |
|||
padding: 3px; |
|||
width: 100px; |
|||
} |
|||
|
|||
.img-fluid { |
|||
max-width: 100%; |
|||
height: auto; |
|||
} |
|||
|
|||
img { |
|||
vertical-align: middle; |
|||
border-style: none; |
|||
} |
|||
|
|||
|
|||
|
|||
.text-center { |
|||
text-align: center !important; |
|||
} |
|||
|
|||
.card-title { |
|||
float: left; |
|||
font-size: 1.1rem; |
|||
font-weight: 400; |
|||
margin: 0; |
|||
} |
|||
|
|||
.card-title { |
|||
margin-bottom: .75rem; |
|||
} |
|||
|
|||
.card { |
|||
position: relative; |
|||
display: -ms-flexbox; |
|||
display: flex; |
|||
-ms-flex-direction: column; |
|||
flex-direction: column; |
|||
min-width: 0; |
|||
word-wrap: break-word; |
|||
background-color: #fff; |
|||
background-clip: border-box; |
|||
border: 0 solid rgba(0,0,0,.125); |
|||
border-radius: .25rem; |
|||
} |
|||
|
|||
.card { |
|||
position: relative; |
|||
display: -ms-flexbox; |
|||
display: flex; |
|||
-ms-flex-direction: column; |
|||
flex-direction: column; |
|||
min-width: 0; |
|||
word-wrap: break-word; |
|||
background-color: #fff; |
|||
background-clip: border-box; |
|||
border: 0 solid rgba(0,0,0,.125); |
|||
border-radius: .25rem; |
|||
padding-top: 30px; |
|||
} |
|||
|
|||
.ui-button.btn-primary, .btn-primary.ui-paginator-element { |
|||
background-color: #0152cc; |
|||
} |
|||
|
|||
.logo { |
|||
display: block; |
|||
width: 100px; |
|||
margin: 0px auto; |
|||
border-radius: 20px; |
|||
background: #222; |
|||
padding: 10px; |
|||
} |
|||
|
|||
.columns { |
|||
display: flex; |
|||
flex-direction: row; |
|||
width: 100%; |
|||
} |
|||
@media only screen and (max-width: 600px) { |
|||
.columns { |
|||
display: flex; |
|||
flex-direction:row; |
|||
flex-wrap: wrap; |
|||
width: 100%; |
|||
} |
|||
.col-md-9{ |
|||
flex: 30%; |
|||
font-size: medium; |
|||
margin: 10px; |
|||
padding: 10px; |
|||
} |
|||
} |
|||
.column { |
|||
flex: 50%; |
|||
font-size: medium; |
|||
} |
|||
.col-md-3{ |
|||
flex: 30%; |
|||
font-size: medium; |
|||
margin: 10px; |
|||
padding: 10px; |
|||
} |
|||
.col-md-9{ |
|||
flex: 70%; |
|||
font-size: medium; |
|||
margin: 10px; |
|||
padding: 10px; |
|||
} |
@ -1,15 +1,75 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; |
|||
import { MatDialog } from '@angular/material/dialog'; |
|||
import { Router } from '@angular/router'; |
|||
import { ConfirmBoxEvokeService } from '@costlydeveloper/ngx-awesome-popup'; |
|||
import { tesoMediaWatcherService } from '@teso/services/media-watcher'; |
|||
import { UserService } from 'app/core/user/user.service'; |
|||
import { TesoBusinessDetail } from 'app/models/businessModel'; |
|||
import { TesoUserDetails } from 'app/models/userModel'; |
|||
import { environment } from 'environments/environment'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
import { FollowersService } from '../Followers/followers.service'; |
|||
import { DescriptionDialogComponent } from './DescriptionDialog/description-dialog.component'; |
|||
import { ProfileService } from './profile.service'; |
|||
|
|||
@Component({ |
|||
selector: 'app-profile', |
|||
templateUrl: './profile.component.html', |
|||
styleUrls: ['./profile.component.scss'] |
|||
styleUrls: ['./profile.component.scss'], |
|||
encapsulation: ViewEncapsulation.ShadowDom, |
|||
}) |
|||
export class ProfileComponent implements OnInit { |
|||
|
|||
constructor() { } |
|||
profile: TesoBusinessDetail = {}; |
|||
subscribers:TesoUserDetails[]=[]; |
|||
newProfilePicture:any; |
|||
private _unsubscribeAll: Subject<any> = new Subject<any>(); |
|||
constructor(private router: Router, private _tesoMediaWatcherService: tesoMediaWatcherService, |
|||
private _profileService: ProfileService, private _userService: UserService, |
|||
private _followersService: FollowersService, public dialog: MatDialog, |
|||
private confirmBoxEvokeService: ConfirmBoxEvokeService,) { } |
|||
|
|||
ngOnInit(): void { |
|||
this._userService.user$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.profile = d; |
|||
}); |
|||
this._followersService.data$.pipe(takeUntil(this._unsubscribeAll)).subscribe((d) => { |
|||
this.subscribers = d; |
|||
}); |
|||
} |
|||
imageLoader(path: string): string { |
|||
return environment.apiURL + `shoplogo/${path}`; |
|||
} |
|||
editShopDescription(){ |
|||
const dialogReference = this.dialog.open(DescriptionDialogComponent,{ |
|||
disableClose: true, |
|||
hasBackdrop: true, |
|||
data: { details: this.profile.businessDescription }, |
|||
}); |
|||
|
|||
dialogReference.afterClosed().subscribe((d)=> { |
|||
this.profile.businessDescription = d; |
|||
}); |
|||
} |
|||
onFileSelected(event) { |
|||
|
|||
const file: File = event.target.files[0]; |
|||
if (file.type.includes("image")) { |
|||
this.newProfilePicture = { |
|||
file: file, |
|||
highlight: true, |
|||
imageSRC: "", |
|||
}; |
|||
let reader = new FileReader(); |
|||
reader.onload = (event: any) => { |
|||
this.newProfilePicture.imageSRC = event.target.result; |
|||
} |
|||
reader.readAsDataURL(file); |
|||
} else { |
|||
this.confirmBoxEvokeService.danger("Incompatible File", "Only images can be added", "OK").subscribe(); |
|||
} |
|||
} |
|||
clear(){ |
|||
this.newProfilePicture={}; |
|||
} |
|||
} |
|||
|
@ -1,12 +1,66 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { ProfileComponent } from './profile.component'; |
|||
import { RouterModule } from '@angular/router'; |
|||
import { QuillModule } from 'ngx-quill'; |
|||
import { MatButtonModule } from '@angular/material/button'; |
|||
import { MatButtonToggleModule } from '@angular/material/button-toggle'; |
|||
import { MatRippleModule } from '@angular/material/core'; |
|||
import { MatDialogModule } from '@angular/material/dialog'; |
|||
import { MatDividerModule } from '@angular/material/divider'; |
|||
import { MatFormFieldModule } from '@angular/material/form-field'; |
|||
import { MatIconModule } from '@angular/material/icon'; |
|||
import { MatInputModule } from '@angular/material/input'; |
|||
import { MatMenuModule } from '@angular/material/menu'; |
|||
import { MatPaginatorModule } from '@angular/material/paginator'; |
|||
import { MatProgressBarModule } from '@angular/material/progress-bar'; |
|||
import { MatSelectModule } from '@angular/material/select'; |
|||
import { MatSidenavModule } from '@angular/material/sidenav'; |
|||
import { MatSortModule } from '@angular/material/sort'; |
|||
import { MatTableModule } from '@angular/material/table'; |
|||
import { MatTabsModule } from '@angular/material/tabs'; |
|||
import { MatTooltipModule } from '@angular/material/tooltip'; |
|||
import { TranslocoModule } from '@ngneat/transloco'; |
|||
import { SharedModule } from 'app/shared/shared.module'; |
|||
import { profileRoutes } from './profile.routing'; |
|||
import { InformationComponent } from './Information/information.component'; |
|||
import { SettingsComponent } from './Settings/settings.component'; |
|||
import { DescriptionDialogComponent } from './DescriptionDialog/description-dialog.component'; |
|||
import { InformationDialogComponent } from './InfoDialog/information-dialog.component'; |
|||
|
|||
|
|||
|
|||
@NgModule({ |
|||
declarations: [], |
|||
declarations: [ |
|||
ProfileComponent, |
|||
InformationComponent, |
|||
SettingsComponent, |
|||
DescriptionDialogComponent, |
|||
InformationDialogComponent |
|||
], |
|||
imports: [ |
|||
CommonModule |
|||
RouterModule.forChild(profileRoutes), |
|||
QuillModule.forRoot(), |
|||
CommonModule, |
|||
MatButtonModule, |
|||
MatButtonToggleModule, |
|||
MatDividerModule, |
|||
MatIconModule, |
|||
MatFormFieldModule, |
|||
MatInputModule, |
|||
MatMenuModule, |
|||
MatProgressBarModule, |
|||
MatRippleModule, |
|||
MatSidenavModule, |
|||
MatSortModule, |
|||
MatTableModule, |
|||
MatTabsModule, |
|||
MatDialogModule, |
|||
TranslocoModule, |
|||
SharedModule, |
|||
MatPaginatorModule, |
|||
MatSelectModule, |
|||
MatTooltipModule, |
|||
] |
|||
}) |
|||
export class ProfileModule { } |
|||
|
@ -0,0 +1,35 @@ |
|||
import { Route } from '@angular/router'; |
|||
import { EditProductComponent } from '../Products/EditProduct/edit-product.component'; |
|||
import { NewProductComponent } from '../Products/NewProduct/new-product.component'; |
|||
import { ProfileComponent } from './profile.component'; |
|||
|
|||
export const profileRoutes: Route[] = [ |
|||
{ |
|||
path : '', |
|||
component: ProfileComponent, |
|||
// resolve : {
|
|||
// data: DesiresResolver
|
|||
// },
|
|||
// children : [
|
|||
// {
|
|||
// path : '',
|
|||
// pathMatch: 'full',
|
|||
// component: ListDesiresComponent,
|
|||
// },
|
|||
// {
|
|||
// path : 'create-product',
|
|||
// component: NewProductComponent,
|
|||
// // resolve : {
|
|||
// // course: AcademyCourseResolver
|
|||
// // }
|
|||
// },
|
|||
// // {
|
|||
// // path : ':id',
|
|||
// // component: EditProductComponent,
|
|||
// // // resolve : {
|
|||
// // // course: AcademyCourseResolver
|
|||
// // // }
|
|||
// // }
|
|||
// ]
|
|||
} |
|||
]; |
@ -0,0 +1,64 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
import { tap } from 'rxjs/operators'; |
|||
import { analytics as analyticsData } from 'app/mock-api/dashboards/analytics/data'; |
|||
import { environment } from 'environments/environment'; |
|||
import { BusinessCategory, TesoBusinessDetail } from 'app/models/businessModel'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class ProfileService { |
|||
private _data: BehaviorSubject<any> = new BehaviorSubject(null); |
|||
private business: TesoBusinessDetail[] = []; |
|||
private _businessCategory: BehaviorSubject<BusinessCategory[]> = new BehaviorSubject(null); |
|||
|
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor(private _httpClient: HttpClient) { |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Accessors
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Getter for data |
|||
*/ |
|||
get data$(): Observable<any> { |
|||
return this._data.asObservable(); |
|||
} |
|||
get categories$(): Observable<BusinessCategory[]> { |
|||
return this._businessCategory.asObservable(); |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Get data |
|||
*/ |
|||
getData(business: string = ".null."): Observable<any> { |
|||
return this._httpClient.get(environment.apiURL + `business/search/filter?businessName=${business}`).pipe( |
|||
tap((response: any) => { |
|||
this._data.next(response); |
|||
this.business = response; |
|||
}) |
|||
); |
|||
} |
|||
|
|||
getBusiness(id: string): TesoBusinessDetail { |
|||
const found = this.business.find(item => item.businessId === id); |
|||
return found; |
|||
} |
|||
|
|||
getCategories(): Observable<BusinessCategory[]> { |
|||
return this._httpClient.get(environment.apiURL + `api/businesscategories1`).pipe( |
|||
tap((response: BusinessCategory[]) => { |
|||
this._businessCategory.next(response); |
|||
})); |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
<p>settings works!</p> |
@ -1,15 +0,0 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'app-settings', |
|||
templateUrl: './settings.component.html', |
|||
styleUrls: ['./settings.component.scss'] |
|||
}) |
|||
export class SettingsComponent implements OnInit { |
|||
|
|||
constructor() { } |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
} |
@ -1,12 +0,0 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
|
|||
|
|||
|
|||
@NgModule({ |
|||
declarations: [], |
|||
imports: [ |
|||
CommonModule |
|||
] |
|||
}) |
|||
export class SettingsModule { } |
@ -1,105 +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">Unlock your session</div> |
|||
<div class="mt-0.5 font-medium">Your session is locked due to inactivity</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> |
|||
|
|||
<!-- Unlock form --> |
|||
<form class="mt-8" [formGroup]="unlockSessionForm" #unlockSessionNgForm="ngForm"> |
|||
|
|||
<!-- Name field --> |
|||
<mat-form-field class="w-full"> |
|||
<mat-label>Full name</mat-label> |
|||
<input id="name" matInput [formControlName]="'name'"> |
|||
</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> |
|||
|
|||
<!-- Submit button --> |
|||
<button class="teso-mat-button-large w-full mt-3" mat-flat-button [color]="'primary'" [disabled]="unlockSessionForm.disabled" (click)="unlock()"> |
|||
<span *ngIf="!unlockSessionForm.disabled"> |
|||
Unlock your session |
|||
</span> |
|||
<mat-progress-spinner |
|||
*ngIf="unlockSessionForm.disabled" |
|||
[diameter]="24" |
|||
[mode]="'indeterminate'"></mat-progress-spinner> |
|||
</button> |
|||
|
|||
<!-- Form footer --> |
|||
<div class="mt-8 text-md font-medium text-secondary"> |
|||
<span>I'm not</span> |
|||
<a class="ml-1 text-primary-500 hover:underline" [routerLink]="['/sign-out']">{{name}}</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,129 +0,0 @@ |
|||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; |
|||
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms'; |
|||
import { ActivatedRoute, Router } from '@angular/router'; |
|||
import { tesoAnimations } from '@teso/animations'; |
|||
import { AuthService } from 'app/core/auth/auth.service'; |
|||
import { UserService } from 'app/core/user/user.service'; |
|||
import { tesoAlertType } from '@teso/components/alert'; |
|||
|
|||
@Component({ |
|||
selector : 'auth-unlock-session', |
|||
templateUrl : './unlock-session.component.html', |
|||
encapsulation: ViewEncapsulation.None, |
|||
animations : tesoAnimations |
|||
}) |
|||
export class AuthUnlockSessionComponent implements OnInit |
|||
{ |
|||
@ViewChild('unlockSessionNgForm') unlockSessionNgForm: NgForm; |
|||
|
|||
alert: { type: tesoAlertType; message: string } = { |
|||
type : 'success', |
|||
message: '' |
|||
}; |
|||
name: string; |
|||
showAlert: boolean = false; |
|||
unlockSessionForm: FormGroup; |
|||
private _email: string; |
|||
|
|||
/** |
|||
* Constructor |
|||
*/ |
|||
constructor( |
|||
private _activatedRoute: ActivatedRoute, |
|||
private _authService: AuthService, |
|||
private _formBuilder: FormBuilder, |
|||
private _router: Router, |
|||
private _userService: UserService |
|||
) |
|||
{ |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Lifecycle hooks
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* On init |
|||
*/ |
|||
ngOnInit(): void |
|||
{ |
|||
// Get the user's name
|
|||
this._userService.user$.subscribe((user) => { |
|||
this.name = user.name; |
|||
this._email = user.email; |
|||
}); |
|||
|
|||
// Create the form
|
|||
this.unlockSessionForm = this._formBuilder.group({ |
|||
name : [ |
|||
{ |
|||
value : this.name, |
|||
disabled: true |
|||
} |
|||
], |
|||
password: ['', Validators.required] |
|||
}); |
|||
} |
|||
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
// @ Public methods
|
|||
// -----------------------------------------------------------------------------------------------------
|
|||
|
|||
/** |
|||
* Unlock |
|||
*/ |
|||
unlock(): void |
|||
{ |
|||
// Return if the form is invalid
|
|||
if ( this.unlockSessionForm.invalid ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Disable the form
|
|||
this.unlockSessionForm.disable(); |
|||
|
|||
// Hide the alert
|
|||
this.showAlert = false; |
|||
|
|||
this._authService.unlockSession({ |
|||
email : this._email ?? '', |
|||
password: this.unlockSessionForm.get('password').value |
|||
}).subscribe( |
|||
() => { |
|||
|
|||
// Set the redirect url.
|
|||
// The '/signed-in-redirect' is a dummy url to catch the request and redirect the user
|
|||
// to the correct page after a successful sign in. This way, that url can be set via
|
|||
// routing file and we don't have to touch here.
|
|||
const redirectURL = this._activatedRoute.snapshot.queryParamMap.get('redirectURL') || '/signed-in-redirect'; |
|||
|
|||
// Navigate to the redirect url
|
|||
this._router.navigateByUrl(redirectURL); |
|||
|
|||
}, |
|||
(response) => { |
|||
|
|||
// Re-enable the form
|
|||
this.unlockSessionForm.enable(); |
|||
|
|||
// Reset the form
|
|||
this.unlockSessionNgForm.resetForm({ |
|||
name: { |
|||
value : this.name, |
|||
disabled: true |
|||
} |
|||
}); |
|||
|
|||
// Set the alert
|
|||
this.alert = { |
|||
type : 'error', |
|||
message: 'Invalid password' |
|||
}; |
|||
|
|||
// Show the alert
|
|||
this.showAlert = true; |
|||
} |
|||
); |
|||
} |
|||
} |
@ -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 { AuthUnlockSessionComponent } from 'app/pages/auth/unlock-session/unlock-session.component'; |
|||
import { authUnlockSessionRoutes } from 'app/pages/auth/unlock-session/unlock-session.routing'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
AuthUnlockSessionComponent |
|||
], |
|||
imports : [ |
|||
RouterModule.forChild(authUnlockSessionRoutes), |
|||
MatButtonModule, |
|||
MatFormFieldModule, |
|||
MatIconModule, |
|||
MatInputModule, |
|||
MatProgressSpinnerModule, |
|||
tesoCardModule, |
|||
tesoAlertModule, |
|||
SharedModule |
|||
] |
|||
}) |
|||
export class AuthUnlockSessionModule |
|||
{ |
|||
} |
@ -1,9 +0,0 @@ |
|||
import { Route } from '@angular/router'; |
|||
import { AuthUnlockSessionComponent } from 'app/pages/auth/unlock-session/unlock-session.component'; |
|||
|
|||
export const authUnlockSessionRoutes: Route[] = [ |
|||
{ |
|||
path : '', |
|||
component: AuthUnlockSessionComponent |
|||
} |
|||
]; |
@ -0,0 +1,13 @@ |
|||
import { Pipe, PipeTransform } from '@angular/core'; |
|||
|
|||
@Pipe({ |
|||
name: 'couponWorth' |
|||
}) |
|||
export class CouponWorthPipe implements PipeTransform { |
|||
|
|||
transform(value: number,rate:number): string { |
|||
var worth = (rate * value)/100; |
|||
return `GH¢ ${worth}`; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
import { Pipe, PipeTransform } from "@angular/core"; |
|||
|
|||
@Pipe({ |
|||
name: 'productDescShort' |
|||
}) |
|||
export class ProductDescriptionShort implements PipeTransform { |
|||
|
|||
constructor( |
|||
) { } |
|||
|
|||
transform(value: string): string { |
|||
if(value.length > 57){ |
|||
return value.substring(0, 58) + "...."; |
|||
}else{ |
|||
return value; |
|||
} |
|||
} |
|||
} |
After Width: | Height: | Size: 568 B |
Loading…
Reference in new issue