diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts index 4e786c73..3364a294 100644 --- a/src/app/app.routing.ts +++ b/src/app/app.routing.ts @@ -79,6 +79,8 @@ export const appRoutes: Route[] = [ {path: 'dashboards', children: [ {path: 'project', loadChildren: () => import('app/modules/admin/dashboards/project/project.module').then(m => m.ProjectModule)}, {path: 'analytics', loadChildren: () => import('app/modules/admin/dashboards/analytics/analytics.module').then(m => m.AnalyticsModule)}, + {path: 'finance', loadChildren: () => import('app/modules/admin/dashboards/finance/finance.module').then(m => m.FinanceModule)}, + {path: 'crypto', loadChildren: () => import('app/modules/admin/dashboards/crypto/crypto.module').then(m => m.CryptoModule)}, ]}, // Apps diff --git a/src/app/mock-api/common/navigation/data.ts b/src/app/mock-api/common/navigation/data.ts index 478dab97..be3cb9b8 100644 --- a/src/app/mock-api/common/navigation/data.ts +++ b/src/app/mock-api/common/navigation/data.ts @@ -22,6 +22,20 @@ export const defaultNavigation: FuseNavigationItem[] = [ type : 'basic', icon : 'heroicons_outline:chart-pie', link : '/dashboards/analytics' + }, + { + id : 'dashboards.finance', + title: 'Finance', + type : 'basic', + icon : 'heroicons_outline:cash', + link : '/dashboards/finance' + }, + { + id : 'dashboards.crypto', + title: 'Crypto', + type : 'basic', + icon : 'heroicons_outline:currency-dollar', + link : '/dashboards/crypto' } ] }, diff --git a/src/app/mock-api/dashboards/crypto/api.ts b/src/app/mock-api/dashboards/crypto/api.ts new file mode 100644 index 00000000..e59c7b04 --- /dev/null +++ b/src/app/mock-api/dashboards/crypto/api.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { cloneDeep } from 'lodash-es'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { crypto as cryptoData } from 'app/mock-api/dashboards/crypto/data'; + +@Injectable({ + providedIn: 'root' +}) +export class CryptoMockApi +{ + private _crypto: any = cryptoData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) + { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void + { + // ----------------------------------------------------------------------------------------------------- + // @ Crypto - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/dashboards/crypto') + .reply(() => [200, cloneDeep(this._crypto)]); + } +} diff --git a/src/app/mock-api/dashboards/crypto/data.ts b/src/app/mock-api/dashboards/crypto/data.ts new file mode 100644 index 00000000..3a564943 --- /dev/null +++ b/src/app/mock-api/dashboards/crypto/data.ts @@ -0,0 +1,1196 @@ +import * as moment from 'moment'; + +/* tslint:disable:max-line-length */ +export const crypto = { + btc : { + amount : 8878.48, + trend : { + dir : 'up', + amount: 0.17 + }, + marketCap : 148752956966, + volume : 22903438381, + supply : 18168448, + allTimeHigh: 19891.00, + price : { + series: [ + { + name: 'Price', + data: [ + { + x: -145, + y: 6554.36 + }, + { + x: -144, + y: 6554.36 + }, + { + x: -143, + y: 6546.94 + }, + { + x: -142, + y: 6546.96 + }, + { + x: -141, + y: 6546.11 + }, + { + x: -140, + y: 6550.26 + }, + { + x: -139, + y: 6546.11 + }, + { + x: -138, + y: 6550.79 + }, + { + x: -137, + y: 6545.36 + }, + { + x: -136, + y: 6541.06 + }, + { + x: -135, + y: 6540.10 + }, + { + x: -134, + y: 6538.31 + }, + { + x: -133, + y: 6538.42 + }, + { + x: -132, + y: 6538.48 + }, + { + x: -131, + y: 6538.71 + }, + { + x: -130, + y: 6548.42 + }, + { + x: -129, + y: 6546.87 + }, + { + x: -128, + y: 6547.07 + }, + { + x: -127, + y: 6535.07 + }, + { + x: -126, + y: 6535.01 + }, + { + x: -125, + y: 6539.02 + }, + { + x: -124, + y: 6547.96 + }, + { + x: -123, + y: 6547.92 + }, + { + x: -122, + y: 6546.56 + }, + { + x: -121, + y: 6546.56 + }, + { + x: -120, + y: 6564.16 + }, + { + x: -119, + y: 6560.83 + }, + { + x: -118, + y: 6559.08 + }, + { + x: -117, + y: 6553.02 + }, + { + x: -116, + y: 6564.99 + }, + { + x: -115, + y: 6558.70 + }, + { + x: -114, + y: 6568.73 + }, + { + x: -113, + y: 6568.80 + }, + { + x: -112, + y: 6568.80 + }, + { + x: -111, + y: 6568.80 + }, + { + x: -110, + y: 6571.83 + }, + { + x: -109, + y: 6562.64 + }, + { + x: -108, + y: 6561.28 + }, + { + x: -107, + y: 6561.28 + }, + { + x: -106, + y: 6560.40 + }, + { + x: -105, + y: 6564.41 + }, + { + x: -104, + y: 6562.44 + }, + { + x: -103, + y: 6565.13 + }, + { + x: -102, + y: 6553.30 + }, + { + x: -101, + y: 6552.68 + }, + { + x: -100, + y: 6551.92 + }, + { + x: -99, + y: 6553.85 + }, + { + x: -98, + y: 6560.00 + }, + { + x: -97, + y: 6560.00 + }, + { + x: -96, + y: 6565.01 + }, + { + x: -95, + y: 6583.19 + }, + { + x: -94, + y: 6555.79 + }, + { + x: -93, + y: 6556.04 + }, + { + x: -92, + y: 6558.85 + }, + { + x: -91, + y: 6564.75 + }, + { + x: -90, + y: 6564.88 + }, + { + x: -89, + y: 6565.10 + }, + { + x: -88, + y: 6565.72 + }, + { + x: -87, + y: 6565.72 + }, + { + x: -86, + y: 6565.95 + }, + { + x: -85, + y: 6561.82 + }, + { + x: -84, + y: 6566.26 + }, + { + x: -83, + y: 6568.81 + }, + { + x: -82, + y: 6588.57 + }, + { + x: -81, + y: 6587.11 + }, + { + x: -80, + y: 6577.86 + }, + { + x: -79, + y: 6586.51 + }, + { + x: -78, + y: 6581.14 + }, + { + x: -77, + y: 6581.45 + }, + { + x: -76, + y: 6589.54 + }, + { + x: -75, + y: 6580.91 + }, + { + x: -74, + y: 6581.67 + }, + { + x: -73, + y: 6579.06 + }, + { + x: -72, + y: 6578.73 + }, + { + x: -71, + y: 6578.64 + }, + { + x: -70, + y: 6579.08 + }, + { + x: -69, + y: 6577.43 + }, + { + x: -68, + y: 6582.12 + }, + { + x: -67, + y: 6572.42 + }, + { + x: -66, + y: 6578.72 + }, + { + x: -65, + y: 6572.43 + }, + { + x: -64, + y: 6570.64 + }, + { + x: -63, + y: 6561.64 + }, + { + x: -62, + y: 6550.84 + }, + { + x: -61, + y: 6561.83 + }, + { + x: -60, + y: 6561.84 + }, + { + x: -59, + y: 6552.44 + }, + { + x: -58, + y: 6552.47 + }, + { + x: -57, + y: 6562.31 + }, + { + x: -56, + y: 6562.10 + }, + { + x: -55, + y: 6561.65 + }, + { + x: -54, + y: 6547.96 + }, + { + x: -53, + y: 6559.95 + }, + { + x: -52, + y: 6562.08 + }, + { + x: -51, + y: 6557.71 + }, + { + x: -50, + y: 6559.05 + }, + { + x: -49, + y: 6562.69 + }, + { + x: -48, + y: 6578.18 + }, + { + x: -47, + y: 6580.15 + }, + { + x: -46, + y: 6584.26 + }, + { + x: -45, + y: 6574.75 + }, + { + x: -44, + y: 6574.85 + }, + { + x: -43, + y: 6582.63 + }, + { + x: -42, + y: 6569.70 + }, + { + x: -41, + y: 6570.10 + }, + { + x: -40, + y: 6570.11 + }, + { + x: -39, + y: 6569.71 + }, + { + x: -38, + y: 6578.03 + }, + { + x: -37, + y: 6579.92 + }, + { + x: -36, + y: 6571.03 + }, + { + x: -35, + y: 6571.48 + }, + { + x: -34, + y: 6576.67 + }, + { + x: -33, + y: 6576.67 + }, + { + x: -32, + y: 6576.63 + }, + { + x: -31, + y: 6576.68 + }, + { + x: -30, + y: 6573.29 + }, + { + x: -29, + y: 6577.28 + }, + { + x: -28, + y: 6577.73 + }, + { + x: -27, + y: 6577.70 + }, + { + x: -26, + y: 6578.36 + }, + { + x: -25, + y: 6578.24 + }, + { + x: -24, + y: 6581.30 + }, + { + x: -23, + y: 6582.59 + }, + { + x: -22, + y: 6602.51 + }, + { + x: -21, + y: 6582.65 + }, + { + x: -20, + y: 6574.77 + }, + { + x: -19, + y: 6574.41 + }, + { + x: -18, + y: 6575.08 + }, + { + x: -17, + y: 6575.08 + }, + { + x: -16, + y: 6574.09 + }, + { + x: -15, + y: 6568.84 + }, + { + x: -14, + y: 6567.49 + }, + { + x: -13, + y: 6559.75 + }, + { + x: -12, + y: 6566.65 + }, + { + x: -11, + y: 6567.52 + }, + { + x: -10, + y: 6567.59 + }, + { + x: -9, + y: 6564.18 + }, + { + x: -8, + y: 6570.11 + }, + { + x: -7, + y: 6562.70 + }, + { + x: -6, + y: 6562.70 + }, + { + x: -5, + y: 6562.77 + }, + { + x: -4, + y: 6569.46 + }, + { + x: -3, + y: 6571.04 + }, + { + x: -2, + y: 6571.48 + }, + { + x: -1, + y: 6571.30 + } + ] + } + ] + } + }, + prices : { + btc: 8878.48, + eth: 170.46, + bch: 359.93, + xrp: 0.23512 + }, + wallets : { + btc: 24.97311243, + eth: 126.3212, + bch: 78.454412, + xrp: 11278.771123 + }, + watchlist: [ + { + title : 'Ethereum', + iso : 'ETH', + amount: 170.46, + trend : { + dir : 'up', + amount: 2.35 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 154.36 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 154.36 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 146.94 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 146.96 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 146.11 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 150.26 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 146.11 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 150.79 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 145.36 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 141.06 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 140.10 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 138.31 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 138.42 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 138.48 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 138.71 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 148.42 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 146.87 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 147.07 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 135.07 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 135.01 + } + ] + } + ] + }, + { + title : 'Bitcoin Cash', + iso : 'BCH', + amount: 359.93, + trend : { + dir : 'up', + amount: 9.94 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 374.77 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 374.41 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 375.08 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 375.08 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 374.09 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 368.84 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 367.49 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 359.75 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 366.65 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 367.52 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 367.59 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 364.18 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 370.11 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 362.70 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 362.70 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 362.77 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 369.46 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 371.04 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 371.48 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 371.30 + } + ] + } + ] + }, + { + title : 'XRP', + iso : 'XRP', + amount: 0.23512, + trend : { + dir : 'down', + amount: 0.35 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 0.258 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 0.256 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 0.255 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 0.255 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 0.254 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 0.248 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 0.247 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 0.249 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 0.246 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 0.247 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 0.247 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 0.244 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 0.250 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 0.242 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 0.251 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 0.251 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 0.251 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 0.249 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 0.242 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 0.240 + } + ] + } + ] + }, + { + title : 'Litecoin', + iso : 'LTC', + amount: 60.15, + trend : { + dir : 'up', + amount: 0.99 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 62.54 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 61.54 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 62.55 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 60.55 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 59.54 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 58.48 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 54.47 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 51.49 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 51.46 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 53.47 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 52.47 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 54.44 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 59.50 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 62.42 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 61.42 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 60.42 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 58.49 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 57.51 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 54.51 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 51.25 + } + ] + } + ] + }, + { + title : 'Zcash', + iso : 'ZEC', + amount: 58.41, + trend : { + dir : 'down', + amount: 8.79 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 53.54 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 52.54 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 52.55 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 46.44 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 49.50 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 55.42 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 54.42 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 43.49 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 43.46 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 41.47 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 41.47 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 51.55 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 48.54 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 49.48 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 45.47 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 51.42 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 49.49 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 46.51 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 41.51 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 44.25 + } + ] + } + ] + }, + { + title : 'Bitcoin Gold', + iso : 'BTG', + amount: 12.23, + trend : { + dir : 'down', + amount: 4.42 + }, + series: [ + { + name: 'Price', + data: [ + { + x: moment().subtract(20, 'minutes').format('HH:mm'), + y: 14.77 + }, + { + x: moment().subtract(19, 'minutes').format('HH:mm'), + y: 14.41 + }, + { + x: moment().subtract(18, 'minutes').format('HH:mm'), + y: 15.08 + }, + { + x: moment().subtract(17, 'minutes').format('HH:mm'), + y: 15.08 + }, + { + x: moment().subtract(16, 'minutes').format('HH:mm'), + y: 14.09 + }, + { + x: moment().subtract(15, 'minutes').format('HH:mm'), + y: 18.84 + }, + { + x: moment().subtract(14, 'minutes').format('HH:mm'), + y: 17.49 + }, + { + x: moment().subtract(13, 'minutes').format('HH:mm'), + y: 19.75 + }, + { + x: moment().subtract(12, 'minutes').format('HH:mm'), + y: 16.65 + }, + { + x: moment().subtract(11, 'minutes').format('HH:mm'), + y: 17.52 + }, + { + x: moment().subtract(10, 'minutes').format('HH:mm'), + y: 17.59 + }, + { + x: moment().subtract(9, 'minutes').format('HH:mm'), + y: 14.18 + }, + { + x: moment().subtract(8, 'minutes').format('HH:mm'), + y: 10.11 + }, + { + x: moment().subtract(7, 'minutes').format('HH:mm'), + y: 12.70 + }, + { + x: moment().subtract(6, 'minutes').format('HH:mm'), + y: 12.70 + }, + { + x: moment().subtract(5, 'minutes').format('HH:mm'), + y: 12.77 + }, + { + x: moment().subtract(4, 'minutes').format('HH:mm'), + y: 19.46 + }, + { + x: moment().subtract(3, 'minutes').format('HH:mm'), + y: 11.04 + }, + { + x: moment().subtract(2, 'minutes').format('HH:mm'), + y: 11.48 + }, + { + x: moment().subtract(1, 'minutes').format('HH:mm'), + y: 11.30 + } + ] + } + ] + } + ] +}; + diff --git a/src/app/mock-api/dashboards/finance/api.ts b/src/app/mock-api/dashboards/finance/api.ts new file mode 100644 index 00000000..cc9bede7 --- /dev/null +++ b/src/app/mock-api/dashboards/finance/api.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { cloneDeep } from 'lodash-es'; +import { FuseMockApiService } from '@fuse/lib/mock-api'; +import { finance as financeData } from 'app/mock-api/dashboards/finance/data'; + +@Injectable({ + providedIn: 'root' +}) +export class FinanceMockApi +{ + private _finance: any = financeData; + + /** + * Constructor + */ + constructor(private _fuseMockApiService: FuseMockApiService) + { + // Register Mock API handlers + this.registerHandlers(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register Mock API handlers + */ + registerHandlers(): void + { + // ----------------------------------------------------------------------------------------------------- + // @ Sales - GET + // ----------------------------------------------------------------------------------------------------- + this._fuseMockApiService + .onGet('api/dashboards/finance') + .reply(() => [200, cloneDeep(this._finance)]); + } +} diff --git a/src/app/mock-api/dashboards/finance/data.ts b/src/app/mock-api/dashboards/finance/data.ts new file mode 100644 index 00000000..77b3334e --- /dev/null +++ b/src/app/mock-api/dashboards/finance/data.ts @@ -0,0 +1,1045 @@ +import * as moment from 'moment'; + +/* tslint:disable:max-line-length */ +export const finance = { + accountBalance : { + growRate: 38.33, + ami : 45332, + series : [ + { + name: 'Predicted', + data: [ + { + x: moment().subtract(12, 'months').day(1).toDate(), + y: 48.84 + }, + { + x: moment().subtract(12, 'months').day(4).toDate(), + y: 53.51 + }, + { + x: moment().subtract(12, 'months').day(7).toDate(), + y: 52.93 + }, + { + x: moment().subtract(12, 'months').day(10).toDate(), + y: 49.08 + }, + { + x: moment().subtract(12, 'months').day(13).toDate(), + y: 50.27 + }, + { + x: moment().subtract(12, 'months').day(16).toDate(), + y: 48.37 + }, + { + x: moment().subtract(12, 'months').day(19).toDate(), + y: 44.84 + }, + { + x: moment().subtract(12, 'months').day(22).toDate(), + y: 40.71 + }, + { + x: moment().subtract(12, 'months').day(25).toDate(), + y: 41.24 + }, + { + x: moment().subtract(12, 'months').day(28).toDate(), + y: 45.63 + }, + { + x: moment().subtract(11, 'months').day(1).toDate(), + y: 38.20 + }, + { + x: moment().subtract(11, 'months').day(4).toDate(), + y: 39.68 + }, + { + x: moment().subtract(11, 'months').day(7).toDate(), + y: 41.02 + }, + { + x: moment().subtract(11, 'months').day(10).toDate(), + y: 39.41 + }, + { + x: moment().subtract(11, 'months').day(13).toDate(), + y: 35.66 + }, + { + x: moment().subtract(11, 'months').day(16).toDate(), + y: 38.53 + }, + { + x: moment().subtract(11, 'months').day(19).toDate(), + y: 38.53 + }, + { + x: moment().subtract(11, 'months').day(22).toDate(), + y: 40.69 + }, + { + x: moment().subtract(11, 'months').day(25).toDate(), + y: 38.79 + }, + { + x: moment().subtract(11, 'months').day(28).toDate(), + y: 42.98 + }, + { + x: moment().subtract(10, 'months').day(1).toDate(), + y: 43.55 + }, + { + x: moment().subtract(10, 'months').day(4).toDate(), + y: 40.65 + }, + { + x: moment().subtract(10, 'months').day(7).toDate(), + y: 36.50 + }, + { + x: moment().subtract(10, 'months').day(10).toDate(), + y: 33.79 + }, + { + x: moment().subtract(10, 'months').day(13).toDate(), + y: 31.91 + }, + { + x: moment().subtract(10, 'months').day(16).toDate(), + y: 29.68 + }, + { + x: moment().subtract(10, 'months').day(19).toDate(), + y: 29.57 + }, + { + x: moment().subtract(10, 'months').day(22).toDate(), + y: 33.13 + }, + { + x: moment().subtract(10, 'months').day(25).toDate(), + y: 37.08 + }, + { + x: moment().subtract(10, 'months').day(28).toDate(), + y: 35.86 + }, + { + x: moment().subtract(9, 'months').day(1).toDate(), + y: 39.65 + }, + { + x: moment().subtract(9, 'months').day(4).toDate(), + y: 39.01 + }, + { + x: moment().subtract(9, 'months').day(7).toDate(), + y: 34.10 + }, + { + x: moment().subtract(9, 'months').day(10).toDate(), + y: 37.48 + }, + { + x: moment().subtract(9, 'months').day(13).toDate(), + y: 39.29 + }, + { + x: moment().subtract(9, 'months').day(16).toDate(), + y: 38.46 + }, + { + x: moment().subtract(9, 'months').day(19).toDate(), + y: 37.71 + }, + { + x: moment().subtract(9, 'months').day(22).toDate(), + y: 40.15 + }, + { + x: moment().subtract(9, 'months').day(25).toDate(), + y: 35.89 + }, + { + x: moment().subtract(9, 'months').day(28).toDate(), + y: 31.50 + }, + { + x: moment().subtract(8, 'months').day(1).toDate(), + y: 30.50 + }, + { + x: moment().subtract(8, 'months').day(4).toDate(), + y: 25.74 + }, + { + x: moment().subtract(8, 'months').day(7).toDate(), + y: 28.23 + }, + { + x: moment().subtract(8, 'months').day(10).toDate(), + y: 28.48 + }, + { + x: moment().subtract(8, 'months').day(13).toDate(), + y: 30.00 + }, + { + x: moment().subtract(8, 'months').day(16).toDate(), + y: 32.16 + }, + { + x: moment().subtract(8, 'months').day(19).toDate(), + y: 32.99 + }, + { + x: moment().subtract(8, 'months').day(22).toDate(), + y: 37.68 + }, + { + x: moment().subtract(8, 'months').day(25).toDate(), + y: 35.24 + }, + { + x: moment().subtract(8, 'months').day(28).toDate(), + y: 39.18 + }, + { + x: moment().subtract(7, 'months').day(1).toDate(), + y: 41.45 + }, + { + x: moment().subtract(7, 'months').day(4).toDate(), + y: 43.78 + }, + { + x: moment().subtract(7, 'months').day(7).toDate(), + y: 39.41 + }, + { + x: moment().subtract(7, 'months').day(10).toDate(), + y: 39.32 + }, + { + x: moment().subtract(7, 'months').day(13).toDate(), + y: 43.80 + }, + { + x: moment().subtract(7, 'months').day(16).toDate(), + y: 42.43 + }, + { + x: moment().subtract(7, 'months').day(19).toDate(), + y: 43.67 + }, + { + x: moment().subtract(7, 'months').day(22).toDate(), + y: 38.79 + }, + { + x: moment().subtract(7, 'months').day(25).toDate(), + y: 43.57 + }, + { + x: moment().subtract(7, 'months').day(28).toDate(), + y: 41.81 + }, + { + x: moment().subtract(6, 'months').day(1).toDate(), + y: 46.19 + }, + { + x: moment().subtract(6, 'months').day(4).toDate(), + y: 47.69 + }, + { + x: moment().subtract(6, 'months').day(7).toDate(), + y: 49.01 + }, + { + x: moment().subtract(6, 'months').day(10).toDate(), + y: 46.40 + }, + { + x: moment().subtract(6, 'months').day(13).toDate(), + y: 51.28 + }, + { + x: moment().subtract(6, 'months').day(16).toDate(), + y: 50.15 + }, + { + x: moment().subtract(6, 'months').day(19).toDate(), + y: 53.60 + }, + { + x: moment().subtract(6, 'months').day(22).toDate(), + y: 56.08 + }, + { + x: moment().subtract(6, 'months').day(25).toDate(), + y: 52.72 + }, + { + x: moment().subtract(6, 'months').day(28).toDate(), + y: 56.60 + }, + { + x: moment().subtract(5, 'months').day(1).toDate(), + y: 58.36 + }, + { + x: moment().subtract(5, 'months').day(4).toDate(), + y: 56.59 + }, + { + x: moment().subtract(5, 'months').day(7).toDate(), + y: 55.75 + }, + { + x: moment().subtract(5, 'months').day(10).toDate(), + y: 54.74 + }, + { + x: moment().subtract(5, 'months').day(13).toDate(), + y: 54.27 + }, + { + x: moment().subtract(5, 'months').day(16).toDate(), + y: 58.65 + }, + { + x: moment().subtract(5, 'months').day(19).toDate(), + y: 57.00 + }, + { + x: moment().subtract(5, 'months').day(22).toDate(), + y: 60.52 + }, + { + x: moment().subtract(5, 'months').day(25).toDate(), + y: 57.60 + }, + { + x: moment().subtract(5, 'months').day(28).toDate(), + y: 56.48 + }, + { + x: moment().subtract(4, 'months').day(1).toDate(), + y: 54.35 + }, + { + x: moment().subtract(4, 'months').day(4).toDate(), + y: 52.39 + }, + { + x: moment().subtract(4, 'months').day(7).toDate(), + y: 54.52 + }, + { + x: moment().subtract(4, 'months').day(10).toDate(), + y: 54.16 + }, + { + x: moment().subtract(4, 'months').day(13).toDate(), + y: 51.95 + }, + { + x: moment().subtract(4, 'months').day(16).toDate(), + y: 51.19 + }, + { + x: moment().subtract(4, 'months').day(19).toDate(), + y: 46.35 + }, + { + x: moment().subtract(4, 'months').day(22).toDate(), + y: 48.33 + }, + { + x: moment().subtract(4, 'months').day(25).toDate(), + y: 45.84 + }, + { + x: moment().subtract(4, 'months').day(28).toDate(), + y: 48.22 + }, + { + x: moment().subtract(3, 'months').day(1).toDate(), + y: 45.82 + }, + { + x: moment().subtract(3, 'months').day(4).toDate(), + y: 43.48 + }, + { + x: moment().subtract(3, 'months').day(7).toDate(), + y: 41.32 + }, + { + x: moment().subtract(3, 'months').day(10).toDate(), + y: 40.99 + }, + { + x: moment().subtract(3, 'months').day(13).toDate(), + y: 38.49 + }, + { + x: moment().subtract(3, 'months').day(16).toDate(), + y: 40.10 + }, + { + x: moment().subtract(3, 'months').day(19).toDate(), + y: 44.86 + }, + { + x: moment().subtract(3, 'months').day(22).toDate(), + y: 44.03 + }, + { + x: moment().subtract(3, 'months').day(25).toDate(), + y: 41.41 + }, + { + x: moment().subtract(3, 'months').day(28).toDate(), + y: 37.80 + }, + { + x: moment().subtract(2, 'months').day(1).toDate(), + y: 35.24 + }, + { + x: moment().subtract(2, 'months').day(4).toDate(), + y: 32.12 + }, + { + x: moment().subtract(2, 'months').day(7).toDate(), + y: 35.68 + }, + { + x: moment().subtract(2, 'months').day(10).toDate(), + y: 38.00 + }, + { + x: moment().subtract(2, 'months').day(13).toDate(), + y: 37.96 + }, + { + x: moment().subtract(2, 'months').day(16).toDate(), + y: 38.70 + }, + { + x: moment().subtract(2, 'months').day(19).toDate(), + y: 37.45 + }, + { + x: moment().subtract(2, 'months').day(22).toDate(), + y: 37.51 + }, + { + x: moment().subtract(2, 'months').day(25).toDate(), + y: 33.10 + }, + { + x: moment().subtract(2, 'months').day(28).toDate(), + y: 35.09 + }, + { + x: moment().subtract(1, 'months').day(1).toDate(), + y: 31.87 + }, + { + x: moment().subtract(1, 'months').day(4).toDate(), + y: 29.18 + }, + { + x: moment().subtract(1, 'months').day(7).toDate(), + y: 31.91 + }, + { + x: moment().subtract(1, 'months').day(10).toDate(), + y: 34.37 + }, + { + x: moment().subtract(1, 'months').day(13).toDate(), + y: 32.91 + }, + { + x: moment().subtract(1, 'months').day(16).toDate(), + y: 33.17 + }, + { + x: moment().subtract(1, 'months').day(19).toDate(), + y: 37.16 + }, + { + x: moment().subtract(1, 'months').day(22).toDate(), + y: 32.60 + }, + { + x: moment().subtract(1, 'months').day(25).toDate(), + y: 36.94 + }, + { + x: moment().subtract(1, 'months').day(28).toDate(), + y: 35.98 + } + ] + }, + { + name: 'Actual', + data: [ + { + x: moment().subtract(12, 'months').day(1).toDate(), + y: 20.21 + }, + { + x: moment().subtract(12, 'months').day(4).toDate(), + y: 17.49 + }, + { + x: moment().subtract(12, 'months').day(7).toDate(), + y: 16.54 + }, + { + x: moment().subtract(12, 'months').day(10).toDate(), + y: 19.00 + }, + { + x: moment().subtract(12, 'months').day(13).toDate(), + y: 16.47 + }, + { + x: moment().subtract(12, 'months').day(16).toDate(), + y: 13.15 + }, + { + x: moment().subtract(12, 'months').day(19).toDate(), + y: 18.07 + }, + { + x: moment().subtract(12, 'months').day(22).toDate(), + y: 17.93 + }, + { + x: moment().subtract(12, 'months').day(25).toDate(), + y: 18.92 + }, + { + x: moment().subtract(12, 'months').day(28).toDate(), + y: 18.46 + }, + { + x: moment().subtract(11, 'months').day(1).toDate(), + y: 18.04 + }, + { + x: moment().subtract(11, 'months').day(4).toDate(), + y: 17.78 + }, + { + x: moment().subtract(11, 'months').day(7).toDate(), + y: 20.15 + }, + { + x: moment().subtract(11, 'months').day(10).toDate(), + y: 18.92 + }, + { + x: moment().subtract(11, 'months').day(13).toDate(), + y: 17.08 + }, + { + x: moment().subtract(11, 'months').day(16).toDate(), + y: 17.11 + }, + { + x: moment().subtract(11, 'months').day(19).toDate(), + y: 15.70 + }, + { + x: moment().subtract(11, 'months').day(22).toDate(), + y: 15.07 + }, + { + x: moment().subtract(11, 'months').day(25).toDate(), + y: 14.51 + }, + { + x: moment().subtract(11, 'months').day(28).toDate(), + y: 15.22 + }, + { + x: moment().subtract(10, 'months').day(1).toDate(), + y: 19.77 + }, + { + x: moment().subtract(10, 'months').day(4).toDate(), + y: 23.67 + }, + { + x: moment().subtract(10, 'months').day(7).toDate(), + y: 27.98 + }, + { + x: moment().subtract(10, 'months').day(10).toDate(), + y: 30.80 + }, + { + x: moment().subtract(10, 'months').day(13).toDate(), + y: 28.56 + }, + { + x: moment().subtract(10, 'months').day(16).toDate(), + y: 27.45 + }, + { + x: moment().subtract(10, 'months').day(19).toDate(), + y: 27.50 + }, + { + x: moment().subtract(10, 'months').day(22).toDate(), + y: 27.28 + }, + { + x: moment().subtract(10, 'months').day(25).toDate(), + y: 24.36 + }, + { + x: moment().subtract(10, 'months').day(28).toDate(), + y: 22.89 + }, + { + x: moment().subtract(9, 'months').day(1).toDate(), + y: 28.04 + }, + { + x: moment().subtract(9, 'months').day(4).toDate(), + y: 27.77 + }, + { + x: moment().subtract(9, 'months').day(7).toDate(), + y: 30.24 + }, + { + x: moment().subtract(9, 'months').day(10).toDate(), + y: 26.57 + }, + { + x: moment().subtract(9, 'months').day(13).toDate(), + y: 22.18 + }, + { + x: moment().subtract(9, 'months').day(16).toDate(), + y: 19.64 + }, + { + x: moment().subtract(9, 'months').day(19).toDate(), + y: 16.74 + }, + { + x: moment().subtract(9, 'months').day(22).toDate(), + y: 17.21 + }, + { + x: moment().subtract(9, 'months').day(25).toDate(), + y: 20.05 + }, + { + x: moment().subtract(9, 'months').day(28).toDate(), + y: 16.13 + }, + { + x: moment().subtract(8, 'months').day(1).toDate(), + y: 10.71 + }, + { + x: moment().subtract(8, 'months').day(4).toDate(), + y: 7.99 + }, + { + x: moment().subtract(8, 'months').day(7).toDate(), + y: 11.33 + }, + { + x: moment().subtract(8, 'months').day(10).toDate(), + y: 15.36 + }, + { + x: moment().subtract(8, 'months').day(13).toDate(), + y: 20.16 + }, + { + x: moment().subtract(8, 'months').day(16).toDate(), + y: 22.56 + }, + { + x: moment().subtract(8, 'months').day(19).toDate(), + y: 19.34 + }, + { + x: moment().subtract(8, 'months').day(22).toDate(), + y: 18.32 + }, + { + x: moment().subtract(8, 'months').day(25).toDate(), + y: 20.75 + }, + { + x: moment().subtract(8, 'months').day(28).toDate(), + y: 17.09 + }, + { + x: moment().subtract(7, 'months').day(1).toDate(), + y: 18.31 + }, + { + x: moment().subtract(7, 'months').day(4).toDate(), + y: 14.34 + }, + { + x: moment().subtract(7, 'months').day(7).toDate(), + y: 9.93 + }, + { + x: moment().subtract(7, 'months').day(10).toDate(), + y: 10.64 + }, + { + x: moment().subtract(7, 'months').day(13).toDate(), + y: 6.18 + }, + { + x: moment().subtract(7, 'months').day(16).toDate(), + y: 10.32 + }, + { + x: moment().subtract(7, 'months').day(19).toDate(), + y: 12.80 + }, + { + x: moment().subtract(7, 'months').day(22).toDate(), + y: 13.44 + }, + { + x: moment().subtract(7, 'months').day(25).toDate(), + y: 18.35 + }, + { + x: moment().subtract(7, 'months').day(28).toDate(), + y: 22.87 + }, + { + x: moment().subtract(6, 'months').day(1).toDate(), + y: 26.92 + }, + { + x: moment().subtract(6, 'months').day(4).toDate(), + y: 22.50 + }, + { + x: moment().subtract(6, 'months').day(7).toDate(), + y: 18.14 + }, + { + x: moment().subtract(6, 'months').day(10).toDate(), + y: 19.06 + }, + { + x: moment().subtract(6, 'months').day(13).toDate(), + y: 19.73 + }, + { + x: moment().subtract(6, 'months').day(16).toDate(), + y: 18.82 + }, + { + x: moment().subtract(6, 'months').day(19).toDate(), + y: 23.33 + }, + { + x: moment().subtract(6, 'months').day(22).toDate(), + y: 20.48 + }, + { + x: moment().subtract(6, 'months').day(25).toDate(), + y: 25.47 + }, + { + x: moment().subtract(6, 'months').day(28).toDate(), + y: 28.84 + }, + { + x: moment().subtract(5, 'months').day(1).toDate(), + y: 27.71 + }, + { + x: moment().subtract(5, 'months').day(4).toDate(), + y: 25.22 + }, + { + x: moment().subtract(5, 'months').day(7).toDate(), + y: 25.43 + }, + { + x: moment().subtract(5, 'months').day(10).toDate(), + y: 24.13 + }, + { + x: moment().subtract(5, 'months').day(13).toDate(), + y: 20.02 + }, + { + x: moment().subtract(5, 'months').day(16).toDate(), + y: 18.38 + }, + { + x: moment().subtract(5, 'months').day(19).toDate(), + y: 18.30 + }, + { + x: moment().subtract(5, 'months').day(22).toDate(), + y: 18.72 + }, + { + x: moment().subtract(5, 'months').day(25).toDate(), + y: 22.46 + }, + { + x: moment().subtract(5, 'months').day(28).toDate(), + y: 21.71 + }, + { + x: moment().subtract(4, 'months').day(1).toDate(), + y: 29.88 + }, + { + x: moment().subtract(4, 'months').day(4).toDate(), + y: 26.94 + }, + { + x: moment().subtract(4, 'months').day(7).toDate(), + y: 28.06 + }, + { + x: moment().subtract(4, 'months').day(10).toDate(), + y: 30.40 + }, + { + x: moment().subtract(4, 'months').day(13).toDate(), + y: 28.98 + }, + { + x: moment().subtract(4, 'months').day(16).toDate(), + y: 30.13 + }, + { + x: moment().subtract(4, 'months').day(19).toDate(), + y: 27.60 + }, + { + x: moment().subtract(4, 'months').day(22).toDate(), + y: 30.21 + }, + { + x: moment().subtract(4, 'months').day(25).toDate(), + y: 26.88 + }, + { + x: moment().subtract(4, 'months').day(28).toDate(), + y: 25.72 + }, + { + x: moment().subtract(3, 'months').day(1).toDate(), + y: 27.89 + }, + { + x: moment().subtract(3, 'months').day(4).toDate(), + y: 30.69 + }, + { + x: moment().subtract(3, 'months').day(7).toDate(), + y: 31.42 + }, + { + x: moment().subtract(3, 'months').day(10).toDate(), + y: 36.14 + }, + { + x: moment().subtract(3, 'months').day(13).toDate(), + y: 32.02 + }, + { + x: moment().subtract(3, 'months').day(16).toDate(), + y: 27.30 + }, + { + x: moment().subtract(3, 'months').day(19).toDate(), + y: 29.51 + }, + { + x: moment().subtract(3, 'months').day(22).toDate(), + y: 32.67 + }, + { + x: moment().subtract(3, 'months').day(25).toDate(), + y: 28.82 + }, + { + x: moment().subtract(3, 'months').day(28).toDate(), + y: 28.85 + }, + { + x: moment().subtract(2, 'months').day(1).toDate(), + y: 29.15 + }, + { + x: moment().subtract(2, 'months').day(4).toDate(), + y: 27.90 + }, + { + x: moment().subtract(2, 'months').day(7).toDate(), + y: 30.71 + }, + { + x: moment().subtract(2, 'months').day(10).toDate(), + y: 28.02 + }, + { + x: moment().subtract(2, 'months').day(13).toDate(), + y: 23.82 + }, + { + x: moment().subtract(2, 'months').day(16).toDate(), + y: 18.83 + }, + { + x: moment().subtract(2, 'months').day(19).toDate(), + y: 14.48 + }, + { + x: moment().subtract(2, 'months').day(22).toDate(), + y: 11.76 + }, + { + x: moment().subtract(2, 'months').day(25).toDate(), + y: 12.75 + }, + { + x: moment().subtract(2, 'months').day(28).toDate(), + y: 11.36 + }, + { + x: moment().subtract(1, 'months').day(1).toDate(), + y: 11.60 + }, + { + x: moment().subtract(1, 'months').day(4).toDate(), + y: 15.24 + }, + { + x: moment().subtract(1, 'months').day(7).toDate(), + y: 13.05 + }, + { + x: moment().subtract(1, 'months').day(10).toDate(), + y: 17.25 + }, + { + x: moment().subtract(1, 'months').day(13).toDate(), + y: 18.50 + }, + { + x: moment().subtract(1, 'months').day(16).toDate(), + y: 23.04 + }, + { + x: moment().subtract(1, 'months').day(19).toDate(), + y: 21.87 + }, + { + x: moment().subtract(1, 'months').day(22).toDate(), + y: 25.97 + }, + { + x: moment().subtract(1, 'months').day(25).toDate(), + y: 22.46 + }, + { + x: moment().subtract(1, 'months').day(28).toDate(), + y: 17.67 + } + ] + } + ] + }, + budget : { + expenses : 11763.34, + expensesLimit: 20000, + savings : 10974.12, + savingsGoal : 250000, + bills : 1789.22, + billsLimit : 1000 + }, + previousStatement : { + status : 'paid', + date : moment().startOf('day').subtract(15, 'days').format('LL'), + limit : 34500, + spent : 27221.21, + minimum: 7331.94 + }, + currentStatement : { + status : 'pending', + date : moment().startOf('day').subtract(15, 'days').add(1, 'month').format('LL'), + limit : 34500, + spent : 39819.41, + minimum: 9112.51 + }, + recentTransactions: [ + { + id : '1b6fd296-bc6a-4d45-bf4f-e45519a58cf5', + transactionId: '528651571NT', + name : 'Morgan Page', + amount : +1358.75, + status : 'completed', + date : '2019-10-07T22:22:37.274Z' + }, + { + id : '2dec6074-98bd-4623-9526-6480e4776569', + transactionId: '421436904YT', + name : 'Nita Hebert', + amount : -1042.82, + status : 'completed', + date : '2019-12-18T14:51:24.461Z' + }, + { + id : 'ae7c065f-4197-4021-a799-7a221822ad1d', + transactionId: '685377421YT', + name : 'Marsha Chambers', + amount : +1828.16, + status : 'pending', + date : '2019-12-25T17:52:14.304Z' + }, + { + id : '0c43dd40-74f6-49d5-848a-57a4a45772ab', + transactionId: '884960091RT', + name : 'Charmaine Jackson', + amount : +1647.55, + status : 'completed', + date : '2019-11-29T06:32:16.111Z' + }, + { + id : 'e5c9f0ed-a64c-4bfe-a113-29f80b4e162c', + transactionId: '361402213NT', + name : 'Maura Carey', + amount : -927.43, + status : 'completed', + date : '2019-11-24T12:13:23.064Z' + } + ] +}; diff --git a/src/app/mock-api/index.ts b/src/app/mock-api/index.ts index 35e24b7d..0673b048 100644 --- a/src/app/mock-api/index.ts +++ b/src/app/mock-api/index.ts @@ -5,8 +5,10 @@ import { AuthMockApi } from 'app/mock-api/common/auth/api'; import { CalendarMockApi } from 'app/mock-api/apps/calendar/api'; import { ChatMockApi } from 'app/mock-api/apps/chat/api'; import { ContactsMockApi } from 'app/mock-api/apps/contacts/api'; +import { CryptoMockApi } from 'app/mock-api/dashboards/crypto/api'; import { ECommerceInventoryMockApi } from 'app/mock-api/apps/ecommerce/inventory/api'; import { FileManagerMockApi } from 'app/mock-api/apps/file-manager/api'; +import { FinanceMockApi } from 'app/mock-api/dashboards/finance/api'; import { HelpCenterMockApi } from 'app/mock-api/apps/help-center/api'; import { IconsMockApi } from 'app/mock-api/ui/icons/api'; import { MailboxMockApi } from 'app/mock-api/apps/mailbox/api'; @@ -29,8 +31,10 @@ export const mockApiServices = [ CalendarMockApi, ChatMockApi, ContactsMockApi, + CryptoMockApi, ECommerceInventoryMockApi, FileManagerMockApi, + FinanceMockApi, HelpCenterMockApi, IconsMockApi, MailboxMockApi, diff --git a/src/app/modules/admin/dashboards/crypto/crypto.component.html b/src/app/modules/admin/dashboards/crypto/crypto.component.html new file mode 100644 index 00000000..530599fd --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.component.html @@ -0,0 +1,277 @@ +
+ + + + + + +
+ + +
+
+
+
+
{{item.title}}
+
({{item.iso}})
+
+
+
+ {{item.amount | currency:'USD':'symbol':'1.2-4'}} +
+ +
+ {{item.trend.amount}}% +
+
+
+ +
+
+ + +
+ + +
+ + Action + + + + + + + + + + Buy + Sell + + +
+ + +
+ + Wallet + + + + {{walletSelector.triggerValue}} + - + + {{data.wallets[walletSelector.value]}} + {{walletSelector.value | uppercase}} + + + + Bitcoin + Ethereum + Bitcoin Cash + XRP + + + USD: + + {{data.wallets[walletSelector.value] * data.prices[walletSelector.value] | currency:'USD'}} + + + +
+ + +
+ + Amount + + + {{walletSelector.value | uppercase}} + USD + + + $ + + + + It will cost: + + {{buyAmount.value * data.prices[walletSelector.value] | currency:'USD':'symbol':'1.2-4'}} + + + + You will receive: + + {{buyAmount.value / data.prices[walletSelector.value] | number:'1.2-6'}} {{walletSelector.value | uppercase}} + + + + + +
+ + +
+ + Amount + + + {{walletSelector.value | uppercase}} + USD + + + $ + + + + You will receive: + + {{sellAmount.value * data.prices[walletSelector.value] | currency:'USD':'symbol':'1.2-4'}} + + + + You will sell: + + {{sellAmount.value / data.prices[walletSelector.value] | number:'1.2-6'}} {{walletSelector.value | uppercase}} + + + + + +
+
+ +
+ +
+ + + + + +
+
+ +
+
+
Bitcoin
+
(BTC)
+
+
+
{{data.btc.amount | currency:'USD':'symbol':'1.2-2'}}
+ +
+ {{data.btc.trend.amount}}% +
+
+
+ +
+
+ +
+
+ +
+ +
+ +
diff --git a/src/app/modules/admin/dashboards/crypto/crypto.component.ts b/src/app/modules/admin/dashboards/crypto/crypto.component.ts new file mode 100644 index 00000000..2c4b494a --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.component.ts @@ -0,0 +1,238 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import * as moment from 'moment'; +import { ApexOptions, ChartComponent } from 'ng-apexcharts'; +import { FuseMediaWatcherService } from '@fuse/services/media-watcher'; +import { CryptoService } from 'app/modules/admin/dashboards/crypto/crypto.service'; + +@Component({ + selector : 'crypto', + templateUrl : './crypto.component.html', + encapsulation : ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CryptoComponent implements OnInit, OnDestroy +{ + @ViewChild('btcChartComponent') btcChartComponent: ChartComponent; + appConfig: any; + btcOptions: ApexOptions = {}; + data: any; + drawerMode: 'over' | 'side' = 'side'; + drawerOpened: boolean = true; + watchlistChartOptions: ApexOptions = {}; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor( + private _cryptoService: CryptoService, + private _changeDetectorRef: ChangeDetectorRef, + private _fuseMediaWatcherService: FuseMediaWatcherService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to media changes + this._fuseMediaWatcherService.onMediaChange$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(({matchingAliases}) => { + + // Set the drawerMode and drawerOpened if 'lg' breakpoint is active + if ( matchingAliases.includes('lg') ) + { + this.drawerMode = 'side'; + this.drawerOpened = true; + } + else + { + this.drawerMode = 'over'; + this.drawerOpened = false; + } + + // Mark for check + this._changeDetectorRef.markForCheck(); + }); + + // Get the data + this._cryptoService.data$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((data) => { + + // Store the data + this.data = data; + + // Prepare the chart data + this._prepareChartData(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Prepare the chart data from the data + * + * @private + */ + private _prepareChartData(): void + { + // BTC + this.btcOptions = { + chart : { + animations: { + enabled: false + }, + fontFamily: 'inherit', + foreColor : 'inherit', + width : '100%', + height : '100%', + type : 'line', + toolbar : { + show: false + }, + zoom : { + enabled: false + } + }, + colors : ['#5A67D8'], + dataLabels: { + enabled: false + }, + grid : { + borderColor : 'var(--fuse-border)', + position : 'back', + show : true, + strokeDashArray: 6, + xaxis : { + lines: { + show: true + } + }, + yaxis : { + lines: { + show: true + } + } + }, + legend : { + show: false + }, + series : this.data.btc.price.series, + stroke : { + width: 2, + curve: 'straight' + }, + tooltip : { + shared: true, + theme : 'dark', + y : { + formatter: (value: number): string => '$' + value.toFixed(2) + } + }, + xaxis : { + type : 'numeric', + crosshairs: { + show : true, + position: 'back', + fill : { + type : 'color', + color: 'var(--fuse-border)' + }, + width : 3, + stroke : { + dashArray: 0, + width : 0 + }, + opacity : 0.9 + }, + tickAmount: 8, + axisTicks : { + show : true, + color: 'var(--fuse-border)' + }, + axisBorder: { + show: false + }, + tooltip : { + enabled: false + }, + labels : { + show : true, + trim : false, + rotate : 0, + minHeight : 40, + hideOverlappingLabels: true, + formatter : (value): string => moment().subtract(Math.abs(parseInt(value, 10)), 'minutes').format('HH:mm'), + style : { + colors: 'currentColor' + } + } + }, + yaxis : { + axisTicks : { + show : true, + color: 'var(--fuse-border)' + }, + axisBorder : { + show: false + }, + forceNiceScale: true, + labels : { + minWidth : 40, + formatter: (value: number): string => '$' + value.toFixed(0), + style : { + colors: 'currentColor' + } + } + } + }; + + // Watchlist options + this.watchlistChartOptions = { + chart : { + animations: { + enabled: false + }, + width : '100%', + height : '100%', + type : 'line', + sparkline : { + enabled: true + } + }, + colors : ['#A0AEC0'], + stroke : { + width: 2, + curve: 'smooth' + }, + tooltip: { + enabled: false + }, + xaxis : { + type: 'category' + } + }; + } +} diff --git a/src/app/modules/admin/dashboards/crypto/crypto.module.ts b/src/app/modules/admin/dashboards/crypto/crypto.module.ts new file mode 100644 index 00000000..902320b1 --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.module.ts @@ -0,0 +1,42 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +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 { 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 { NgApexchartsModule } from 'ng-apexcharts'; +import { SharedModule } from 'app/shared/shared.module'; +import { CryptoComponent } from 'app/modules/admin/dashboards/crypto/crypto.component'; +import { cryptoRoutes } from 'app/modules/admin/dashboards/crypto/crypto.routing'; + +@NgModule({ + declarations: [ + CryptoComponent + ], + imports : [ + RouterModule.forChild(cryptoRoutes), + MatButtonModule, + MatButtonToggleModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatMenuModule, + MatSelectModule, + MatSidenavModule, + MatSortModule, + MatTableModule, + MatTabsModule, + NgApexchartsModule, + SharedModule + ] +}) +export class CryptoModule +{ +} diff --git a/src/app/modules/admin/dashboards/crypto/crypto.resolvers.ts b/src/app/modules/admin/dashboards/crypto/crypto.resolvers.ts new file mode 100644 index 00000000..65184929 --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.resolvers.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; +import { CryptoService } from 'app/modules/admin/dashboards/crypto/crypto.service'; + +@Injectable({ + providedIn: 'root' +}) +export class CryptoResolver implements Resolve +{ + /** + * Constructor + */ + constructor(private _cryptoService: CryptoService) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable + { + return this._cryptoService.getData(); + } +} diff --git a/src/app/modules/admin/dashboards/crypto/crypto.routing.ts b/src/app/modules/admin/dashboards/crypto/crypto.routing.ts new file mode 100644 index 00000000..c248684e --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.routing.ts @@ -0,0 +1,13 @@ +import { Route } from '@angular/router'; +import { CryptoComponent } from 'app/modules/admin/dashboards/crypto/crypto.component'; +import { CryptoResolver } from 'app/modules/admin/dashboards/crypto/crypto.resolvers'; + +export const cryptoRoutes: Route[] = [ + { + path : '', + component: CryptoComponent, + resolve : { + data: CryptoResolver + } + } +]; diff --git a/src/app/modules/admin/dashboards/crypto/crypto.service.ts b/src/app/modules/admin/dashboards/crypto/crypto.service.ts new file mode 100644 index 00000000..8908c2bc --- /dev/null +++ b/src/app/modules/admin/dashboards/crypto/crypto.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class CryptoService +{ + private _data: BehaviorSubject = new BehaviorSubject(null); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for data + */ + get data$(): Observable + { + return this._data.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get data + */ + getData(): Observable + { + return this._httpClient.get('api/dashboards/crypto').pipe( + tap((response: any) => { + this._data.next(response); + }) + ); + } +} diff --git a/src/app/modules/admin/dashboards/finance/finance.component.html b/src/app/modules/admin/dashboards/finance/finance.component.html new file mode 100644 index 00000000..ca7a9123 --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.component.html @@ -0,0 +1,526 @@ +
+ +
+ + +
+
+

Finance dashboard

+
Keep track of your financial status
+
+
+ + + + + +
+ + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
Previous Statement
+
+ Paid on {{data.previousStatement.date}} +
+
+
+ + + + + + + + + +
+
+
+
+
Card Limit
+
{{data.previousStatement.limit | currency:'USD'}}
+
+
+
Spent
+
{{data.previousStatement.spent | currency:'USD'}}
+
+
+
Minimum
+
{{data.previousStatement.minimum | currency:'USD'}}
+
+
+
+ +
+
+ +
+
+
+
Current Statement
+
+ Must be paid before {{data.currentStatement.date}} +
+
+
+ + + + + + + + + +
+
+
+
+
Card Limit
+
{{data.currentStatement.limit | currency:'USD'}}
+
+
+
Spent
+
{{data.currentStatement.spent | currency:'USD'}}
+
+
+
Minimum
+
{{data.currentStatement.minimum | currency:'USD'}}
+
+
+
+
+ +
+
+
+
+
Account Balance
+
Monthly balance growth and avg. monthly income
+
+
+ + + + + + + +
+
+
+
+
{{data.accountBalance.growRate}}%
+
Average Monthly Growth
+
+
+
{{data.accountBalance.ami | currency:'USD'}}
+
Average Monthly Income
+
+
+
+
+ +
+
+
+ +
+ +
+
+
Recent transactions
+
1 pending, 4 completed
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Transaction ID + + + {{transaction.transactionId}} + + + Date + + + {{transaction.date | date:'MMM dd, y'}} + + + Name + + + {{transaction.name}} + + + Amount + + + {{transaction.amount | currency:'USD'}} + + + Status + + + {{transaction.status}} + + + +
+
+
+ + +
+
+
+
Budget
+
Monthly budget summary
+
+
+ + + + + + + + + +
+
+
+ Last month; you had 223 expense transactions, 12 savings entries and 4 bills. +
+
+
+
+
+ +
+
+
Expenses
+
{{data.budget.expenses | currency:'USD'}}
+ +
+
+
2.6%
+ +
+
+
+
+
+
+ +
+
+
Savings
+
{{data.budget.savings | currency:'USD'}}
+ +
+
+
12.7%
+ +
+
+
+
+
+
+ +
+
+
Bills
+
{{data.budget.bills | currency:'USD'}}
+ +
+
+
105.7%
+ +
+
+
Exceeded your personal limit! Be careful next month.
+
+
+
+ +
+
+
+ +
+ +
diff --git a/src/app/modules/admin/dashboards/finance/finance.component.ts b/src/app/modules/admin/dashboards/finance/finance.component.ts new file mode 100644 index 00000000..e7f479cb --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.component.ts @@ -0,0 +1,146 @@ +import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { MatSort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { ApexOptions } from 'ng-apexcharts'; +import { FinanceService } from 'app/modules/admin/dashboards/finance/finance.service'; + +@Component({ + selector : 'finance', + templateUrl : './finance.component.html', + encapsulation : ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FinanceComponent implements OnInit, AfterViewInit, OnDestroy +{ + @ViewChild('recentTransactionsTable', {read: MatSort}) recentTransactionsTableMatSort: MatSort; + + data: any; + accountBalanceOptions: ApexOptions; + recentTransactionsDataSource: MatTableDataSource = new MatTableDataSource(); + recentTransactionsTableColumns: string[] = ['transactionId', 'date', 'name', 'amount', 'status']; + private _unsubscribeAll: Subject = new Subject(); + + /** + * Constructor + */ + constructor(private _financeService: FinanceService) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Get the data + this._financeService.data$ + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((data) => { + + // Store the data + this.data = data; + + // Store the table data + this.recentTransactionsDataSource.data = data.recentTransactions; + + // Prepare the chart data + this._prepareChartData(); + }); + } + + /** + * After view init + */ + ngAfterViewInit(): void + { + // Make the data source sortable + this.recentTransactionsDataSource.sort = this.recentTransactionsTableMatSort; + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Track by function for ngFor loops + * + * @param index + * @param item + */ + trackByFn(index: number, item: any): any + { + return item.id || index; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Prepare the chart data from the data + * + * @private + */ + private _prepareChartData(): void + { + // Account balance + this.accountBalanceOptions = { + chart : { + animations: { + speed : 400, + animateGradually: { + enabled: false + } + }, + fontFamily: 'inherit', + foreColor : 'inherit', + width : '100%', + height : '100%', + type : 'area', + sparkline : { + enabled: true + } + }, + colors : ['#A3BFFA', '#667EEA'], + fill : { + colors : ['#CED9FB', '#AECDFD'], + opacity: 0.5, + type : 'solid' + }, + series : this.data.accountBalance.series, + stroke : { + curve: 'straight', + width: 2 + }, + tooltip: { + followCursor: true, + theme : 'dark', + x : { + format: 'MMM dd, yyyy' + }, + y : { + formatter: (value): string => value + '%' + } + }, + xaxis : { + type: 'datetime' + } + }; + } +} diff --git a/src/app/modules/admin/dashboards/finance/finance.module.ts b/src/app/modules/admin/dashboards/finance/finance.module.ts new file mode 100644 index 00000000..f3275204 --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.module.ts @@ -0,0 +1,34 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; +import { NgApexchartsModule } from 'ng-apexcharts'; +import { SharedModule } from 'app/shared/shared.module'; +import { FinanceComponent } from 'app/modules/admin/dashboards/finance/finance.component'; +import { financeRoutes } from 'app/modules/admin/dashboards/finance/finance.routing'; + +@NgModule({ + declarations: [ + FinanceComponent + ], + imports : [ + RouterModule.forChild(financeRoutes), + MatButtonModule, + MatDividerModule, + MatIconModule, + MatMenuModule, + MatProgressBarModule, + MatSortModule, + MatTableModule, + NgApexchartsModule, + SharedModule + ] +}) +export class FinanceModule +{ +} diff --git a/src/app/modules/admin/dashboards/finance/finance.resolvers.ts b/src/app/modules/admin/dashboards/finance/finance.resolvers.ts new file mode 100644 index 00000000..f2505cbc --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.resolvers.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; +import { Observable } from 'rxjs'; +import { FinanceService } from 'app/modules/admin/dashboards/finance/finance.service'; + +@Injectable({ + providedIn: 'root' +}) +export class FinanceResolver implements Resolve +{ + /** + * Constructor + */ + constructor(private _financeService: FinanceService) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param route + * @param state + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable + { + return this._financeService.getData(); + } +} diff --git a/src/app/modules/admin/dashboards/finance/finance.routing.ts b/src/app/modules/admin/dashboards/finance/finance.routing.ts new file mode 100644 index 00000000..2a731558 --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.routing.ts @@ -0,0 +1,13 @@ +import { Route } from '@angular/router'; +import { FinanceComponent } from 'app/modules/admin/dashboards/finance/finance.component'; +import { FinanceResolver } from 'app/modules/admin/dashboards/finance/finance.resolvers'; + +export const financeRoutes: Route[] = [ + { + path : '', + component: FinanceComponent, + resolve : { + data: FinanceResolver + } + } +]; diff --git a/src/app/modules/admin/dashboards/finance/finance.service.ts b/src/app/modules/admin/dashboards/finance/finance.service.ts new file mode 100644 index 00000000..5e07314e --- /dev/null +++ b/src/app/modules/admin/dashboards/finance/finance.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class FinanceService +{ + private _data: BehaviorSubject = new BehaviorSubject(null); + + /** + * Constructor + */ + constructor(private _httpClient: HttpClient) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Getter for data + */ + get data$(): Observable + { + return this._data.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get data + */ + getData(): Observable + { + return this._httpClient.get('api/dashboards/finance').pipe( + tap((response: any) => { + this._data.next(response); + }) + ); + } +}