[init] init version
This commit is contained in:
23
src/app/@common/base/base-form.component.ts
Normal file
23
src/app/@common/base/base-form.component.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { CDialogConfig, IDialogConfig } from "../interface/Dialog";
|
||||
|
||||
|
||||
@Component({ template: "", standalone: true })
|
||||
export class BaseFormComponent {
|
||||
|
||||
dataForm: any = {};
|
||||
dataFilter: any = {};
|
||||
ids: any;
|
||||
action: any;
|
||||
params: any = {};
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
|
||||
|
||||
public isFieldValid(form: any, field: any) {
|
||||
return field.errors && (field.dirty || field.touched || form.submitted);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
123
src/app/@common/base/base-list.component.ts
Normal file
123
src/app/@common/base/base-list.component.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {MatPaginator} from '@angular/material/paginator';
|
||||
import {MatSort} from '@angular/material/sort';
|
||||
|
||||
import generateParamsValue from '../utils/GenerateParamsValue';
|
||||
|
||||
import {MatTableDataSource} from '@angular/material/table';
|
||||
import {IListPageDefault, IListResponse} from "../interface/ListResponse";
|
||||
import {CDialogConfig, IDialogConfig} from "../interface/Dialog";
|
||||
import { STORAGE } from "../../@config/app";
|
||||
|
||||
@Component({template: ''})
|
||||
export abstract class BaseListComponent {
|
||||
|
||||
dataFilter: any = {};
|
||||
dataSource: any = [];
|
||||
dataSourceList = new MatTableDataSource<any>([]);
|
||||
dataSourceCount = 0;
|
||||
pageSizeOptions = [10, 20, 50];
|
||||
pageIndex: number = 1;
|
||||
pageSize: number = 10;
|
||||
totalItem: any = 0;
|
||||
totalOfElement: number = 10;
|
||||
isTab: string = '';
|
||||
storage: any = STORAGE;
|
||||
|
||||
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
default: IListPageDefault = {
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
|
||||
@ViewChild(MatSort, {static: true}) sort: MatSort | any;
|
||||
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator | any;
|
||||
|
||||
protected setParams(url: string, $event? : any) {
|
||||
this.pageIndex = $event ? $event.pageIndex + 1 : this.default.pageIndex;
|
||||
this.pageSize = $event ? $event.pageSize : this.default.pageSize;
|
||||
const filter = generateParamsValue(this.dataFilter);
|
||||
return `${url}?page=${this.pageIndex}&perPage=${this.pageSize}${filter ? '&' + filter : '' }`;
|
||||
}
|
||||
|
||||
|
||||
protected setDataSource<T>(data: IListResponse<T>) {
|
||||
this.totalItem = data ? data.totalItem : 0;
|
||||
this.totalOfElement = data ? data.totalOfElement : 0;
|
||||
this.paginator.length = data ? data.totalItem : 0;
|
||||
this.dataSourceCount = data ? data.totalItem : 0;
|
||||
return data ? data.data : [];
|
||||
}
|
||||
|
||||
protected getCurrentPage() {
|
||||
return {pageIndex: this.pageIndex - 1, pageSize: this.pageSize};
|
||||
}
|
||||
|
||||
protected setDataSourceList<T>(data : any) {
|
||||
this.dataSourceList = new MatTableDataSource<T>(data);
|
||||
this.dataSourceList.paginator = this.paginator;
|
||||
this.dataSourceCount = data ? data.length : 0;
|
||||
}
|
||||
|
||||
protected setFilterPredicate<T>() {
|
||||
this.dataSourceList.filterPredicate = (data: T, filtersJson: string) => {
|
||||
const matchFilter : any = [];
|
||||
const filters = JSON.parse(filtersJson);
|
||||
filters.forEach((filter : any) => {
|
||||
// @ts-ignore
|
||||
const val = data[filter.id] ? data[filter.id] : '';
|
||||
filter.value = filter.value ? filter.value : '';
|
||||
matchFilter.push(val.toLowerCase().includes(filter.value.toLowerCase()));
|
||||
});
|
||||
return matchFilter.every(Boolean);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected onFilterPredicate() {
|
||||
const tableFilters : any = [];
|
||||
Object.keys(this.dataFilter).forEach(key => {
|
||||
if (key) tableFilters.push({id: key, value: this.dataFilter[key]});
|
||||
});
|
||||
this.dataSourceList.filter = JSON.stringify(tableFilters);
|
||||
|
||||
if (this.dataSourceList.paginator) {
|
||||
this.dataSourceList.paginator.firstPage();
|
||||
}
|
||||
}
|
||||
|
||||
protected setFilterLocal(page : any) {
|
||||
const data = {
|
||||
page,
|
||||
filter: this.dataFilter
|
||||
};
|
||||
const filterLocalData = [];
|
||||
const filterLocal: any = localStorage.getItem('filterLocal');
|
||||
|
||||
if (filterLocal) {
|
||||
const parse = JSON.parse(filterLocal);
|
||||
const mapData = parse.map((item : any) => {
|
||||
if (item.page === page) return data;
|
||||
return item;
|
||||
});
|
||||
return localStorage.setItem('filterLocal', JSON.stringify(mapData));
|
||||
}
|
||||
|
||||
filterLocalData.push(data);
|
||||
localStorage.setItem('filterLocal', JSON.stringify(filterLocalData));
|
||||
}
|
||||
|
||||
protected getFilterLocal(page : any) {
|
||||
const filterLocal: any = localStorage.getItem('filterLocal');
|
||||
if (!filterLocal) return;
|
||||
const parse = JSON.parse(filterLocal);
|
||||
const isPage = parse.filter((f : any) => f.page === page);
|
||||
if (!isPage[0]) return;
|
||||
this.dataFilter = isPage[0].filter;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
15
src/app/@common/base/base-popup.component.ts
Normal file
15
src/app/@common/base/base-popup.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {CDialogConfig, IDialogConfig} from "../interface/Dialog";
|
||||
|
||||
@Component({template: ''})
|
||||
export abstract class BasePopupComponent {
|
||||
|
||||
ids: any;
|
||||
dataForm: any = {};
|
||||
dialogConfig: IDialogConfig = CDialogConfig;
|
||||
|
||||
public isFieldValid(form : any, field : any) {
|
||||
return field.errors && (field.dirty || field.touched || form.submitted);
|
||||
}
|
||||
}
|
||||
21
src/app/@common/interface/Dialog.ts
Normal file
21
src/app/@common/interface/Dialog.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {EAction} from "../../@config/app";
|
||||
|
||||
export const CDialogConfig: IDialogConfig = {
|
||||
width: '80%',
|
||||
height: '80%',
|
||||
data: {}
|
||||
};
|
||||
|
||||
|
||||
export interface IDialogConfig {
|
||||
width: string;
|
||||
height: string;
|
||||
data: IDialogConfigData;
|
||||
}
|
||||
|
||||
export interface IDialogConfigData {
|
||||
action?: EAction;
|
||||
ids?: string;
|
||||
datas?: any;
|
||||
dataForm?: any;
|
||||
}
|
||||
12
src/app/@common/interface/ListResponse.ts
Normal file
12
src/app/@common/interface/ListResponse.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface IListResponse<T> {
|
||||
data: T[];
|
||||
totalItem: number;
|
||||
totalOfElement: number;
|
||||
page: number;
|
||||
rowsPerPage: number;
|
||||
lastPage: number;
|
||||
}
|
||||
export interface IListPageDefault {
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
}
|
||||
201
src/app/@common/interface/Quotation.ts
Normal file
201
src/app/@common/interface/Quotation.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
export interface IQuotation {
|
||||
id?: number
|
||||
step?: number
|
||||
quotationNo?: string
|
||||
productId?: any
|
||||
typeCode?: any
|
||||
productNo?: string
|
||||
productName?: string
|
||||
productBrandName?: string
|
||||
productSize?: string
|
||||
productColor?: string
|
||||
productWeight?: any
|
||||
productYear?: string
|
||||
productPrice?: string
|
||||
productLatestPrice?: string
|
||||
productImages?: any
|
||||
images?: any
|
||||
openingVideo?: any
|
||||
coverImage?: string
|
||||
startDate?: string
|
||||
deposit?: string
|
||||
cmfsDeposit?: string
|
||||
price?: string
|
||||
lessSellerDeposit?: string
|
||||
sellerDeposit?: string
|
||||
sellerDeposit2ndTime?: any
|
||||
sellerDeposit3rdTime?: any
|
||||
sellerDepositSum?: any
|
||||
plusPacking?: string
|
||||
plusLuxuryHandbag?: string
|
||||
principalBalanceTotal?: string
|
||||
wantToInstallmentTerm?: number
|
||||
installment?: any
|
||||
plusBankFee?: string
|
||||
transferSummary?: string
|
||||
customerId?: number
|
||||
sellerId?: any
|
||||
customerPrefix?: any
|
||||
customerFirstName?: string
|
||||
customerLastName?: string
|
||||
customerPhone?: string
|
||||
customerIdCard?: any
|
||||
customerIdCardImage?: any
|
||||
customerAddress?: any
|
||||
customerEmail?: any
|
||||
customerLine?: any
|
||||
customerLineShop?: any
|
||||
customerFacebook?: any
|
||||
customerOccupation?: any
|
||||
customerIg?: any
|
||||
userFullName?: string
|
||||
sellerName?: string
|
||||
sellerPhone?: string
|
||||
sellerEmail?: any
|
||||
sellerLine?: any
|
||||
sellerLineShop?: any
|
||||
sellerFacebook?: any
|
||||
sellerIg?: any
|
||||
sellerSnProduct?: any
|
||||
status?: string
|
||||
status2ndTime?: string
|
||||
status3rdTime?: string
|
||||
statusContract?: string
|
||||
contractDate?: any
|
||||
contractApprovedDate?: any
|
||||
contractCancelDate?: any
|
||||
contractBankName?: any
|
||||
contractAccountName?: any
|
||||
contractAccountNumber?: any
|
||||
contractDetail?: any
|
||||
isContractClosing?: any
|
||||
contractPrice?: any
|
||||
contractInterest?: any
|
||||
contractPriceSum?: any
|
||||
receivedDate?: any
|
||||
statusWarehouse?: any
|
||||
areaId?: any
|
||||
areaCode?: any
|
||||
areaName?: any
|
||||
areaRoomName?: any
|
||||
areaLocation?: any
|
||||
areaFloor?: any
|
||||
areaRoomSize?: any
|
||||
storageBoxId?: any
|
||||
storageBoxCode?: any
|
||||
storageBoxName?: any
|
||||
storageBoxSize?: any
|
||||
disbursementDate?: any
|
||||
disbursementType?: any
|
||||
deliveryWorker?: any
|
||||
isCheckInspection?: any
|
||||
isReceived?: any
|
||||
type?: string
|
||||
pickType?: any
|
||||
settingInterestRate?: any
|
||||
settingCmfsDeposit?: any
|
||||
priceDisbursement?: any
|
||||
sellerPaymentAccountName?: string
|
||||
sellerPaymentPayee?: string
|
||||
sellerPaymentMethod?: string
|
||||
sellerPaymentDate?: string
|
||||
sellerPaymentAmount?: string
|
||||
sellerPaymentAccountNumber?: string
|
||||
isInvoice?: string
|
||||
isPaying?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: number
|
||||
productMeasurement?: IQuotationProductMeasurement[]
|
||||
quotationDetail?: IQuotationDetail[]
|
||||
customer?: IQuotationCustomer
|
||||
seller?: any
|
||||
discount?: any
|
||||
}
|
||||
|
||||
export interface IQuotationCustomer {
|
||||
id?: number
|
||||
code?: any
|
||||
prefix?: string
|
||||
gender?: string
|
||||
firstName?: string
|
||||
lastName?: string
|
||||
phone?: string
|
||||
idCard?: string
|
||||
idCardImage?: string
|
||||
address?: string
|
||||
isAddress?: boolean
|
||||
deliveryAddress?: string
|
||||
email?: string
|
||||
line?: string
|
||||
lineShop?: any
|
||||
facebook?: string
|
||||
occupation?: string
|
||||
ig?: string
|
||||
status?: any
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationProductMeasurement {
|
||||
id?: number
|
||||
productId?: any
|
||||
masterProductMeasurementId?: any
|
||||
quotationId?: number
|
||||
code?: any
|
||||
name?: string
|
||||
size?: string
|
||||
unitId?: number
|
||||
status?: any
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationDetail {
|
||||
id?: number
|
||||
quotationId?: number
|
||||
installment?: number
|
||||
dueDate?: string
|
||||
principle?: string
|
||||
interestTotal?: string
|
||||
fee?: string
|
||||
totalPayment?: string
|
||||
principleTotal?: string
|
||||
status?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
}
|
||||
|
||||
export interface IQuotationPayment {
|
||||
id?: number
|
||||
quotationId?: number
|
||||
quotationNo?: string
|
||||
productNo?: string
|
||||
productName?: string
|
||||
customerPrefix?: string
|
||||
customerFirstName?: string
|
||||
customerLastName?: string
|
||||
customerPhone?: string
|
||||
price?: string
|
||||
sellerDeposit?: string
|
||||
deposit?: string
|
||||
paymentDate?: string
|
||||
paymentType?: string
|
||||
paymentAmount?: string
|
||||
paymentAmountAll?: string
|
||||
paymentMethod?: string
|
||||
status?: string
|
||||
createdDate?: string
|
||||
createdBy?: any
|
||||
updatedDate?: string
|
||||
updatedBy?: any
|
||||
quotation?: IQuotation
|
||||
}
|
||||
|
||||
199
src/app/@common/utils/CurrencyInputMask.ts
Normal file
199
src/app/@common/utils/CurrencyInputMask.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { OnInit, Directive, HostListener, ElementRef, forwardRef } from "@angular/core";
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||
import { DecimalPipe } from "@angular/common";
|
||||
|
||||
export const CURRENCY_INPUT_MASK_DIRECTIVE_VALUE_ACCESSOR: any = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => CurrencyInputMaskDirective),
|
||||
multi: true
|
||||
};
|
||||
|
||||
@Directive({
|
||||
selector: "[appCurrencyInputMask]",
|
||||
providers: [
|
||||
CURRENCY_INPUT_MASK_DIRECTIVE_VALUE_ACCESSOR,
|
||||
DecimalPipe
|
||||
]
|
||||
})
|
||||
export class CurrencyInputMaskDirective implements ControlValueAccessor, OnInit {
|
||||
private el: HTMLInputElement | any;
|
||||
private onModelChange: Function | any;
|
||||
private onModelTouched: Function | any;
|
||||
private lastNumVal: number | any;
|
||||
private DECIMAL_MARK = ".";
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
private decimalPipe: DecimalPipe
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.el = this.elementRef.nativeElement;
|
||||
}
|
||||
|
||||
@HostListener("focus", ["$event"])
|
||||
handleFocus(event: any) {
|
||||
const strVal: string = this.getInputValue();
|
||||
const unmaskedStr: string = this.getUnmaskedValue(strVal);
|
||||
this.updateInputValue(unmaskedStr);
|
||||
}
|
||||
|
||||
@HostListener("cut", ["$event"])
|
||||
handleCut(event: any) {
|
||||
setTimeout(() => {
|
||||
this.inputUpdated();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@HostListener("keypress", ["$event"])
|
||||
handleKeypress(event: any) {
|
||||
// Restrict characters
|
||||
const newChar: string = String.fromCharCode(event.which);
|
||||
const allowedChars: RegExp = /^[\d.]+$/;
|
||||
if (!allowedChars.test(newChar)) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
// Handle decimal mark input
|
||||
const currentValue: string = event.target.value;
|
||||
const separatorIdx: number = currentValue.indexOf(this.DECIMAL_MARK);
|
||||
const hasFractionalPart: boolean = (separatorIdx >= 0);
|
||||
if (!hasFractionalPart || newChar !== this.DECIMAL_MARK) {
|
||||
return;
|
||||
}
|
||||
const isOutsideSelection = !this.isIdxBetweenSelection(separatorIdx);
|
||||
if (isOutsideSelection) {
|
||||
const positionAfterMark = separatorIdx + 1;
|
||||
this.setCursorPosition(positionAfterMark);
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener("input", ["$event"])
|
||||
handleInput(event: any) {
|
||||
this.inputUpdated();
|
||||
}
|
||||
|
||||
@HostListener("paste", ["$event"])
|
||||
handlePaste(event: any) {
|
||||
setTimeout(() => {
|
||||
this.inputUpdated();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@HostListener("blur", ["$event"])
|
||||
handleBlur(event: any) {
|
||||
const strVal: string = this.getInputValue();
|
||||
const numVal: any = this.convertStrToDecimal(strVal);
|
||||
this.maskInput(numVal);
|
||||
|
||||
this.onModelTouched.apply(event);
|
||||
}
|
||||
|
||||
registerOnChange(callbackFunction: Function): void {
|
||||
this.onModelChange = callbackFunction;
|
||||
}
|
||||
|
||||
registerOnTouched(callbackFunction: Function): void {
|
||||
this.onModelTouched = callbackFunction;
|
||||
}
|
||||
|
||||
setDisabledState(value: boolean): void {
|
||||
|
||||
this.el.disabled = value;
|
||||
}
|
||||
|
||||
writeValue(numValue: number): void {
|
||||
this.maskInput(numValue);
|
||||
}
|
||||
|
||||
private maskInput(numVal: number): void {
|
||||
if (!this.isNumeric(numVal)) {
|
||||
this.updateInputValue("");
|
||||
return;
|
||||
}
|
||||
const strVal: string = this.convertDecimalToStr(numVal);
|
||||
const newVal: any = this.transformWithPipe(strVal);
|
||||
this.updateInputValue(newVal);
|
||||
}
|
||||
|
||||
private inputUpdated() {
|
||||
this.restrictDecimalValue();
|
||||
const strVal: string = this.getInputValue();
|
||||
const unmaskedVal: string = this.getUnmaskedValue(strVal);
|
||||
const numVal: any = this.convertStrToDecimal(unmaskedVal);
|
||||
if (numVal !== this.lastNumVal) {
|
||||
this.lastNumVal = numVal;
|
||||
|
||||
this.onModelChange(numVal);
|
||||
}
|
||||
}
|
||||
|
||||
private restrictDecimalValue(): void {
|
||||
const strVal: string = this.getInputValue();
|
||||
const dotIdx: number = strVal.indexOf(this.DECIMAL_MARK);
|
||||
const hasFractionalPart: boolean = (dotIdx >= 0);
|
||||
if (hasFractionalPart) {
|
||||
const fractionalPart: string = strVal.substring(dotIdx + 1);
|
||||
if (fractionalPart.length > 2) {
|
||||
const choppedVal: string = strVal.substring(0, dotIdx + 3);
|
||||
this.updateInputValue(choppedVal, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private transformWithPipe(str: any) {
|
||||
return this.decimalPipe.transform(str, "1.2-2");
|
||||
}
|
||||
|
||||
private getUnmaskedValue(value: string): string {
|
||||
return value.replace(/[^-\d\\.]/g, "");
|
||||
}
|
||||
|
||||
private updateInputValue(value: string, savePosition = false) {
|
||||
if (savePosition) {
|
||||
this.saveCursorPosition();
|
||||
}
|
||||
this.el.value = value;
|
||||
}
|
||||
|
||||
private getInputValue(): string {
|
||||
return this.el.value;
|
||||
}
|
||||
|
||||
private convertStrToDecimal(str: any) {
|
||||
return (this.isNumeric(str)) ? parseFloat(str) : null;
|
||||
}
|
||||
|
||||
private convertDecimalToStr(n: number): string {
|
||||
return (this.isNumeric(n)) ? n + "" : "";
|
||||
}
|
||||
|
||||
private isNumeric(n: any): boolean {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
private saveCursorPosition() {
|
||||
|
||||
const position: number = this.el.selectionStart;
|
||||
setTimeout(() => {
|
||||
this.setCursorPosition(position);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
private setCursorPosition(position: number) {
|
||||
this.el.selectionStart = position;
|
||||
this.el.selectionEnd = position;
|
||||
}
|
||||
|
||||
private isIdxBetweenSelection(idx: number) {
|
||||
if (this.el.selectionStart === this.el.selectionEnd) {
|
||||
return false;
|
||||
}
|
||||
return (idx >= this.el.selectionStart && idx < this.el.selectionEnd);
|
||||
}
|
||||
|
||||
}
|
||||
4
src/app/@common/utils/DeepCopy.ts
Normal file
4
src/app/@common/utils/DeepCopy.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default function deepCopy(data: any) {
|
||||
if (!data) return {};
|
||||
return JSON.parse(JSON.stringify(data));
|
||||
}
|
||||
16
src/app/@common/utils/Empty.ts
Normal file
16
src/app/@common/utils/Empty.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default function isEmpty(value: any) {
|
||||
switch (value) {
|
||||
case '':
|
||||
case 0:
|
||||
case '0':
|
||||
case null:
|
||||
case false:
|
||||
case 'null':
|
||||
case 'undefined':
|
||||
case undefined:
|
||||
case typeof value === 'undefined':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
134
src/app/@common/utils/FilterPipe.ts
Normal file
134
src/app/@common/utils/FilterPipe.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterBy',
|
||||
pure: false
|
||||
})
|
||||
export class FilterPipe implements PipeTransform {
|
||||
static isFoundOnWalking(value, key) {
|
||||
let walker = value;
|
||||
let found = false;
|
||||
do {
|
||||
if (
|
||||
walker.hasOwnProperty(key) ||
|
||||
Object.getOwnPropertyDescriptor(walker, key)
|
||||
) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
// tslint:disable-next-line:no-conditional-assignment
|
||||
} while ((walker = Object.getPrototypeOf(walker)));
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static isNumber(value) {
|
||||
return !isNaN(parseInt(value, 10)) && isFinite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks function's value if type is function otherwise same value
|
||||
*/
|
||||
static getValue(value: any): any {
|
||||
return typeof value === 'function' ? value() : value;
|
||||
}
|
||||
|
||||
private filterByString(filter) {
|
||||
if (filter) {
|
||||
filter = filter.toLowerCase();
|
||||
}
|
||||
return value =>
|
||||
!filter ||
|
||||
(value ? ('' + value).toLowerCase().indexOf(filter) !== -1 : false);
|
||||
}
|
||||
|
||||
private filterByBoolean(filter) {
|
||||
return value => Boolean(value) === filter;
|
||||
}
|
||||
|
||||
private filterByObject(filter) {
|
||||
return value => {
|
||||
for (const key in filter) {
|
||||
if (key === '$or') {
|
||||
if (!this.filterByOr(filter.$or)(FilterPipe.getValue(value))) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!value || !FilterPipe.isFoundOnWalking(value, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isMatching(filter[key], FilterPipe.getValue(value[key]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private isMatching(filter, val) {
|
||||
switch (typeof filter) {
|
||||
case 'boolean':
|
||||
return this.filterByBoolean(filter)(val);
|
||||
case 'string':
|
||||
return this.filterByString(filter)(val);
|
||||
case 'object':
|
||||
return this.filterByObject(filter)(val);
|
||||
}
|
||||
return this.filterDefault(filter)(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter value by $or
|
||||
*/
|
||||
private filterByOr(filter: any[]): (value: any) => boolean {
|
||||
return (value: any) => {
|
||||
const length = filter.length;
|
||||
|
||||
const arrayComparison = i => value.indexOf(filter[i]) !== -1;
|
||||
const otherComparison = i => this.isMatching(filter[i], value);
|
||||
const comparison = Array.isArray(value)
|
||||
? arrayComparison
|
||||
: otherComparison;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (comparison(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Default filterDefault function
|
||||
*/
|
||||
private filterDefault(filter: any): (value: any) => boolean {
|
||||
return (value: any) => filter === undefined || filter === value;
|
||||
}
|
||||
|
||||
transform(array: any[], filter: any): any {
|
||||
if (!array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
switch (typeof filter) {
|
||||
case 'boolean':
|
||||
return array.filter(this.filterByBoolean(filter));
|
||||
case 'string':
|
||||
if (FilterPipe.isNumber(filter)) {
|
||||
return array.filter(this.filterDefault(filter));
|
||||
}
|
||||
return array.filter(this.filterByString(filter));
|
||||
case 'object':
|
||||
return array.filter(this.filterByObject(filter));
|
||||
case 'function':
|
||||
return array.filter(filter);
|
||||
}
|
||||
return array.filter(this.filterDefault(filter));
|
||||
}
|
||||
}
|
||||
10
src/app/@common/utils/GenerateParamsValue.ts
Normal file
10
src/app/@common/utils/GenerateParamsValue.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function generateParamsValue(jsonValue: any) {
|
||||
let params = '';
|
||||
Object.keys(jsonValue).forEach((key) => {
|
||||
if (jsonValue[key]) {
|
||||
params += key + '=' + jsonValue[key] + '&';
|
||||
}
|
||||
});
|
||||
params = params.substring(0, params.length - 1);
|
||||
return params;
|
||||
}
|
||||
41
src/app/@common/utils/NumberOnlyDirective.ts
Normal file
41
src/app/@common/utils/NumberOnlyDirective.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import {Directive, ElementRef, EventEmitter, HostListener, Output} from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appNumberOnly]'
|
||||
})
|
||||
export class NumberOnlyDirective {
|
||||
// Emit the parsed number value
|
||||
@Output() numberValue: EventEmitter<number> = new EventEmitter<number>();
|
||||
// Allow key codes for special events. Reflect :
|
||||
// Allow decimal numbers with 2 decimal places and negative values
|
||||
private regex: RegExp = new RegExp(/^\d*\.?\d{0,2}$/g);
|
||||
// Backspace, tab, end, home
|
||||
private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-', 'ArrowLeft', 'ArrowRight', 'Del', 'Delete'];
|
||||
|
||||
constructor(private el: ElementRef) {
|
||||
}
|
||||
|
||||
@HostListener('keydown', ['$event'])
|
||||
onKeyDown(event: KeyboardEvent) {
|
||||
if (this.specialKeys.indexOf(event.key) !== -1) {
|
||||
return;
|
||||
}
|
||||
const current: string = this.el.nativeElement.value;
|
||||
const position = this.el.nativeElement.selectionStart;
|
||||
const next: string = [current.slice(0, position), event.key === 'Decimal' ? '.' : event.key, current.slice(position)].join('');
|
||||
if (next && !String(next).match(this.regex)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('input', ['$event'])
|
||||
onInput(event: KeyboardEvent) {
|
||||
// Get the parsed number value
|
||||
const parsedValue = Number(this.el.nativeElement.value);
|
||||
|
||||
// Emit the parsed value only if it's a number
|
||||
if (!isNaN(parsedValue)) {
|
||||
this.numberValue.emit(parsedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/app/@common/utils/OrderBy.ts
Normal file
22
src/app/@common/utils/OrderBy.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export function orderByArray(data: any, key: string) {
|
||||
if (!data) return;
|
||||
if (data.length === 0) return;
|
||||
return data.sort((a: any, b: any) => a[key].localeCompare(b[key], 'en', {numeric: true}));
|
||||
}
|
||||
|
||||
export function sortByProperty<T>(array: T[], propName: keyof T, order: 'ASC' | 'DESC') {
|
||||
array.sort((a, b) => {
|
||||
if (a[propName] < b[propName]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a[propName] > b[propName]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (order === 'DESC') {
|
||||
array.reverse();
|
||||
}
|
||||
}
|
||||
22
src/app/@common/utils/generateUUID.ts
Normal file
22
src/app/@common/utils/generateUUID.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export function generateUUID() {
|
||||
// Public Domain/MIT
|
||||
let d = new Date().getTime(); // Timestamp
|
||||
let d2 =
|
||||
(typeof performance !== 'undefined' &&
|
||||
performance.now &&
|
||||
performance.now() * 1000) ||
|
||||
0; // Time in microseconds since page-load or 0 if unsupported
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16; // random number between 0 and 16
|
||||
if (d > 0) {
|
||||
// Use timestamp until depleted
|
||||
r = (d + r) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
} else {
|
||||
// Use microseconds since page-load if supported
|
||||
r = (d2 + r) % 16 | 0;
|
||||
d2 = Math.floor(d2 / 16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user