├── .browserslistrc
├── .editorconfig
├── README.md
├── angular.json
├── config.json
├── karma.conf.js
├── license
├── package.json
├── src
├── app
│ ├── about
│ │ ├── about.component.html
│ │ └── about.component.ts
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── app.router.ts
│ ├── common
│ │ ├── common.data.ts
│ │ └── common.service.ts
│ ├── dashboard
│ │ ├── cards
│ │ │ ├── cards.component.html
│ │ │ └── cards.component.ts
│ │ ├── column-chart
│ │ │ ├── column-chart.component.html
│ │ │ └── column-chart.component.ts
│ │ ├── dashboard.component.html
│ │ ├── dashboard.component.ts
│ │ ├── dashboard.service.ts
│ │ ├── line-chart
│ │ │ ├── line-chart.component.html
│ │ │ └── line-chart.component.ts
│ │ ├── pie-chart
│ │ │ ├── pie-chart.component.html
│ │ │ └── pie-chart.component.ts
│ │ └── recent-exp-grid
│ │ │ ├── recent-exp-grid.component.html
│ │ │ └── recent-exp-grid.component.ts
│ ├── expense
│ │ ├── content
│ │ │ ├── content.component.html
│ │ │ └── content.component.ts
│ │ ├── dialogs
│ │ │ ├── dialogs.component.html
│ │ │ └── dialogs.component.ts
│ │ ├── expense.component.html
│ │ ├── expense.component.ts
│ │ └── filter
│ │ │ ├── filter.component.html
│ │ │ ├── filter.component.ts
│ │ │ └── filter.service.ts
│ ├── main.ts
│ └── menu
│ │ ├── menu.component.html
│ │ └── menu.component.ts
├── assets
│ ├── definition
│ │ └── material.scss
│ ├── favicon.ico
│ ├── images
│ │ ├── About.svg
│ │ ├── AvailableCash.svg
│ │ ├── Home.svg
│ │ ├── OverallTransactions.svg
│ │ ├── Profile-img-Desktop
│ │ ├── Profile-img-Mobile
│ │ ├── Search.svg
│ │ ├── TotalExpenses.svg
│ │ ├── TotalIncome.svg
│ │ ├── Transactions.svg
│ │ ├── balance.svg
│ │ ├── cash-wallet.svg
│ │ ├── category
│ │ │ ├── bills.png
│ │ │ ├── business.png
│ │ │ ├── clothing.png
│ │ │ ├── education.png
│ │ │ ├── entertainment.png
│ │ │ ├── extra.png
│ │ │ ├── food.png
│ │ │ ├── health.png
│ │ │ ├── house.png
│ │ │ ├── insurance.png
│ │ │ ├── interest.png
│ │ │ ├── miscellaneous.png
│ │ │ ├── personal.png
│ │ │ ├── rent.png
│ │ │ ├── salary.png
│ │ │ ├── shopping.png
│ │ │ ├── tax.png
│ │ │ ├── transport.png
│ │ │ └── utilities.png
│ │ ├── exp-track.png
│ │ ├── expense.svg
│ │ ├── fonts
│ │ │ ├── Expense-Analysis-Sample.eot
│ │ │ ├── Expense-Analysis-Sample.svg
│ │ │ ├── Expense-Analysis-Sample.ttf
│ │ │ ├── Expense-Analysis-Sample.woff
│ │ │ ├── controls.eot
│ │ │ ├── controls.svg
│ │ │ ├── controls.ttf
│ │ │ ├── controls.woff
│ │ │ ├── icons.eot
│ │ │ ├── icons.svg
│ │ │ ├── icons.ttf
│ │ │ └── icons.woff
│ │ ├── i.svg
│ │ ├── income.svg
│ │ ├── no-records.png
│ │ ├── t.svg
│ │ ├── title.svg
│ │ ├── transaction.svg
│ │ └── user.svg
│ ├── index.css
│ ├── index.scss
│ ├── styles.css
│ └── styles.scss
├── environments
│ └── environment.ts
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts
├── tsconfig.app.json
├── tsconfig.base.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major version
15 | last 2 iOS major versions
16 | Firefox ESR
17 | not IE 9-11 # For IE 9-11 support, remove 'not'.
18 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Essential JS 2 for Angular - Expense Tracker
2 |
3 | This expense tracker demo application showcases using several Essential JS 2 components together in
4 | a real-world application scenario. You can further explore the source code of this application and
5 | use it as a reference for integrating Essential JS 2 components into your applications.
6 |
7 | ## Deployment
8 |
9 | ### Install
10 |
11 | To install all dependent packages, use the below command
12 |
13 | ```
14 | npm install
15 | ```
16 |
17 | ### Run
18 |
19 | To run the sample, use the below command
20 |
21 | ```
22 | ng serve
23 | ```
24 |
25 | ## Demo
26 |
27 | #### https://ej2.syncfusion.com/showcase/angular/expensetracker/
28 |
29 | Check all the showcase samples from here.
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "ej2-ng-expense-tracker": {
7 | "projectType": "application",
8 | "schematics": {},
9 | "root": "",
10 | "sourceRoot": "src",
11 | "prefix": "app",
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "output",
17 | "index": "src/index.html",
18 | "main": "src/main.ts",
19 | "polyfills": "src/polyfills.ts",
20 | "tsConfig": "tsconfig.app.json",
21 | "aot": true,
22 | "assets": [
23 | "src/favicon.ico",
24 | "src/assets"
25 | ],
26 | "styles": [
27 | "src/styles.css"
28 | ],
29 | "scripts": []
30 | },
31 | "configurations": {
32 | "production": {
33 | "fileReplacements": [
34 | {
35 | "replace": "src/environments/environment.ts",
36 | "with": "src/environments/environment.prod.ts"
37 | }
38 | ],
39 | "optimization": true,
40 | "outputHashing": "all",
41 | "sourceMap": false,
42 | "extractCss": true,
43 | "namedChunks": false,
44 | "extractLicenses": true,
45 | "vendorChunk": false,
46 | "buildOptimizer": true,
47 | "budgets": [
48 | {
49 | "type": "initial",
50 | "maximumWarning": "2mb",
51 | "maximumError": "5mb"
52 | },
53 | {
54 | "type": "anyComponentStyle",
55 | "maximumWarning": "6kb",
56 | "maximumError": "10kb"
57 | }
58 | ]
59 | }
60 | }
61 | },
62 | "serve": {
63 | "builder": "@angular-devkit/build-angular:dev-server",
64 | "options": {
65 | "browserTarget": "ej2-ng-expense-tracker:build"
66 | },
67 | "configurations": {
68 | "production": {
69 | "browserTarget": "ej2-ng-expense-tracker:build:production"
70 | }
71 | }
72 | },
73 | "extract-i18n": {
74 | "builder": "@angular-devkit/build-angular:extract-i18n",
75 | "options": {
76 | "browserTarget": "ej2-ng-expense-tracker:build"
77 | }
78 | },
79 | "test": {
80 | "builder": "@angular-devkit/build-angular:karma",
81 | "options": {
82 | "main": "src/test.ts",
83 | "polyfills": "src/polyfills.ts",
84 | "tsConfig": "tsconfig.spec.json",
85 | "karmaConfig": "karma.conf.js",
86 | "assets": [
87 | "src/favicon.ico",
88 | "src/assets"
89 | ],
90 | "styles": [
91 | "src/styles.css"
92 | ],
93 | "scripts": []
94 | }
95 | },
96 | "lint": {
97 | "builder": "@angular-devkit/build-angular:tslint",
98 | "options": {
99 | "tsConfig": [
100 | "tsconfig.app.json",
101 | "tsconfig.spec.json",
102 | "e2e/tsconfig.json"
103 | ],
104 | "exclude": [
105 | "**/node_modules/**"
106 | ]
107 | }
108 | },
109 | "e2e": {
110 | "builder": "@angular-devkit/build-angular:protractor",
111 | "options": {
112 | "protractorConfig": "e2e/protractor.conf.js",
113 | "devServerTarget": "ej2-ng-expense-tracker:serve"
114 | },
115 | "configurations": {
116 | "production": {
117 | "devServerTarget": "ej2-ng-expense-tracker:serve:production"
118 | }
119 | }
120 | }
121 | }
122 | }},
123 | "defaultProject": "ej2-ng-expense-tracker"
124 | }
125 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "sasslint": ["./src/assets/**/*.scss"],
3 | "tslint": ["./src/app/**/*.ts", "!./src/app/**/*-model.d.ts", "!./src/app/**/**/*.d.ts", "!./src/app/**/**/*.ngfactory.ts"],
4 | "ts": ["./src/app/**/*.ts", "!./node_modules/**/*.ts"],
5 | "styleDependency":["ej2"],
6 | "isShowCase": true
7 | }
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, './coverage/ej2-ng-expense-tracker'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | Essential JS 2 library is available under the Syncfusion Essential Studio program, and can be licensed either under the Syncfusion Community License Program or the Syncfusion commercial license.
2 |
3 | To be qualified for the Syncfusion Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion’s terms and conditions.
4 |
5 | Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options.
6 |
7 | Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion’s license containing all terms and conditions.
8 |
9 | The Syncfusion license that contains the terms and conditions can be found at
10 | https://www.syncfusion.com/content/downloads/syncfusion_license.pdf
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@syncfusion/ej2-ng-expense-tracker",
3 | "version": "0.0.1",
4 | "description": "Essential JS 2 for Angular - Expense Tracker",
5 | "author": "Syncfusion Inc.",
6 | "license": "SEE LICENSE IN license",
7 | "scripts": {
8 | "ng": "ng",
9 | "start": "ng serve",
10 | "build": "ng build",
11 | "test": "ng test",
12 | "lint": "ng lint",
13 | "e2e": "ng e2e",
14 | "scss": "gulp styles",
15 | "ci-publish": "gulp publish-samples"
16 | },
17 | "private": true,
18 | "dependencies": {
19 | "@angular/animations": "^15.0.0",
20 | "@angular/common": "^15.0.0",
21 | "@angular/compiler": "^15.0.0",
22 | "@angular/core": "^15.0.0",
23 | "@angular/forms": "^15.0.0",
24 | "@angular/platform-browser": "^15.0.0",
25 | "@angular/platform-browser-dynamic": "^15.0.0",
26 | "@angular/router": "^15.0.0",
27 | "@syncfusion/ej2-angular-base": "*",
28 | "@syncfusion/ej2-angular-buttons": "*",
29 | "@syncfusion/ej2-angular-calendars": "*",
30 | "@syncfusion/ej2-angular-charts": "*",
31 | "@syncfusion/ej2-angular-dropdowns": "*",
32 | "@syncfusion/ej2-angular-grids": "*",
33 | "@syncfusion/ej2-angular-inputs": "*",
34 | "@syncfusion/ej2-angular-navigations": "*",
35 | "@syncfusion/ej2-angular-popups": "*",
36 | "ajv": "^8.11.2",
37 | "gulp": "^3.9.0",
38 | "gulp-sass": "^3.1.0",
39 | "run-sequence": "2.2.0",
40 | "rxjs": "~7.5.0",
41 | "shelljs": "^0.7.0",
42 | "tslib": "^2.3.0",
43 | "zone.js": "~0.12.0"
44 | },
45 | "devDependencies": {
46 | "@angular-devkit/build-angular": "^15.0.4",
47 | "@angular/cli": "~15.0.4",
48 | "@angular/compiler-cli": "^15.0.0",
49 | "@types/jasmine": "~4.3.0",
50 | "@types/jasminewd2": "~2.0.3",
51 | "@types/node": "^10.13.0",
52 | "codelyzer": "^6.0.0-next.1",
53 | "jasmine-core": "~4.5.0",
54 | "jasmine-spec-reporter": "~5.0.0",
55 | "karma": "~6.4.0",
56 | "karma-chrome-launcher": "~3.1.0",
57 | "karma-coverage-istanbul-reporter": "~3.0.2",
58 | "karma-jasmine": "~5.1.0",
59 | "karma-jasmine-html-reporter": "~2.0.0",
60 | "protractor": "~7.0.0",
61 | "ts-node": "~8.3.0",
62 | "tslint": "~6.1.0",
63 | "typescript": "~4.8.2"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/app/about/about.component.html:
--------------------------------------------------------------------------------
1 |
2 |
{{title}}
3 |
{{description}}
4 |
{{listTitle}}
5 |
11 |
--------------------------------------------------------------------------------
/src/app/about/about.component.ts:
--------------------------------------------------------------------------------
1 | import { LowerCasePipe } from '@angular/common';
2 | import { Component, ViewEncapsulation, OnInit } from '@angular/core';
3 |
4 | import { MenuComponent } from '../menu/menu.component';
5 | import { CardsComponent } from '../dashboard/cards/cards.component';
6 |
7 | import { CommonService } from '../common/common.service';
8 |
9 | @Component({
10 | templateUrl: 'about.component.html',
11 | encapsulation: ViewEncapsulation.None,
12 | providers: [CommonService, CardsComponent]
13 | })
14 | export class AboutComponent implements OnInit {
15 | public title: string;
16 | public listTitle: string;
17 | public description: string;
18 | public controlList: Object[];
19 |
20 | /** Configurations for the About page */
21 | constructor(
22 | public common: CommonService,
23 | public cards: CardsComponent,
24 | public menu: MenuComponent
25 | ) {
26 | this.common.removeRootClass();
27 | this.common.addRootClass('about-page');
28 | this.title = 'About this sample';
29 | this.listTitle = 'List of EJ2 components used in this sample';
30 | this.description = 'This expense tracker demo application showcases using several Essential JS 2 '
31 | + 'components together in a real-world application scenario. You can further explore the source '
32 | + 'code of this application and use it as a reference for integrating Essential JS 2 components '
33 | + 'into your applications.';
34 |
35 | this.controlList = [
36 | { 'control': 'Button', 'link': 'http://ej2.syncfusion.com/angular/documentation/button/getting-started/' },
37 | { 'control': 'Chart', 'link': 'http://ej2.syncfusion.com/angular/documentation/chart/getting-started/' },
38 | { 'control': 'CheckBox', 'link': 'http://ej2.syncfusion.com/angular/documentation/check-box/getting-started/' },
39 | { 'control': 'DatePicker', 'link': 'http://ej2.syncfusion.com/angular/documentation/datepicker/getting-started/' },
40 | { 'control': 'DateRangePicker', 'link': 'http://ej2.syncfusion.com/angular/documentation/daterangepicker/getting-started/' },
41 | { 'control': 'Dialog', 'link': 'http://ej2.syncfusion.com/angular/documentation/dialog/getting-started/' },
42 | { 'control': 'DropDownList', 'link': 'http://ej2.syncfusion.com/angular/documentation/drop-down-list/getting-started/' },
43 | { 'control': 'Grid', 'link': 'http://ej2.syncfusion.com/angular/documentation/grid/getting-started/' },
44 | { 'control': 'MultiSelect', 'link': 'http://ej2.syncfusion.com/angular/documentation/multi-select/getting-started/' },
45 | { 'control': 'NumericTextBox', 'link': 'http://ej2.syncfusion.com/angular/documentation/numerictextbox/getting-started/' },
46 | { 'control': 'RadioButton' , 'link': 'http://ej2.syncfusion.com/angular/documentation/radio-button/getting-started/'},
47 | { 'control': 'TextBoxes', 'link': 'http://ej2.syncfusion.com/angular/documentation/textbox/getting-started/' },
48 | { 'control': 'TimePicker', 'link': 'http://ej2.syncfusion.com/angular/documentation/timepicker/getting-started/' }
49 | ];
50 | }
51 |
52 | public ngOnInit(): void {
53 | this.cards.updateCardValues();
54 | this.menu.removeToggleClass();
55 | this.menu.disableOverlay();
56 | }
57 | }
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Directive, HostListener } from '@angular/core';
2 |
3 | import { expenseData, startDate, endDate } from './common/common.data';
4 |
5 | @Component({
6 | selector: 'app-root',
7 | templateUrl: 'app.component.html'
8 | })
9 | export class AppComponent {
10 | public dataSource: Object[];
11 | public startDate: Date;
12 | public endDate: Date;
13 |
14 | constructor() {
15 | this.startDate = startDate;
16 | this.endDate = endDate;
17 | this.dataSource = expenseData;
18 | this.handleResize();
19 | }
20 |
21 | public handleResize(): void {
22 | if (document.documentElement.offsetWidth > 1400) {
23 | document.body.style.minHeight = 'auto';
24 | document.body.style.minHeight = document.documentElement.offsetHeight + 'px';
25 | }
26 | }
27 |
28 | @HostListener('window:resize', ['$event'])
29 | onResize(event: any): void {
30 | /** Document height alignment corrections for high resoultion screens */
31 | this.handleResize();
32 | }
33 | }
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3 | import { APP_BASE_HREF, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
4 |
5 | import { GridModule, PagerModule } from '@syncfusion/ej2-angular-grids';
6 | import { NumericTextBoxAllModule } from '@syncfusion/ej2-angular-inputs';
7 | import { CheckBoxAllModule, RadioButtonAllModule } from '@syncfusion/ej2-angular-buttons';
8 | import { ChartAllModule, AccumulationChartAllModule } from '@syncfusion/ej2-angular-charts';
9 | import { MultiSelectAllModule, DropDownListAllModule } from '@syncfusion/ej2-angular-dropdowns';
10 | import { DialogAllModule, TooltipAllModule } from '@syncfusion/ej2-angular-popups';
11 | import { DateRangePickerModule, DateRangePickerAllModule, DatePickerAllModule, TimePickerAllModule } from '@syncfusion/ej2-angular-calendars';
12 |
13 | import { routing } from './app.router';
14 |
15 | import { AppComponent } from './app.component';
16 | import { MenuComponent } from './menu/menu.component';
17 | import { AboutComponent } from './about/about.component';
18 | import { ExpenseComponent } from './expense/expense.component';
19 | import { CardsComponent } from './dashboard/cards/cards.component';
20 | import { FilterComponent } from './expense/filter/filter.component';
21 | import { DashBoardComponent } from './dashboard/dashboard.component';
22 | import { ContentComponent } from './expense/content/content.component';
23 | import { DialogsComponent } from './expense/dialogs/dialogs.component';
24 | import { PieChartComponent } from './dashboard/pie-chart/pie-chart.component';
25 | import { LineChartComponent } from './dashboard/line-chart/line-chart.component';
26 | import { ColumnChartComponent } from './dashboard/column-chart/column-chart.component';
27 | import { RecentExpGridComponent } from './dashboard/recent-exp-grid/recent-exp-grid.component';
28 |
29 | import { CommonService } from './common/common.service';
30 | import { DashBoardService } from './dashboard/dashboard.service';
31 |
32 | @NgModule({
33 | imports: [
34 | routing,
35 | GridModule,
36 | PagerModule,
37 | BrowserModule,
38 | ChartAllModule,
39 | DialogAllModule,
40 | CheckBoxAllModule,
41 | DatePickerAllModule,
42 | TimePickerAllModule,
43 | MultiSelectAllModule,
44 | RadioButtonAllModule,
45 | DateRangePickerModule,
46 | DropDownListAllModule,
47 | NumericTextBoxAllModule,
48 | DateRangePickerAllModule,
49 | AccumulationChartAllModule
50 | ],
51 | declarations: [
52 | AppComponent,
53 | MenuComponent,
54 | CardsComponent,
55 | AboutComponent,
56 | FilterComponent,
57 | ExpenseComponent,
58 | ContentComponent,
59 | DialogsComponent,
60 | PieChartComponent,
61 | DashBoardComponent,
62 | LineChartComponent,
63 | ColumnChartComponent,
64 | RecentExpGridComponent,
65 | ],
66 | bootstrap: [AppComponent],
67 | schemas: [CUSTOM_ELEMENTS_SCHEMA],
68 | providers: [
69 | Location,
70 | CommonService,
71 | DashBoardService,
72 | ContentComponent,
73 | {provide: APP_BASE_HREF, useValue : '/' },
74 | {provide: LocationStrategy, useClass: HashLocationStrategy}
75 | ]
76 | })
77 | export class AppModule {
78 | private location: Location;
79 | constructor(location: Location) {
80 | this.location = location;
81 | }
82 | }
--------------------------------------------------------------------------------
/src/app/app.router.ts:
--------------------------------------------------------------------------------
1 | import { ModuleWithProviders } from '@angular/core';
2 | import { Routes, RouterModule } from '@angular/router';
3 | import { DashBoardComponent } from './dashboard/dashboard.component';
4 | import { ExpenseComponent } from './expense/expense.component';
5 | import { AboutComponent } from './about/about.component';
6 |
7 | // Route Configuration
8 | export const routes: Routes = [
9 | { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
10 | { path: 'dashboard', component: DashBoardComponent },
11 | { path: 'expense', component: ExpenseComponent },
12 | { path: 'about', component: AboutComponent },
13 | { path: '**', redirectTo: 'home' }
14 | ];
15 |
16 | export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
--------------------------------------------------------------------------------
/src/app/common/common.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, ViewChild } from '@angular/core';
2 |
3 | import { extend, Internationalization } from '@syncfusion/ej2-base';
4 | import { Predicate } from '@syncfusion/ej2-data';
5 |
6 | import { expenseData } from '../common/common.data';
7 |
8 | @Injectable()
9 | export class CommonService {
10 | public predicateStart: Predicate;
11 | public predicateEnd: Predicate;
12 | public predicate: Predicate;
13 | public intl: Internationalization = new Internationalization();
14 |
15 | constructor() {}
16 |
17 | public getPredicate(start: Date, end: Date): Predicate {
18 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', start);
19 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', end);
20 | this.predicate = this.predicateStart.and(this.predicateEnd);
21 | return this.predicate;
22 | }
23 |
24 | public addRootClass(cls: string): void {
25 | let ele: HTMLElement = document.body;
26 | ele.classList.add(cls);
27 | }
28 |
29 | public removeRootClass(): void {
30 | let ele: HTMLElement = document.body;
31 | ele.classList.remove('dashboard-page');
32 | ele.classList.remove('expense-page');
33 | ele.classList.remove('about-page');
34 | }
35 |
36 | public objectAssign(e: any): object[] {
37 | let result: Object[] = [];
38 | let obj: any;
39 | obj = extend(obj, e.result, {}, true);
40 | for (let data: number = 0; data < Object.keys(e.result).length; data++) {
41 | result.push(obj[data]);
42 | }
43 | return result;
44 | }
45 |
46 | public getDate(value: Date): string {
47 | return this.intl.formatDate(value, { skeleton: 'yMd', type: 'date' });
48 | }
49 |
50 | public getCurrencyVal(value: number): string {
51 | return this.intl.formatNumber(value, { format: 'C0' });
52 | }
53 |
54 | public getNumberVal(value: number): string {
55 | return this.intl.getNumberFormat({ skeleton: 'C0', currency: 'USD' })(value);
56 | }
57 | }
--------------------------------------------------------------------------------
/src/app/dashboard/cards/cards.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/dashboard/cards/cards.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit } from '@angular/core';
2 |
3 | import { Internationalization } from '@syncfusion/ej2-base';
4 | import { Query, DataManager, Predicate } from '@syncfusion/ej2-data';
5 |
6 | import { AppComponent } from '../../app.component';
7 |
8 | import { CommonService } from '../../common/common.service';
9 |
10 | @Component({
11 | selector: 'cards',
12 | templateUrl: 'cards.component.html',
13 | encapsulation: ViewEncapsulation.None,
14 | providers: [CommonService]
15 | })
16 | export class CardsComponent implements OnInit {
17 | public predicate: Predicate;
18 | public predicateEnd: Predicate;
19 | public predicateStart: Predicate;
20 | public totalIncome: string = '$0';
21 | public totalExpense: string = '$0';
22 | public totalBalance: string = '$0';
23 | public totalTransactions: string = '0';
24 |
25 | constructor(public common: CommonService, public app: AppComponent) {}
26 |
27 | public ngOnInit(): void {
28 |
29 | /** Updates each card values on the initial load */
30 | this.updateCardValues();
31 | }
32 |
33 | public updateCardValues(): void {
34 | let predicate: Predicate = this.common.getPredicate(this.app.startDate, this.app.endDate);
35 | let intl: Internationalization = new Internationalization();
36 | let incomeRS: number = 0;
37 | let expenseRS: number = 0;
38 | let incomeD: any;
39 | let expenseD: any;
40 |
41 | /** Calulates total income and sets to the Income card */
42 | new DataManager(this.app.dataSource).executeQuery((new Query()
43 | .where((predicate).and('TransactionType', 'equal', 'Income'))))
44 | .then((e: any) => {
45 | incomeD = this.common.objectAssign(e);
46 | for (let i: number = 0; i < incomeD.length; i++) {
47 | incomeRS += parseInt(incomeD[i].Amount, 0);
48 | }
49 | this.totalIncome = this.common.getCurrencyVal(incomeRS ? incomeRS : 0);
50 | });
51 |
52 | /** Calulates total expenses and sets to the Expenses card */
53 | new DataManager(this.app.dataSource).executeQuery(new Query()
54 | .where((predicate).and('TransactionType', 'equal', 'Expense')))
55 | .then((e: any) => {
56 | expenseD = this.common.objectAssign(e);
57 | for (let i: number = 0; i < expenseD.length; i++) {
58 | expenseRS += parseInt(expenseD[i].Amount, 0);
59 | }
60 | this.totalExpense = this.common.getCurrencyVal(expenseRS ? expenseRS : 0);
61 | document.getElementById('current-balance').textContent = this.common.getCurrencyVal(incomeRS - expenseRS);
62 |
63 | /** Based on the Income and Expense, calulates the balance and sets to the Balance card */
64 | this.totalBalance = this.common.getCurrencyVal(incomeRS - expenseRS);
65 | });
66 |
67 | /** Calulates total transactions and sets to the Transactions card */
68 | let transaction: any = new DataManager(this.app.dataSource)
69 | .executeLocal((new Query().where(predicate)));
70 | this.totalTransactions = this.common.getNumberVal(transaction.length);
71 | }
72 | }
--------------------------------------------------------------------------------
/src/app/dashboard/column-chart/column-chart.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/app/dashboard/column-chart/column-chart.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
2 |
3 | import { ChartComponent, ILoadedEventArgs} from '@syncfusion/ej2-angular-charts';
4 |
5 | import { DashBoardComponent } from '../dashboard.component';
6 |
7 | @Component({
8 | selector: 'column-chart',
9 | templateUrl: 'column-chart.component.html',
10 | encapsulation: ViewEncapsulation.None
11 | })
12 | export class ColumnChartComponent implements OnInit {
13 | @ViewChild('columnChart') colChart: ChartComponent;
14 |
15 | public lineObj: any;
16 | public marker: Object;
17 | public margin: Object;
18 | public cBorder: Object;
19 | public tooltip: Object;
20 | public titleStyle: Object;
21 | public incomeDS: any = [];
22 | public expenseDS: any = [];
23 | public primaryXAxis: Object;
24 | public primaryYAxis: Object;
25 | public legendSettings: Object;
26 | public initialRender: boolean = true;
27 | public animation: Object;
28 |
29 | constructor(public dashBoard: DashBoardComponent) {}
30 |
31 | public ngOnInit(): void {
32 |
33 | /** Configurations for the Column chart (Income vs Expense) component */
34 | this.primaryXAxis = {
35 | labelFormat: 'MMM',
36 | valueType: 'DateTime',
37 | intervalType: 'Months',
38 | edgeLabelPlacement: 'Shift'
39 | };
40 | this.primaryYAxis = {
41 | minimum: 3000,
42 | maximum: 9000,
43 | labelFormat: 'c0'
44 | };
45 | this.titleStyle = { textAlignment: 'Near', fontWeight: '500', size: '16', color: '#000' };
46 | this.legendSettings = { visible: true };
47 | this.tooltip = {
48 | fill: '#707070',
49 | enable: true,
50 | shared: true,
51 | format: '${series.name} : ${point.y}',
52 | header: 'Month - ${point.x} ',
53 | };
54 | this.marker = { visible: true, height: 10, width: 10 };
55 | this.margin = { top: 90 };
56 | this.cBorder = { width: 0.5, color: '#A16EE5' };
57 | this.animation = { enable: false };
58 | }
59 |
60 | public onChartLoaded(args: ILoadedEventArgs): void {
61 | if (this.initialRender) {
62 | this.initialRender = false;
63 | this.lineObj.line.refresh();
64 | } else {
65 | this.initialRender = false;
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Dashboard
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
2 |
3 | import { Query, DataManager, Predicate } from '@syncfusion/ej2-data';
4 | import { DateRangePickerComponent, RangeEventArgs } from '@syncfusion/ej2-angular-calendars';
5 |
6 | import { AppComponent } from '../app.component';
7 | import { MenuComponent } from '../menu/menu.component';
8 | import { CardsComponent } from './cards/cards.component';
9 | import { PieChartComponent } from './pie-chart/pie-chart.component';
10 | import { LineChartComponent } from './line-chart/line-chart.component';
11 | import { ColumnChartComponent } from './column-chart/column-chart.component';
12 | import { RecentExpGridComponent } from './recent-exp-grid/recent-exp-grid.component';
13 |
14 | import { DashBoardService } from './dashboard.service';
15 | import { CommonService } from '../common/common.service';
16 |
17 | @Component({
18 | templateUrl: 'dashboard.component.html',
19 | encapsulation: ViewEncapsulation.None,
20 | providers: [DashBoardService, CommonService]
21 | })
22 | export class DashBoardComponent implements OnInit {
23 | @ViewChild('cards') cards: CardsComponent;
24 | @ViewChild('pieChart') pieChart: PieChartComponent;
25 | @ViewChild('lineChart') lineChart: LineChartComponent;
26 | @ViewChild('columnChart') columnChart: ColumnChartComponent;
27 | @ViewChild('recentGrid') recentGrid: RecentExpGridComponent;
28 | @ViewChild('dateRangePicker') dateRangePicker: DateRangePickerComponent;
29 |
30 | public predicate: Predicate;
31 | public datePresets: Object[];
32 | public lineChartData: Object[];
33 | public predicateEnd: Predicate;
34 | public predicateStart: Predicate;
35 | public colChartIncomeData: Object[];
36 | public colChartExpenseData: Object[];
37 |
38 | constructor(
39 | public app: AppComponent,
40 | public dashService: DashBoardService,
41 | public common: CommonService,
42 | public menu: MenuComponent
43 | ) {
44 | this.common.removeRootClass();
45 | this.common.addRootClass('dashboard-page');
46 | }
47 |
48 | public ngOnInit(): void {
49 |
50 | /** Configurations for the components in the DashBoard page */
51 | this.menu.removeToggleClass();
52 | this.menu.disableOverlay();
53 | this.datePresets = [
54 | { label: 'Last Month', start: new Date('10/1/2017'), end: new Date('10/31/2017') },
55 | { label: 'Last 3 Months', start: new Date('9/1/2017'), end: new Date('11/30/2017') },
56 | { label: 'All Time', start: new Date('6/1/2017'), end: new Date('11/30/2017') }
57 | ];
58 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', this.app.startDate);
59 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', this.app.endDate);
60 | this.predicate = this.predicateStart.and(this.predicateEnd);
61 | this.updateChartData();
62 | }
63 |
64 | public ngAfterViewInit(): void {
65 | this.columnChart.lineObj = this.lineChart;
66 | }
67 |
68 | /** Updates chart data during the DateRangePicker filtering operation */
69 | public updateChartData(): void {
70 | new DataManager(this.app.dataSource).executeQuery(new Query()
71 | .where(this.predicate.and('TransactionType', 'equal', 'Expense')))
72 | .then((e: any) => {
73 | this.colChartExpenseData = this.dashService.getColumnChartExpenseDS(e);
74 | });
75 | new DataManager(this.app.dataSource).executeQuery(new Query()
76 | .where(this.predicate.and('TransactionType', 'equal', 'Income')))
77 | .then((e: any) => {
78 | this.colChartIncomeData = this.dashService.getColumnChartIncomeDS(e);
79 | this.lineChartData = this.dashService.getLineChartDS();
80 | });
81 | }
82 |
83 | /** Performs fitlering and refreshes cards, chart and grid components based on the selected date ranges by using the DateRangePicker */
84 | public onDateRangeChange(args: RangeEventArgs): void {
85 | this.app.startDate = args.startDate;
86 | this.app.endDate = args.endDate;
87 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', args.startDate);
88 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', args.endDate);
89 | this.predicate = this.predicateStart.and(this.predicateEnd);
90 | this.cards.updateCardValues();
91 | this.pieChart.getTotalExpense();
92 | this.updateChartData();
93 | setTimeout(() => {
94 | this.pieChart.pie.refresh();
95 | this.lineChart.line.refresh();
96 | this.columnChart.colChart.refresh();
97 | }, 400);
98 | setTimeout(() => {
99 | this.pieChart.refreshPieChart();
100 | }, 1000);
101 | }
102 | }
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { extend } from '@syncfusion/ej2-base';
4 |
5 | import { CommonService } from '../common/common.service';
6 | import { userInfo } from '../common/common.data';
7 |
8 | @Injectable()
9 | export class DashBoardService {
10 | public name: string;
11 | public lineD: any = [];
12 | public lineDS: any = [];
13 | public curDateTime: any;
14 | public tempLineDS: any = {};
15 | public colIncomeDS: any = [];
16 | public colExpenseDS: any = [];
17 | public tempIncomeDS: any = {};
18 | public tempExpenseDS: any = {};
19 |
20 | constructor(public common: CommonService) {
21 | this.name = userInfo.FirstName;
22 | }
23 |
24 | public getName(): string {
25 | return this.name;
26 | }
27 |
28 | public getColumnChartIncomeDS(e: any): Object[] {
29 | this.colIncomeDS = [];
30 | this.tempIncomeDS = [];
31 | let result: Object[] = this.common.objectAssign(e);
32 | for (let i: number = 0; i < result.length; i++) {
33 | let cur: any = result[i];
34 | if (cur.DateTime.getMonth() in this.tempIncomeDS) {
35 | this.curDateTime = this.tempIncomeDS[cur.DateTime.getMonth()];
36 | this.tempIncomeDS[cur.DateTime.getMonth()].Amount = parseInt(this.curDateTime.Amount, 0) + parseInt(cur.Amount, 0);
37 | } else {
38 | this.tempIncomeDS[cur.DateTime.getMonth()] = cur;
39 | this.tempIncomeDS[cur.DateTime.getMonth()].DateTime = new Date(new Date(this.tempIncomeDS[cur.DateTime.getMonth()].DateTime.setHours(0, 0, 0, 0)).setDate(1));
40 | }
41 | }
42 | for (let data in this.tempIncomeDS) {
43 | this.colIncomeDS.push(this.tempIncomeDS[data]);
44 | }
45 | return this.colIncomeDS;
46 | }
47 |
48 | public getColumnChartExpenseDS(e: any): Object[] {
49 | this.colExpenseDS = [];
50 | this.tempExpenseDS = [];
51 | let result: Object[] = this.common.objectAssign(e);
52 | for (let i: number = 0; i < result.length; i++) {
53 | let cur: any = result[i];
54 | if (cur.DateTime.getMonth() in this.tempExpenseDS) {
55 | this.curDateTime = this.tempExpenseDS[cur.DateTime.getMonth()];
56 | this.tempExpenseDS[cur.DateTime.getMonth()].Amount = parseInt(this.curDateTime.Amount, 0) + parseInt(cur.Amount, 0);
57 | } else {
58 | this.tempExpenseDS[cur.DateTime.getMonth()] = cur;
59 | this.tempExpenseDS[cur.DateTime.getMonth()].DateTime = new Date(new Date(this.tempExpenseDS[cur.DateTime.getMonth()].DateTime.setHours(0, 0, 0, 0)).setDate(1));
60 | }
61 | }
62 | for (let data in this.tempExpenseDS) {
63 | this.colExpenseDS.push(this.tempExpenseDS[data]);
64 | }
65 | return this.colExpenseDS;
66 | }
67 |
68 | public getLineChartDS(): Object[] {
69 | this.lineD = [];
70 | this.lineDS = [];
71 | this.tempLineDS = [];
72 | let result: Object[] = [];
73 | let obj: any;
74 | obj = extend(obj, (this.colIncomeDS.concat(this.colExpenseDS)), {}, true);
75 | for (let data: number = 0; data < Object.keys((this.colIncomeDS.concat(this.colExpenseDS))).length; data++) {
76 | result.push(obj[data]);
77 | }
78 | this.tempLineDS = result;
79 | for (let i: number = 0; i < this.tempLineDS.length; i++) {
80 | let cur: any = this.tempLineDS[i];
81 | if (cur.DateTime.getMonth() in this.lineD) {
82 | this.curDateTime = this.lineD[cur.DateTime.getMonth()];
83 | this.lineD[cur.DateTime.getMonth()].Amount = Math.abs((parseInt(this.curDateTime.Amount, 0) - parseInt(cur.Amount, 0)));
84 | } else {
85 | this.lineD[cur.DateTime.getMonth()] = cur;
86 | }
87 | }
88 | for (let data: number = 0; data <= this.lineD.length; data++) {
89 | if (this.lineD[data]) {
90 | this.lineDS.push(this.lineD[data]);
91 | }
92 | }
93 | return this.lineDS;
94 | }
95 | }
--------------------------------------------------------------------------------
/src/app/dashboard/line-chart/line-chart.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/app/dashboard/line-chart/line-chart.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
2 |
3 | import { ChartComponent } from '@syncfusion/ej2-angular-charts';
4 |
5 | import { DashBoardComponent } from '../dashboard.component';
6 |
7 | @Component({
8 | selector: 'line-chart',
9 | templateUrl: 'line-chart.component.html',
10 | encapsulation: ViewEncapsulation.None
11 | })
12 | export class LineChartComponent implements OnInit {
13 | @ViewChild('lineChart') line: ChartComponent;
14 |
15 | public marker: Object;
16 | public margin: Object;
17 | public tooltip: Object;
18 | public lBorder: Object;
19 | public lineDS: any = [];
20 | public crossHair: Object;
21 | public chartArea: Object;
22 | public dataSource: Object;
23 | public primaryXAxis: Object;
24 | public primaryYAxis: Object;
25 | public animation: Object;
26 |
27 | constructor(public dashBoard: DashBoardComponent) {}
28 |
29 | public ngOnInit(): void {
30 |
31 | /** Configurations for the Line chart component */
32 | this.primaryXAxis = {
33 | valueType: 'DateTime',
34 | labelFormat: 'MMM',
35 | majorGridLines: { width: 0 },
36 | intervalType: 'Months'
37 | };
38 | this.primaryYAxis = {
39 | maximum: 1800,
40 | interval: 300,
41 | labelFormat: 'c0'
42 | };
43 | this.tooltip = {
44 | fill: '#707070',
45 | enable: true,
46 | shared: true,
47 | format: '${series.name} : ${point.y}',
48 | header: 'Month - ${point.x} '
49 | };
50 | this.chartArea = {
51 | border: { width: 0 }
52 | };
53 | this.margin = { top: 90 };
54 | this.lBorder = { width: 0.5, color: '#0470D8' };
55 | this.marker = {
56 | visible: true,
57 | width: 10,
58 | height: 10,
59 | fill: 'white',
60 | border: { width: 2, color: '#0470D8' },
61 | };
62 | this.animation = { enable: false };
63 | }
64 | }
--------------------------------------------------------------------------------
/src/app/dashboard/pie-chart/pie-chart.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | |
44 | {{data.text}} |
45 | {{data.y | currency:'USD'}} |
46 | {{data.x}} |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/app/dashboard/pie-chart/pie-chart.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit, ViewChild, HostListener } from '@angular/core';
2 |
3 | import { GridComponent } from '@syncfusion/ej2-angular-grids';
4 | import { Query, DataManager } from '@syncfusion/ej2-data';
5 | import { isNullOrUndefined as isNOU, Browser } from '@syncfusion/ej2-base';
6 | import { IAccTextRenderEventArgs, IAccLoadedEventArgs, AccumulationChartComponent,
7 | IAccAnimationCompleteEventArgs } from '@syncfusion/ej2-angular-charts';
8 |
9 | import { AppComponent } from '../../app.component';
10 |
11 | @Component({
12 | selector: 'pie-chart',
13 | templateUrl: 'pie-chart.component.html',
14 | encapsulation: ViewEncapsulation.None
15 | })
16 | export class PieChartComponent {
17 | @ViewChild('pie') pie: AccumulationChartComponent;
18 | @ViewChild('legendGrid') lGrid: GridComponent;
19 |
20 | public dataLabel: Object;
21 | public groupValue: string;
22 | public hiGridData: Object[];
23 | public expTotal: number = 0;
24 | public legendSettings: Object;
25 | public colorPalettes: Object[];
26 | public category: string[] = [];
27 | public tempData: IExpenseData[];
28 | public legendData: Object[] = [];
29 | public pieLegendData: Object[] = [];
30 | public pieRenderData: Object[] = [];
31 | public enableLegend: boolean = false;
32 | public pieRenderingData: Object[] = [];
33 | public animation: Object;
34 | public showWaitingPopup: boolean = false;
35 |
36 | constructor(public app: AppComponent) {}
37 |
38 | public ngOnInit(): void {
39 |
40 | /** Configurations for the Pie chart component */
41 | this.legendSettings = { visible: true };
42 | this.colorPalettes = ['#61EFCD', '#CDDE1F', '#FEC200', '#CA765A', '#2485FA', '#F57D7D', '#C152D2', '#8854D9', '#3D4EB8',
43 | '#00BCD7'];
44 | this.dataLabel = {
45 | name: 'x', visible: true,
46 | position: 'Outside', connectorStyle: { length: '10%' },
47 | font: { color: 'Black', size: '14px', fontFamily: 'Roboto' }
48 | };
49 | this.getTotalExpense();
50 | this.animation = { enable: false };
51 | }
52 |
53 | public ngAfterViewInit(): void {
54 | this.handleDataLabel();
55 | }
56 |
57 | @HostListener('window:resize', ['$event'])
58 | onResize(event: any): void {
59 | /** Pie chart label disable at mobile mode handle at here */
60 | this.handleDataLabel();
61 | }
62 |
63 | public handleDataLabel(): void {
64 | if (Browser.isDevice || window.innerWidth < 400) {
65 | this.pie.series[0].dataLabel.visible = false;
66 | } else {
67 | this.pie.series[0].dataLabel.visible = true;
68 | }
69 | }
70 |
71 | /** Sets the pie chart's font size based on its size */
72 | public getFontSize(width: number): string {
73 | if (width > 300) {
74 | return '13px';
75 | } else if (width > 250) {
76 | return '8px';
77 | } else {
78 | return '6px';
79 | }
80 | }
81 |
82 | public onChartLoaded(args: IAccLoadedEventArgs): void {
83 | this.createLegendData('pie');
84 | this.enableLegend = true;
85 | }
86 |
87 | public onTextRender(args: IAccTextRenderEventArgs): void {
88 | args.series.dataLabel.font.size = this.getFontSize(this.pie.initialClipRect.width);
89 | this.pie.animateSeries = true;
90 | if (args.text.indexOf('Others') > -1) {
91 | args.text = 'Others';
92 | }
93 | }
94 |
95 | public onAnimateCompleted(args: IAccAnimationCompleteEventArgs): void {
96 | let element: HTMLElement = document.getElementById('total-expense_datalabel_Series_0');
97 | if (!isNOU(element)) { element.style.visibility = 'visible'; }
98 | }
99 |
100 | public getTotalExpense(): void {
101 | this.tempData = this.app.dataSource;
102 | this.expTotal = 0;
103 | this.category = [];
104 | this.legendData = [];
105 | let renderingData: { x: string; y: number; text: string; }[] = [];
106 |
107 | /** Extracts the category based data from the whole expense data */
108 | this.tempData.forEach((item: IExpenseData) => {
109 | if (item.TransactionType === 'Expense' && this.app.startDate.valueOf() <= item.DateTime.valueOf()
110 | && this.app.endDate.valueOf() >= item.DateTime.valueOf()) {
111 | this.expTotal += Number(item.Amount);
112 | this.legendData.push(item);
113 | if (this.category.indexOf(item.Category) < 0) {
114 | this.category.push(item.Category);
115 | }
116 | }
117 | });
118 |
119 | /** From the category data, percentage calculation for legend grid */
120 | this.category.forEach((str: string) => {
121 | let total: number = 0;
122 | this.legendData.forEach((item: IExpenseData) => {
123 | if (str === item.Category) {
124 | total += Number(item.Amount);
125 | }
126 | });
127 | let percent: string = ((total / this.expTotal) * 100).toFixed(2) + '%';
128 | renderingData.push({ x: str, y: total, text: percent });
129 | });
130 |
131 | /** Generates the pie chart data (pieRenderingData) */
132 | this.pieRenderingData = new DataManager(JSON.parse(JSON.stringify(renderingData)))
133 | .executeLocal((new Query().sortByDesc('y')));
134 | if (this.pieRenderingData.length > 10) {
135 | let temp: { x: string; y: number; text: string; } = <{ x: string; y: number; text: string; }>
136 | new DataManager(JSON.parse(JSON.stringify(renderingData))).executeLocal((new Query()
137 | .sortByDesc('y').range(0, 9)))[8];
138 | this.groupValue = (temp.y - 1).toString();
139 | this.hiGridData = new DataManager(JSON.parse(JSON.stringify(renderingData)))
140 | .executeLocal((new Query().sortByDesc('y').skip(9)));
141 | } else {
142 | this.groupValue = null;
143 | }
144 | }
145 |
146 | public createLegendData(initiate: string): void {
147 | if (initiate === 'pieUpdate' || this.pieLegendData.length === 0) {
148 | this.pieLegendData = [];
149 | this.pieLegendData = this.pie.visibleSeries[0].points;
150 | }
151 | this.pie.legendSettings.visible = false;
152 | /** Generates the legend grid data (pieRenderData) */
153 | this.pieRenderData = [];
154 | for (let i: number = 0; i < this.pieLegendData.length; i++) {
155 | let data: { [k: string]: any } = this.pieLegendData[i];
156 | if (data.text.indexOf('Others') > -1) {
157 | data.x = ((data.y / this.expTotal) * 100).toFixed(2).toString() + '%';
158 | }
159 | this.pieRenderData.push(data);
160 | }
161 | }
162 |
163 | public onGridDataBound(args: Object): void {
164 | //this.pie.refresh();
165 | //this.lineChart.refresh();
166 | //this.columnChart.refresh();
167 | this.showWaitingPopup = false;
168 | }
169 |
170 | public onGridLoad(args: any): void {
171 | /** While the legend grid loads, it gets the data from pie chart and process to this */
172 | this.createLegendData('pie');
173 | this.showWaitingPopup = true;
174 | }
175 |
176 | public refreshPieChart(): void {
177 | this.getTotalExpense();
178 | this.createLegendData('pieUpdate');
179 | this.lGrid.refresh();
180 | }
181 |
182 | public updatePieChart(): void {
183 | let pieContainerObj: HTMLElement = document.getElementById('totalExpense');
184 | if (!isNOU(pieContainerObj) && pieContainerObj.offsetWidth < 480) {
185 | this.disableChartLabel();
186 | } else if (!isNOU(pieContainerObj) && pieContainerObj.offsetWidth > 480) {
187 | this.enableChartLabel();
188 | }
189 | }
190 | public disableChartLabel(): void {
191 | this.pie.series[0].dataLabel.visible = false;
192 | this.pie.refresh();
193 | }
194 | public enableChartLabel(): void {
195 | this.pie.series[0].dataLabel.visible = true;
196 | this.pie.refresh();
197 | }
198 | }
199 |
200 | export interface IExpenseData {
201 | Amount: number;
202 | Category: string;
203 | DateTime: Date;
204 | Description: string;
205 | PaymentMode: string;
206 | TransactionType: string;
207 | UniqueId: string;
208 | }
--------------------------------------------------------------------------------
/src/app/dashboard/recent-exp-grid/recent-exp-grid.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{data.DateTime | date:'M/d/yyyy'}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
{{data.Category}}
15 |
16 |
17 |
20 |
21 |
{{data.Category}}
22 |
{{data.Description}}
23 |
24 |
25 |
26 |
29 |
30 |
{{data.Category}}
31 |
{{data.Description}}
32 |
{{data.PaymentMode}}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | {{data.Amount | currency:'USD'}}
44 |
45 |
46 |
47 |
48 | {{data.Amount | currency:'USD'}}
49 |
50 |
{{data.DateTime | date:'M/d/yyyy'}}
51 |
52 |
53 |
54 | {{data.Amount | currency:'USD'}}
55 |
56 |
{{data.DateTime | date:'M/d/yyyy'}}
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/app/dashboard/recent-exp-grid/recent-exp-grid.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit } from '@angular/core';
2 |
3 | import { Query, Predicate } from '@syncfusion/ej2-data';
4 |
5 | import { AppComponent } from '../../app.component';
6 |
7 | @Component({
8 | selector: 'recent-exp-grid',
9 | templateUrl: 'recent-exp-grid.component.html',
10 | encapsulation: ViewEncapsulation.None
11 | })
12 | export class RecentExpGridComponent implements OnInit {
13 | public query: Query;
14 | public gridToolbar: Object[];
15 | public predicate: Predicate;
16 | public predicateEnd: Predicate;
17 | public predicateStart: Predicate;
18 |
19 | constructor(public app: AppComponent) {}
20 |
21 | public ngOnInit(): void {
22 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', this.app.startDate);
23 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', this.app.endDate);
24 | this.predicate = this.predicateStart.and(this.predicateEnd);
25 |
26 | /** Query to takes last 5 lows to show the recent records only */
27 | this.query = new Query().where(this.predicate).sortByDesc('DateTime').take(5);
28 | this.gridToolbar = [{ text: 'Recent Transactions' }];
29 | }
30 | }
--------------------------------------------------------------------------------
/src/app/expense/content/content.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{transactionTitle}}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
{{data.Category}}
31 |
32 |
33 |
36 |
37 |
{{data.Category}}
38 |
{{data.Description}}
39 |
40 |
41 |
42 |
45 |
46 |
{{data.Category}}
47 |
{{data.Description}}
48 |
{{data.PaymentMode}}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {{data.Amount | currency:'USD'}}
63 |
64 |
65 |
66 |
67 |
68 |
69 | {{data.Amount | currency:'USD'}}
70 |
71 |
{{data.DateTime | date:'M/d/yyyy'}}
72 |
73 |
74 |
75 |
76 |
77 | {{data.Amount | currency:'USD'}}
78 |
79 |
{{data.DateTime | date:'M/d/yyyy'}}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/app/expense/content/content.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit, ElementRef, ViewChild } from '@angular/core';
2 |
3 | import { KeyboardEventArgs } from '@syncfusion/ej2-base';
4 | import { Query, DataManager, Predicate } from '@syncfusion/ej2-data';
5 | import { Input } from '@syncfusion/ej2-inputs';
6 | import { GridComponent, RowSelectEventArgs, RowDeselectEventArgs, CheckBoxChangeEventArgs,
7 | PageService, EditService, CommandColumnService, ToolbarService, ContextMenuService,
8 | ResizeService } from '@syncfusion/ej2-angular-grids';
9 |
10 | import { AppComponent } from '../../app.component';
11 | import { MenuComponent } from '../../menu/menu.component';
12 | import { DialogsComponent } from '../dialogs/dialogs.component';
13 |
14 | import { expenseData, categoryIncomeData, categoryExpenseData } from '../../common/common.data';
15 |
16 | @Component({
17 | selector: 'content-section',
18 | templateUrl: 'content.component.html',
19 | encapsulation: ViewEncapsulation.None,
20 | providers: [DialogsComponent, AppComponent, PageService, EditService, CommandColumnService, ToolbarService, ContextMenuService, ResizeService],
21 | })
22 | export class ContentComponent implements OnInit {
23 | @ViewChild('transactGrid') grid: GridComponent;
24 |
25 | public query: Query;
26 | public dlgCompObj: any;
27 | public filterCompObj: any;
28 | public predicate: Predicate;
29 | public dataSource: Object[];
30 | public pageSettings: Object;
31 | public editSettings: Object;
32 | public validateRule: Object;
33 | public toolbarValue: Object[];
34 | public predicateEnd: Predicate;
35 | public transactionTitle: string;
36 | public predicateStart: Predicate;
37 | public searchInput: HTMLInputElement;
38 | public clearIcon: HTMLElement;
39 |
40 | constructor(
41 | public app: AppComponent,
42 | public eleRef: ElementRef,
43 | public menu: MenuComponent) {}
44 |
45 | public ngOnInit(): void {
46 | this.transactionTitle = 'All Transactions';
47 |
48 | /** Configurations for the Expense Grid component */
49 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', this.app.startDate);
50 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', this.app.endDate);
51 | this.predicate = this.predicateStart.and(this.predicateEnd);
52 | this.toolbarValue = ['Edit', 'Delete'];
53 | this.query = new Query().where(this.predicate).sortByDesc('DateTime');
54 | this.pageSettings = { pageSize: 11 };
55 | this.validateRule = { required: true };
56 | this.editSettings = { allowEditing: true };
57 | }
58 |
59 | public ngAfterViewInit(): void {
60 | this.searchInput = this.eleRef.nativeElement.querySelector('#txt');
61 | Input.createInput({
62 | element: this.searchInput,
63 | properties: {
64 | showClearButton: true
65 | }
66 | });
67 | this.clearIcon = this.eleRef.nativeElement.querySelector('.e-clear-icon');
68 | this.clearIcon.onmousedown = () => {
69 | this.searchInput.value = '';
70 | };
71 | }
72 |
73 | public onGridCreated(): void {
74 | /** Edit and Delete toolbar items customization on the grid's created event */
75 | let ele: any = this.eleRef.nativeElement.querySelector('#grid_edit');
76 | let el: any = this.eleRef.nativeElement.querySelector('#grid_delete');
77 | if (ele) {
78 | ele.addEventListener('click', this.showEditTransactDialog.bind(this));
79 | }
80 | if (el) {
81 | el.addEventListener('click', this.showDeleteDialog.bind(this));
82 | }
83 | }
84 |
85 | public onGridCellSaved(args: any): void {
86 | new DataManager( this.app.dataSource).update('UniqueId', args.rowData);
87 | }
88 |
89 | public onGridRowSelected(args: RowSelectEventArgs): void {
90 | this.handleToolbarVisibility();
91 | }
92 | public onGridRowDeselected(args: RowDeselectEventArgs): void {
93 | this.handleToolbarVisibility();
94 | }
95 |
96 | public showAddTransactDialog(): void {
97 | this.dlgCompObj.showAddDialog();
98 | }
99 |
100 | public showDeleteDialog(): void {
101 | this.dlgCompObj.showAlertDialog();
102 | }
103 |
104 | public showEditTransactDialog(): void {
105 | this.dlgCompObj.showEditDialog();
106 | setTimeout(() => {
107 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_delete').parentElement, true);
108 | }, 0);
109 | }
110 |
111 | public showFilterNavigation(): void {
112 | this.menu.toggleFilterMenu();
113 | }
114 |
115 | /** Performs search operation when press Enter key */
116 | public onInputKeyUpSearch(args: KeyboardEventArgs): void {
117 | if (args.keyCode === 13) {
118 | this.grid.search(this.searchInput.value);
119 | }
120 | }
121 |
122 | /** Disables edit toolbar item in the Expense Grid on the initial load */
123 | public onGridActionComplete(e: any): void {
124 | setTimeout(() => {
125 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_edit').parentElement, false);
126 | }, 0);
127 | }
128 |
129 | /** Prevents the edit operation of Grid, since we handled the custom dialog for the edit operation */
130 | public onEditBegin(e: any): void {
131 | if (e.requestType === 'beginEdit') {
132 | e.cancel = true;
133 | }
134 | }
135 |
136 | /** Performs search operation in the Expense Grid */
137 | public onSearchClicked(): void {
138 | this.grid.search(this.searchInput.value);
139 | }
140 |
141 | /** Based on the selected rows from the Grid, updates the visibility of the toolbar items (Edit, Delete) */
142 | public handleToolbarVisibility(): void {
143 | if (this.grid.getSelectedRowIndexes().length > 1) {
144 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_edit').parentElement, false);
145 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_delete').parentElement, true);
146 | } else if (this.grid.getSelectedRowIndexes().length === 0) {
147 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_edit').parentElement, false);
148 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_delete').parentElement, false);
149 | } else if (this.grid.getSelectedRowIndexes().length === 1) {
150 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_edit').parentElement, true);
151 | this.grid.toolbarModule.toolbar.enableItems(document.getElementById('grid_delete').parentElement, true);
152 | }
153 | }
154 | }
--------------------------------------------------------------------------------
/src/app/expense/dialogs/dialogs.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Are you sure you want to delete the selected transaction(s)?
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
28 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/app/expense/dialogs/dialogs.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, ViewChild, OnInit, ElementRef } from '@angular/core';
2 |
3 | import { DialogComponent } from '@syncfusion/ej2-angular-popups';
4 | import { isNullOrUndefined as isNOU } from '@syncfusion/ej2-base';
5 | import { NumericTextBoxComponent } from '@syncfusion/ej2-angular-inputs';
6 | import { Query, DataManager, Predicate } from '@syncfusion/ej2-data';
7 | import { DropDownListComponent } from '@syncfusion/ej2-angular-dropdowns';
8 | import { ChangeEventArgs, RadioButtonComponent } from '@syncfusion/ej2-angular-buttons';
9 | import { DatePickerComponent, TimePickerComponent } from '@syncfusion/ej2-angular-calendars';
10 |
11 | import { AppComponent } from '../../app.component';
12 | import { CardsComponent } from '../../dashboard/cards/cards.component';
13 |
14 | import { categoryIncomeData, categoryExpenseData } from '../../common/common.data';
15 |
16 | @Component({
17 | selector: 'dialog-section',
18 | templateUrl: 'dialogs.component.html',
19 | encapsulation: ViewEncapsulation.None,
20 | providers: [ CardsComponent]
21 | })
22 | export class DialogsComponent implements OnInit {
23 | @ViewChild('dialog') dialog: DialogComponent;
24 | @ViewChild('confirmDialog') alertDialog: DialogComponent;
25 | @ViewChild('dlgAmount') dlgAmount: NumericTextBoxComponent;
26 | @ViewChild('dlgDropDown') dlgDropDown: DropDownListComponent;
27 | @ViewChild('dlgCashRadio') dlgCashRadio: RadioButtonComponent;
28 | @ViewChild('dlgDatePicker') dlgDatePicker: DatePickerComponent;
29 | @ViewChild('dlgTimePicker') dlgTimePicker: TimePickerComponent;
30 | @ViewChild('dlgDebitRadio') dlgDebitRadio: RadioButtonComponent;
31 | @ViewChild('dlgCreditRadio') dlgCreditRadio: RadioButtonComponent;
32 | @ViewChild('dlgIncomeRadio') dlgIncomeRadio: RadioButtonComponent;
33 | @ViewChild('dlgExpenseRadio') dlgExpenseRadio: RadioButtonComponent;
34 |
35 | public dateValue: Date;
36 | public cntCompObj: any;
37 | public isModal: boolean;
38 | public proxy: any = this;
39 | public predicate: Predicate;
40 | public dlgTarget: HTMLElement;
41 | public dropDownFields: Object;
42 | public predicateEnd: Predicate;
43 | public addDlgButtons: Object[];
44 | public editDlgButtons: Object[];
45 | public enableCloseIcon: boolean;
46 | public predicateStart: Predicate;
47 | public animationSettings: Object;
48 | public deleteDlgButtons: Object[];
49 | public enableCloseOnEscape: boolean;
50 | public categoryDataSource: Object[];
51 | public description: HTMLInputElement;
52 |
53 | constructor(public app: AppComponent, public eleRef: ElementRef, public cards: CardsComponent) {
54 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', this.app.startDate);
55 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', this.app.endDate);
56 | this.predicate = this.predicateStart.and(this.predicateEnd);
57 | this.isModal = true;
58 | this.dlgTarget = document.body;
59 | this.enableCloseIcon = true;
60 | this.enableCloseOnEscape = false;
61 | this.animationSettings = { effect: 'None' };
62 |
63 | /** Functionalities for the buttons of "Add Dialog" window */
64 | this.addDlgButtons = [{
65 | click: (() => {
66 | let newExpense: IExpenseData = {
67 | 'UniqueId': 'T' + ('' + (+new Date())).substring(5, 10),
68 | 'DateTime': new Date(this.dlgDatePicker.value.setHours(this.dlgTimePicker.value.getHours())),
69 | 'Category': this.dlgDropDown.value,
70 | 'PaymentMode': (this.dlgCashRadio.checked && this.dlgCashRadio.label) ||
71 | (this.dlgCreditRadio.checked && this.dlgCreditRadio.label) ||
72 | (this.dlgDebitRadio.checked && this.dlgDebitRadio.label),
73 | 'TransactionType': (this.dlgIncomeRadio.checked && this.dlgIncomeRadio.label) ||
74 | (this.dlgExpenseRadio.checked && this.dlgExpenseRadio.label),
75 | 'Description': this.description.value,
76 | 'Amount': this.dlgAmount.value
77 | };
78 | new DataManager(this.app.dataSource).insert(newExpense);
79 | new DataManager(this.app.dataSource).update('UniqueId', {
80 | UniqueId: newExpense.UniqueId,
81 | 'DateTime': (this.dlgDatePicker.value),
82 | 'Category': newExpense.Category,
83 | 'PaymentMode': newExpense.PaymentMode,
84 | 'TransactionType': newExpense.TransactionType,
85 | 'Description': newExpense.Description,
86 | 'Amount': newExpense.Amount
87 | });
88 | this.cntCompObj.grid.setProperties({
89 | dataSource: this.app.dataSource,
90 | query: new Query().where(this.predicate).sortByDesc('DateTime')
91 | });
92 | this.cntCompObj.grid.refresh();
93 | this.cards.updateCardValues();
94 | this.dialog.hide();
95 | }),
96 | buttonModel: { content: 'Add', cssClass: 'e-info e-add', isPrimary: true }
97 | }, {
98 | click: (() => {
99 | this.dialog.hide();
100 | }),
101 | buttonModel: { cssClass: 'e-outline e-cancel', content: 'Cancel' }
102 | }];
103 |
104 | /** Functionalities for the buttons of "Delete Dialog" window */
105 | this.deleteDlgButtons = [{
106 | click: (() => {
107 | let selectedRecords: Object[] = this.cntCompObj.grid.getSelectedRecords();
108 | for (let i: number = 0; i < selectedRecords.length; i++) {
109 | new DataManager(this.app.dataSource).remove('UniqueId', selectedRecords[i]);
110 | }
111 | this.cntCompObj.grid.refresh();
112 | this.cards.updateCardValues();
113 | this.alertDialog.hide();
114 | }), buttonModel: { content: 'Yes', cssClass: 'e-ok e-flat', isPrimary: true }
115 | }, {
116 | click: (() => {
117 | this.alertDialog.hide();
118 | }), buttonModel: { cssClass: 'e-no e-flat', content: 'No' }
119 | }];
120 |
121 | /** Functionalities for the buttons of "Edit Dialog" window */
122 | this.editDlgButtons = [{
123 | click: (() => {
124 | let editRecord: IExpenseData = this.cntCompObj.grid.getSelectedRecords()[0];
125 | let newExpense: IExpenseData = {
126 | 'UniqueId': editRecord.UniqueId,
127 | 'DateTime': new Date(this.dlgDatePicker.value.setHours(this.dlgTimePicker.value.getHours())),
128 | 'Category': this.dlgDropDown.value,
129 | 'PaymentMode': (this.dlgCashRadio.checked && this.dlgCashRadio.label) ||
130 | (this.dlgCreditRadio.checked && this.dlgCreditRadio.label) ||
131 | (this.dlgDebitRadio.checked && this.dlgDebitRadio.label),
132 | 'TransactionType': (this.dlgIncomeRadio.checked && this.dlgIncomeRadio.label) ||
133 | (this.dlgExpenseRadio.checked && this.dlgExpenseRadio.label),
134 | 'Description': this.description.value,
135 | 'Amount': this.dlgAmount.value
136 | };
137 | new DataManager(this.app.dataSource).update('UniqueId', newExpense);
138 | this.cntCompObj.grid.refresh();
139 | this.cards.updateCardValues();
140 | this.dialog.hide();
141 | }),
142 | buttonModel: { content: 'Save', cssClass: 'e-info e-add', isPrimary: true }
143 | }, {
144 | click: (() => {
145 | this.dialog.hide();
146 | }), buttonModel: { cssClass: 'e-outline e-cancel', content: 'Cancel' }
147 | }];
148 | }
149 |
150 | public ngOnInit(): void {
151 | /** Configurations for the Category selection dropdown */
152 | this.categoryDataSource = categoryExpenseData;
153 | this.dropDownFields = { text: 'Category', iconCss: 'Class', value: 'Category' };
154 | }
155 |
156 | public ngAfterViewInit(): void {
157 | this.description = this.eleRef.nativeElement.querySelector('#description');
158 | }
159 |
160 | /** Shows the "Edit Dialog" window with the corresponding selected row configuration */
161 | public showEditDialog(): void {
162 | this.dialog.header = 'Edit Transaction';
163 | this.dialog.buttons = this.editDlgButtons;
164 | this.dialog.dataBind();
165 | let selectedRecord: IExpenseData = this.cntCompObj.grid.getSelectedRecords()[0];
166 | if (!isNOU(selectedRecord)) {
167 | if (selectedRecord.TransactionType === 'Income') {
168 | this.dlgIncomeRadio.checked = true;
169 | this.dlgDropDown.dataSource = categoryIncomeData;
170 | } else if (selectedRecord.TransactionType === 'Expense') {
171 | this.dlgExpenseRadio.checked = true;
172 | this.dlgDropDown.dataSource = categoryExpenseData;
173 | }
174 | this.dlgDropDown.refresh();
175 | this.dlgDatePicker.value = selectedRecord.DateTime;
176 | this.dlgTimePicker.value = selectedRecord.DateTime;
177 | if (selectedRecord.PaymentMode === 'Credit Card') {
178 | this.dlgCreditRadio.checked = true;
179 | } else if (selectedRecord.PaymentMode === 'Debit Card') {
180 | this.dlgDebitRadio.checked = true;
181 | } else if (selectedRecord.PaymentMode === 'Cash') {
182 | this.dlgCashRadio.checked = true;
183 | }
184 | this.description.value = selectedRecord.Description;
185 | this.dlgDropDown.text = selectedRecord.Category;
186 | this.dlgAmount.value = selectedRecord.Amount;
187 | this.dialog.show();
188 | }
189 | this.dialog.show();
190 | }
191 |
192 | public showAlertDialog(): void {
193 | this.alertDialog.buttons = this.deleteDlgButtons;
194 | this.alertDialog.dataBind();
195 | this.alertDialog.show();
196 | }
197 |
198 | public alertDialogOpen(): void {
199 | this.proxy.alertDialog.dlgContainer.style.zIndex = '1000000';
200 | }
201 |
202 | /** Shows the "Add Dialog" window with the default configuration */
203 | public showAddDialog(): void {
204 | this.dialog.header = 'New Transaction';
205 | this.dialog.buttons = this.addDlgButtons;
206 | this.dialog.dataBind();
207 | this.dlgAmount.value = 0;
208 | this.description.value = '';
209 | this.dlgExpenseRadio.checked = true;
210 | this.dlgDropDown.dataSource = categoryExpenseData;
211 | this.dlgDropDown.dataBind();
212 | this.dlgCashRadio.checked = true;
213 | this.dialog.show();
214 | }
215 |
216 | /** Toggles the body scroll when the Dialog opens and close */
217 | public dialogOpen(): void {
218 | this.proxy.dialog.dlgContainer.style.zIndex = '1000000';
219 | document.body.style.overflowY = 'hidden';
220 | }
221 | public dlgClose(): void {
222 | document.body.style.overflowY = 'auto';
223 | }
224 |
225 | public dlgOverlayClicked(): void {
226 | this.proxy.alertDialog.hide();
227 | this.proxy.dialog.hide();
228 | }
229 |
230 | /** Update of the dropdown datasource based on the "Income" and "Expense" type */
231 | public dlgTransactTypeChanged(args: ChangeEventArgs): void {
232 | let transactValue: any = (args.event.target).value;
233 | if (transactValue === 'Expense') {
234 | this.dlgDropDown.dataSource = categoryExpenseData;
235 | } else {
236 | this.dlgDropDown.dataSource = categoryIncomeData;
237 | }
238 | this.dlgDropDown.dataBind();
239 | }
240 | }
241 |
242 | export interface IExpenseData {
243 | Amount: number;
244 | Category: string;
245 | DateTime: Date;
246 | Description: string;
247 | PaymentMode: string;
248 | TransactionType: string;
249 | UniqueId: string;
250 | }
--------------------------------------------------------------------------------
/src/app/expense/expense.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/app/expense/expense.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, ViewChild, OnInit, HostListener } from '@angular/core';
2 |
3 | import { Browser } from '@syncfusion/ej2-base';
4 |
5 | import { MenuComponent } from '../menu/menu.component';
6 | import { FilterComponent } from './filter/filter.component';
7 | import { DialogsComponent } from './dialogs/dialogs.component';
8 | import { ContentComponent } from './content/content.component';
9 | import { CardsComponent } from '../dashboard/cards/cards.component';
10 |
11 | import { CommonService } from '../common/common.service';
12 |
13 | @Component({
14 | templateUrl: 'expense.component.html',
15 | encapsulation: ViewEncapsulation.None,
16 | providers: [CommonService, CardsComponent]
17 | })
18 | export class ExpenseComponent implements OnInit {
19 | @ViewChild('filterSection') filterObj: FilterComponent;
20 | @ViewChild('dialogSection') dialogObj: DialogsComponent;
21 | @ViewChild('contentSection') contentObj: ContentComponent;
22 |
23 | constructor(
24 | public common: CommonService,
25 | public cards: CardsComponent,
26 | public menu: MenuComponent
27 | ) {
28 | this.common.removeRootClass();
29 | this.common.addRootClass('expense-page');
30 | }
31 |
32 | public ngOnInit(): void {
33 | /** On initial load, update the sidebar selections and overlay */
34 | this.menu.removeToggleClass();
35 | this.menu.disableOverlay();
36 | this.cards.updateCardValues();
37 | }
38 |
39 | public ngAfterViewInit(): void {
40 | this.contentObj.filterCompObj = this.filterObj;
41 | this.filterObj.cntCompObj = this.contentObj;
42 | this.contentObj.dlgCompObj = this.dialogObj;
43 | this.dialogObj.cntCompObj = this.contentObj;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/app/expense/filter/filter.component.html:
--------------------------------------------------------------------------------
1 |
2 |
44 |
--------------------------------------------------------------------------------
/src/app/expense/filter/filter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, ViewChild, OnInit, ChangeDetectorRef } from '@angular/core';
2 |
3 | import { Query, Predicate } from '@syncfusion/ej2-data';
4 | import { isNullOrUndefined as isNOU } from '@syncfusion/ej2-base';
5 | import { CheckBoxComponent, ChangeEventArgs } from '@syncfusion/ej2-angular-buttons';
6 | import { DateRangePickerComponent, RangeEventArgs } from '@syncfusion/ej2-angular-calendars';
7 | import { MultiSelectComponent, SelectEventArgs, RemoveEventArgs } from '@syncfusion/ej2-angular-dropdowns';
8 |
9 | import { AppComponent } from '../../app.component';
10 |
11 | import { FilterService } from './filter.service';
12 |
13 | @Component({
14 | selector: 'filter-section',
15 | templateUrl: 'filter.component.html',
16 | encapsulation: ViewEncapsulation.None,
17 | providers: [FilterService, AppComponent]
18 | })
19 | export class FilterComponent implements OnInit {
20 | @ViewChild('filterCash') cashFilter: CheckBoxComponent;
21 | @ViewChild('filterDebit') debitFilter: CheckBoxComponent;
22 | @ViewChild('filterCredit') creditFilter: CheckBoxComponent;
23 | @ViewChild('filterIncome') incomeFilter: CheckBoxComponent;
24 | @ViewChild('filterExpense') expenseFilter: CheckBoxComponent;
25 | @ViewChild('filterMinAmount') minAmtFilter: CheckBoxComponent;
26 | @ViewChild('filterMaxAmount') maxAmtFilter: CheckBoxComponent;
27 | @ViewChild('filterMultiSelect') multiSelectFilter: MultiSelectComponent;
28 | @ViewChild('filterDateRange') dateRangeFilter: DateRangePickerComponent;
29 |
30 | public cntCompObj: any;
31 | public minValue: number;
32 | public maxValue: number;
33 | public predicate: Predicate;
34 | public predicateEnd: Predicate;
35 | public tempData: IExpenseData[];
36 | public filterCategory: string[];
37 | public cashPredicate: Predicate;
38 | public predicateStart: Predicate;
39 | public debitPredicate: Predicate;
40 | public minAmtPredicate: Predicate;
41 | public maxAmtPredicate: Predicate;
42 | public incomePredicate: Predicate;
43 | public creditPredicate: Predicate;
44 | public expensePredicate: Predicate;
45 | public categoryPredicate: Predicate;
46 | public categoryPredicates: Predicate;
47 |
48 | constructor(
49 | public app: AppComponent,
50 | public filter: FilterService,
51 | private chgRef: ChangeDetectorRef
52 | ) {
53 | this.filterCategory = [];
54 | }
55 |
56 | public ngOnInit(): void {
57 | this.minValue = 0;
58 | this.maxValue = 0;
59 | this.tempData = this.app.dataSource;
60 | this.getCategory(this.app.startDate, this.app.endDate);
61 | }
62 |
63 | /** Gets the available category in-between the start and end date, for category filter dropdown */
64 | public getCategory(start: Date, end: Date): void {
65 | this.filterCategory = [];
66 | this.tempData.forEach((item: any) => {
67 | if (start.valueOf() <= item.DateTime.valueOf() && end.valueOf() >= item.DateTime.valueOf()) {
68 | if (this.filterCategory.indexOf(item.Category) < 0) {
69 | this.filterCategory.push(item.Category);
70 | }
71 | }
72 | });
73 | }
74 |
75 | public numericTextBoxCreated(): void {
76 | let val: IMinMax = this.filter.minMaxAmount(this.dateRangeFilter.startDate, this.dateRangeFilter.endDate);
77 | this.minValue = val.minValue;
78 | this.maxValue = val.maxValue;
79 | this.chgRef.detectChanges();
80 | }
81 |
82 | /** Updates the Grid datasource based on the modified date range values */
83 | public dateRangeChanged(args: RangeEventArgs): void {
84 | this.app.startDate = args.startDate;
85 | this.app.endDate = args.endDate;
86 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', this.app.startDate);
87 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', this.app.endDate);
88 | this.predicate = this.predicateStart.and(this.predicateEnd);
89 | this.updateGrid(this.app.startDate, this.app.endDate, 'dateChange');
90 | }
91 |
92 | /** Filters the datasource based on amount */
93 | public amountChanged(): void {
94 | this.updateGrid(this.dateRangeFilter.startDate, this.dateRangeFilter.endDate, '');
95 | }
96 |
97 | /** Filters the datasource based on Cashflow and Payment modes */
98 | public checkBoxStateChanged(args: ChangeEventArgs): void {
99 | this.updateGrid(this.dateRangeFilter.startDate, this.dateRangeFilter.endDate, '');
100 | }
101 |
102 | /** Filters the datasource when category selected or deselected, from Multiselect component */
103 | public categorySelected(args: SelectEventArgs): void {
104 | setTimeout(() => {
105 | this.updateGrid(this.dateRangeFilter.startDate, this.dateRangeFilter.endDate, '');
106 | }, 10);
107 | }
108 | public categoryRemoved(args: RemoveEventArgs): void {
109 | this.updateGrid(this.dateRangeFilter.startDate, this.dateRangeFilter.endDate, '');
110 | }
111 |
112 | /** Updates the Grid based on the filtered data source */
113 | public updateGrid(start: Date, end: Date, updater: string): void {
114 | if (end instanceof Date) {
115 | end.setHours(23);
116 | end.setMinutes(59);
117 | }
118 | this.predicateStart = new Predicate('DateTime', 'greaterthanorequal', start);
119 | this.predicateEnd = new Predicate('DateTime', 'lessthanorequal', end);
120 | this.predicate = this.predicateStart.and(this.predicateEnd);
121 | let val: IMinMax = this.filter.minMaxAmount(start, end);
122 | this.minValue = val.minValue;
123 | this.maxValue = val.maxValue;
124 | this.minAmtPredicate = new Predicate('Amount', 'greaterthanorequal', this.minAmtFilter.value);
125 | this.maxAmtPredicate = new Predicate('Amount', 'lessthanorequal', this.maxAmtFilter.value);
126 | this.predicate = this.predicate.and(this.minAmtPredicate).and(this.maxAmtPredicate);
127 | if (this.incomeFilter.checked || this.expenseFilter.checked) {
128 | if (this.incomeFilter.checked) {
129 | this.incomePredicate = new Predicate('TransactionType', 'equal', 'Income');
130 | }
131 | if (this.expenseFilter.checked) {
132 | this.expensePredicate = new Predicate('TransactionType', 'equal', 'Expense');
133 | }
134 | if (this.expenseFilter.checked && this.incomeFilter.checked) {
135 | this.incomePredicate = this.incomePredicate.or(this.expensePredicate);
136 | this.predicate = this.predicate.and(this.incomePredicate);
137 | } else if (this.incomeFilter.checked) {
138 | this.predicate = this.predicate.and(this.incomePredicate);
139 | } else if (this.expenseFilter.checked) {
140 | this.predicate = this.predicate.and(this.expensePredicate);
141 | }
142 | }
143 | if (this.cashFilter.checked || this.debitFilter.checked || this.creditFilter.checked) {
144 | if (this.cashFilter.checked) {
145 | this.cashPredicate = new Predicate('PaymentMode', 'equal', 'Cash');
146 | }
147 | if (this.creditFilter.checked) {
148 | this.creditPredicate = new Predicate('PaymentMode', 'equal', 'Credit Card');
149 | }
150 | if (this.debitFilter.checked) {
151 | this.debitPredicate = new Predicate('PaymentMode', 'equal', 'Debit Card');
152 | }
153 | if (this.cashFilter.checked && this.creditFilter.checked && this.debitFilter.checked) {
154 | this.incomePredicate = this.creditPredicate.or(this.debitPredicate).or(this.cashPredicate);
155 | this.predicate = this.predicate.and(this.incomePredicate);
156 | } else if (this.cashFilter.checked && this.creditFilter.checked) {
157 | this.incomePredicate = this.cashPredicate.or(this.creditPredicate);
158 | this.predicate = this.predicate.and(this.incomePredicate);
159 | } else if (this.cashFilter.checked && this.debitFilter.checked) {
160 | this.incomePredicate = this.cashPredicate.or(this.debitPredicate);
161 | this.predicate = this.predicate.and(this.incomePredicate);
162 | } else if (this.creditFilter.checked && this.debitFilter.checked) {
163 | this.incomePredicate = this.creditPredicate.or(this.debitPredicate);
164 | this.predicate = this.predicate.and(this.incomePredicate);
165 | } else if (this.cashFilter.checked) {
166 | this.predicate = this.predicate.and(this.cashPredicate);
167 | } else if (this.debitFilter.checked) {
168 | this.predicate = this.predicate.and(this.debitPredicate);
169 | } else if (this.creditFilter.checked) {
170 | this.predicate = this.predicate.and(this.creditPredicate);
171 | }
172 | }
173 | if (!isNOU(this.multiSelectFilter.value) && this.multiSelectFilter.value.length > 0) {
174 | let list: string[] = this.multiSelectFilter.value;
175 | for (let i: number = 0; i < list.length; i++) {
176 | this.categoryPredicate = new Predicate('Category', 'equal', list[i]);
177 | if (i === 0) {
178 | this.categoryPredicates = this.categoryPredicate;
179 | } else {
180 | this.categoryPredicates = this.categoryPredicates.or(this.categoryPredicate);
181 | }
182 | }
183 | this.predicate = this.predicate.and(this.categoryPredicates);
184 | }
185 | this.cntCompObj.grid.setProperties({
186 | dataSource: this.app.dataSource,
187 | query: new Query().where(this.predicate).sortByDesc('DateTime')
188 | });
189 | this.cntCompObj.grid.refresh();
190 | this.getCategory(start, end);
191 | this.multiSelectFilter.dataSource = this.filterCategory;
192 | this.multiSelectFilter.dataBind();
193 | }
194 | }
195 |
196 | export interface IMinMax {
197 | minValue: number;
198 | maxValue: number;
199 | }
200 |
201 | export interface IExpenseData {
202 | Amount: number;
203 | Category: string;
204 | DateTime: Date;
205 | Description: string;
206 | PaymentMode: string;
207 | TransactionType: string;
208 | UniqueId: string;
209 | }
--------------------------------------------------------------------------------
/src/app/expense/filter/filter.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, ViewChild } from '@angular/core';
2 |
3 | import { Query, DataManager, Predicate } from '@syncfusion/ej2-data';
4 |
5 | import { AppComponent } from '../../app.component';
6 |
7 | @Injectable()
8 | export class FilterService {
9 | public predicate: Predicate;
10 | public predicateEnd: Predicate;
11 | public predicateStart: Predicate;
12 |
13 | constructor(public app: AppComponent) {}
14 |
15 | /** Gets the minimum and maximum amount from the datasource */
16 | public minMaxAmount(start: Date, end: Date): Object {
17 | let predicateStart: Predicate = new Predicate('DateTime', 'greaterthanorequal', start);
18 | let predicateEnd: Predicate = new Predicate('DateTime', 'lessthanorequal', end);
19 | let minAmount: any = new DataManager(this.app.dataSource).executeLocal((new Query()
20 | .where((predicateStart.and(predicateEnd))))
21 | .requiresCount().aggregate('min', 'Amount'));
22 | let maxAmount: any = new DataManager(this.app.dataSource).executeLocal((new Query()
23 | .where((predicateStart.and(predicateEnd))))
24 | .requiresCount().aggregate('max', 'Amount'));
25 | return {
26 | minValue: minAmount.aggregates['Amount - min'],
27 | maxValue: maxAmount.aggregates['Amount - max']
28 | };
29 | }
30 | }
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowser } from '@angular/platform-browser';
2 | import { AppModuleNgFactory } from './app.module.ngfactory';
3 | platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
--------------------------------------------------------------------------------
/src/app/menu/menu.component.html:
--------------------------------------------------------------------------------
1 |
10 |
36 |
41 |
--------------------------------------------------------------------------------
/src/app/menu/menu.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Directive, ElementRef } from '@angular/core';
2 |
3 | import { Browser, rippleEffect, isNullOrUndefined as isNOU, enableRipple } from '@syncfusion/ej2-base';
4 |
5 | import { userInfo } from '../common/common.data';
6 | enableRipple(true);
7 |
8 | @Component({
9 | selector: 'ng-app',
10 | templateUrl: 'menu.component.html'
11 | })
12 |
13 | export class MenuComponent {
14 | public menu: HTMLElement;
15 | public userName: string;
16 | public filterMenu: HTMLElement;
17 | public overlay: HTMLElement;
18 |
19 | constructor(public eleRef: ElementRef) {
20 | /** Loads the user data in the profile from the sidebar */
21 | this.userName = userInfo.FullName;
22 | rippleEffect(document.body, { selector: '.ripple-element', rippleFlag: true });
23 | }
24 |
25 | public ngAfterViewInit(): void {
26 | /** Holds the sidebar elements for later use */
27 | this.menu = this.eleRef.nativeElement.querySelector('#sidebar-wrapper');
28 | this.overlay = this.eleRef.nativeElement.querySelector('#overlay');
29 | }
30 |
31 | /** Toggles the sidebar open and close actions - for small resoultion */
32 | public toggleMenu(): void {
33 | if (this.menu.classList.contains('open')) {
34 | this.removeToggleClass();
35 | this.menu.classList.add('close');
36 | this.disableOverlay();
37 | } else if (this.menu.classList.contains('close')) {
38 | this.removeToggleClass();
39 | this.menu.classList.add('open');
40 | this.enableOverlay();
41 | } else {
42 | this.menu.classList.add('open');
43 | this.enableOverlay();
44 | }
45 | }
46 |
47 | public removeToggleClass(): void {
48 | this.menu.classList.remove('open');
49 | this.menu.classList.remove('close');
50 | }
51 |
52 | public enableOverlay(): void {
53 | this.overlay.classList.add('dialog');
54 | this.overlay.style.background = '#383838';
55 | }
56 |
57 | public disableOverlay(): void {
58 | this.overlay.classList.remove('dialog');
59 | this.overlay.style.background = 'none';
60 | }
61 |
62 | public handleOverlay(): void {
63 | this.disableOverlay();
64 | this.removeToggleClass();
65 | this.removeFilterToggleClass();
66 | }
67 |
68 | public removeFilterToggleClass(): void {
69 | this.menu.style.zIndex = '100001';
70 | this.filterMenu = this.eleRef.nativeElement.querySelector('.sidebar-wrapper-filter');
71 | if (!isNOU(this.filterMenu)) {
72 | this.filterMenu.classList.remove('filter-open');
73 | this.filterMenu.classList.remove('filter-close');
74 | }
75 | }
76 |
77 | /** Toggles the filter bar open and close actions */
78 | public toggleFilterMenu(): void {
79 | this.menu.style.zIndex = '10000';
80 | this.filterMenu = this.eleRef.nativeElement.querySelector('.sidebar-wrapper-filter');
81 | if (this.filterMenu.classList.contains('filter-open')) {
82 | this.filterMenu.classList.remove('filter-open');
83 | this.filterMenu.classList.add('filter-close');
84 | this.disableOverlay();
85 | } else if (this.filterMenu.classList.contains('filter-close')) {
86 | this.filterMenu.classList.remove('filter-close');
87 | this.filterMenu.classList.add('filter-open');
88 | this.enableOverlay();
89 | } else {
90 | this.filterMenu.classList.add('filter-open');
91 | this.enableOverlay();
92 | }
93 | }
94 |
95 | public onNavigationClick(args: MouseEvent): void {
96 | if ((args.target as HTMLElement).nodeName === 'A') {
97 | this.handleOverlay();
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/src/assets/definition/material.scss:
--------------------------------------------------------------------------------
1 | $accent: #ff4081;
2 | $accent-font: #fff;
3 |
4 | $primary: #3f51b5;
5 | $primary-50: lighten($primary, 38%);
6 | $primary-100: lighten($primary, 31%);
7 | $primary-200: lighten($primary, 19%);
8 | $primary-300: lighten($primary, 8%);
9 | $primary-font: #fff;
10 | $primary-50-font: #000;
11 | $primary-100-font: #000;
12 | $primary-200-font: #000;
13 | $primary-300-font: #fff;
14 | $grey-white: #fff;
15 | $grey-black: #000;
16 | $grey-50: #fafafa;
17 | $grey-100: #f5f5f5;
18 | $grey-200: #eee;
19 | $grey-300: #e0e0e0;
20 | $grey-400: #bdbdbd;
21 | $grey-500: #9e9e9e;
22 | $grey-600: #757575;
23 | $grey-700: #616161;
24 | $grey-800: #424242;
25 | $grey-900: #212121;
26 | $grey-dark: #303030;
27 | $grey-light-font: #000;
28 | $grey-dark-font: #fff;
29 | $base-font: #000;
30 | $error-font: #f44336;
31 |
--------------------------------------------------------------------------------
/src/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/favicon.ico
--------------------------------------------------------------------------------
/src/assets/images/About.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/AvailableCash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/Home.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/OverallTransactions.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/Profile-img-Desktop:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/Profile-img-Desktop
--------------------------------------------------------------------------------
/src/assets/images/Profile-img-Mobile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/Profile-img-Mobile
--------------------------------------------------------------------------------
/src/assets/images/Search.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/TotalExpenses.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/TotalIncome.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/Transactions.svg:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/src/assets/images/balance.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/src/assets/images/cash-wallet.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/images/category/bills.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/bills.png
--------------------------------------------------------------------------------
/src/assets/images/category/business.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/business.png
--------------------------------------------------------------------------------
/src/assets/images/category/clothing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/clothing.png
--------------------------------------------------------------------------------
/src/assets/images/category/education.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/education.png
--------------------------------------------------------------------------------
/src/assets/images/category/entertainment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/entertainment.png
--------------------------------------------------------------------------------
/src/assets/images/category/extra.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/extra.png
--------------------------------------------------------------------------------
/src/assets/images/category/food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/food.png
--------------------------------------------------------------------------------
/src/assets/images/category/health.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/health.png
--------------------------------------------------------------------------------
/src/assets/images/category/house.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/house.png
--------------------------------------------------------------------------------
/src/assets/images/category/insurance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/insurance.png
--------------------------------------------------------------------------------
/src/assets/images/category/interest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/interest.png
--------------------------------------------------------------------------------
/src/assets/images/category/miscellaneous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/miscellaneous.png
--------------------------------------------------------------------------------
/src/assets/images/category/personal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/personal.png
--------------------------------------------------------------------------------
/src/assets/images/category/rent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/rent.png
--------------------------------------------------------------------------------
/src/assets/images/category/salary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/salary.png
--------------------------------------------------------------------------------
/src/assets/images/category/shopping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/shopping.png
--------------------------------------------------------------------------------
/src/assets/images/category/tax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/tax.png
--------------------------------------------------------------------------------
/src/assets/images/category/transport.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/transport.png
--------------------------------------------------------------------------------
/src/assets/images/category/utilities.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/category/utilities.png
--------------------------------------------------------------------------------
/src/assets/images/exp-track.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/exp-track.png
--------------------------------------------------------------------------------
/src/assets/images/expense.svg:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/src/assets/images/fonts/Expense-Analysis-Sample.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/Expense-Analysis-Sample.eot
--------------------------------------------------------------------------------
/src/assets/images/fonts/Expense-Analysis-Sample.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/images/fonts/Expense-Analysis-Sample.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/Expense-Analysis-Sample.ttf
--------------------------------------------------------------------------------
/src/assets/images/fonts/Expense-Analysis-Sample.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/Expense-Analysis-Sample.woff
--------------------------------------------------------------------------------
/src/assets/images/fonts/controls.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/controls.eot
--------------------------------------------------------------------------------
/src/assets/images/fonts/controls.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/images/fonts/controls.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/controls.ttf
--------------------------------------------------------------------------------
/src/assets/images/fonts/controls.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/controls.woff
--------------------------------------------------------------------------------
/src/assets/images/fonts/icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/icons.eot
--------------------------------------------------------------------------------
/src/assets/images/fonts/icons.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/images/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/icons.ttf
--------------------------------------------------------------------------------
/src/assets/images/fonts/icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/fonts/icons.woff
--------------------------------------------------------------------------------
/src/assets/images/i.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/income.svg:
--------------------------------------------------------------------------------
1 |
40 |
--------------------------------------------------------------------------------
/src/assets/images/no-records.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncfusion/ej2-showcase-angular-expensetracker/e83ec6b422b78b4af7141fee40b0105f57443e77/src/assets/images/no-records.png
--------------------------------------------------------------------------------
/src/assets/images/t.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/images/title.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
81 |
--------------------------------------------------------------------------------
/src/assets/images/transaction.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/assets/styles.scss:
--------------------------------------------------------------------------------
1 | //sass-lint:disable-all
2 | @import 'definition/material.scss';
3 | @import 'ej2-base/styles/material-definition.scss';
4 | @import 'ej2-base/styles/all.scss';
5 | @import 'ej2-base/styles/definition/_material.scss';
6 | @import 'ej2-icons/styles/material.scss';
7 | $accent: #4273F9;
8 | $accent-font: #fff;
9 | @import 'ej2-buttons/styles/button/material-definition.scss';
10 | @import 'ej2-buttons/styles/button/all.scss';
11 | @import 'ej2-inputs/styles/input/material-definition.scss';
12 | @import 'ej2-inputs/styles/input/icons/material.scss';
13 | @import 'ej2-inputs/styles/input/all.scss';
14 | @import 'ej2-inputs/styles/numerictextbox/material-definition.scss';
15 | @import 'ej2-inputs/styles/numerictextbox/icons/material.scss';
16 | @import 'ej2-inputs/styles/numerictextbox/all.scss';
17 | @import 'ej2-calendars/styles/calendar/material-definition.scss';
18 | @import 'ej2-calendars/styles/calendar/icons/material.scss';
19 | @import 'ej2-calendars/styles/calendar/all.scss';
20 | @import 'ej2-buttons/styles/check-box/material-definition.scss';
21 | @import 'ej2-buttons/styles/check-box/icons/material.scss';
22 | @import 'ej2-buttons/styles/check-box/all.scss';
23 | @import 'ej2-navigations/styles/context-menu/material-definition.scss';
24 | @import 'ej2-navigations/styles/context-menu/icons/material.scss';
25 | @import 'ej2-navigations/styles/context-menu/all.scss';
26 | @import 'ej2-calendars/styles/datepicker/material-definition.scss';
27 | @import 'ej2-calendars/styles/datepicker/icons/material.scss';
28 | @import 'ej2-calendars/styles/datepicker/all.scss';
29 | @import 'ej2-calendars/styles/daterangepicker/material-definition.scss';
30 | @import 'ej2-calendars/styles/daterangepicker/icons/material.scss';
31 | @import 'ej2-calendars/styles/daterangepicker/all.scss';
32 | @import 'ej2-popups/styles/dialog/material-definition.scss';
33 | @import 'ej2-popups/styles/dialog/icons/material.scss';
34 | @import 'ej2-popups/styles/dialog/all.scss';
35 | @import 'ej2-dropdowns/styles/drop-down-base/material-definition.scss';
36 | @import 'ej2-dropdowns/styles/drop-down-base/all.scss';
37 | @import 'ej2-dropdowns/styles/drop-down-list/material-definition.scss';
38 | @import 'ej2-dropdowns/styles/drop-down-list/icons/material.scss';
39 | @import 'ej2-dropdowns/styles/drop-down-list/all.scss';
40 | @import 'ej2-navigations/styles/h-scroll/material-definition.scss';
41 | @import 'ej2-navigations/styles/h-scroll/icons/material.scss';
42 | @import 'ej2-navigations/styles/h-scroll/all.scss';
43 | @import 'ej2-lists/styles/list-view/material-definition.scss';
44 | @import 'ej2-lists/styles/list-view/icons/material.scss';
45 | @import 'ej2-lists/styles/list-view/all.scss';
46 | @import 'ej2-dropdowns/styles/multi-select/material-definition.scss';
47 | @import 'ej2-dropdowns/styles/multi-select/icons/material.scss';
48 | @import 'ej2-dropdowns/styles/multi-select/all.scss';
49 | @import 'ej2-popups/styles/popup/all.scss';
50 | @import 'ej2-buttons/styles/radio-button/material-definition.scss';
51 | @import 'ej2-buttons/styles/radio-button/all.scss';
52 | @import 'ej2-popups/styles/spinner/material-definition.scss';
53 | @import 'ej2-popups/styles/spinner/all.scss';
54 | @import 'ej2-calendars/styles/timepicker/material-definition.scss';
55 | @import 'ej2-calendars/styles/timepicker/icons/material.scss';
56 | @import 'ej2-calendars/styles/timepicker/all.scss';
57 | @import 'ej2-navigations/styles/toolbar/material-definition.scss';
58 | @import 'ej2-navigations/styles/toolbar/icons/material.scss';
59 | @import 'ej2-navigations/styles/toolbar/all.scss';
60 | @import 'ej2-popups/styles/tooltip/material-definition.scss';
61 | @import 'ej2-popups/styles/tooltip/icons/material.scss';
62 | @import 'ej2-popups/styles/tooltip/all.scss';
63 | @import 'ej2-grids/styles/grid/icons/material.scss';
64 | @import 'ej2-grids/styles/grid/material-definition.scss';
65 | @import 'ej2-grids/styles/grid/all.scss';
66 | @import 'ej2-grids/styles/pager/material-definition.scss';
67 | @import 'ej2-grids/styles/pager/icons/material.scss';
68 | @import 'ej2-grids/styles/pager/all.scss';
69 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `.angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 | Essential JS 2 for Angular - Expense Tracker
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.log(err));
13 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | //import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | @import "./assets/styles.css";
2 | @import "./assets/index.css";
3 |
--------------------------------------------------------------------------------
/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.base.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "downlevelIteration": true,
10 | "experimentalDecorators": true,
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "es2015",
14 | "module": "es6",
15 | "lib": [
16 | "es2015",
17 | "dom"
18 | ]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "module": "es2015",
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": false,
11 | "experimentalDecorators": true,
12 | "target": "es2015",
13 | "typeRoots": [
14 | "node_modules/@types"
15 | ],
16 | "lib": [
17 | "es2017",
18 | "dom"
19 | ]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.base.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rules": {
4 | "align": {
5 | "options": [
6 | "parameters",
7 | "statements"
8 | ]
9 | },
10 | "array-type": false,
11 | "arrow-return-shorthand": true,
12 | "curly": true,
13 | "deprecation": {
14 | "severity": "warning"
15 | },
16 | "component-class-suffix": true,
17 | "contextual-lifecycle": true,
18 | "directive-class-suffix": true,
19 | "directive-selector": [
20 | true,
21 | "attribute",
22 | "app",
23 | "camelCase"
24 | ],
25 | "component-selector": [
26 | true,
27 | "element",
28 | "app",
29 | "kebab-case"
30 | ],
31 | "eofline": true,
32 | "import-blacklist": [
33 | true,
34 | "rxjs/Rx"
35 | ],
36 | "import-spacing": true,
37 | "indent": {
38 | "options": [
39 | "spaces"
40 | ]
41 | },
42 | "max-classes-per-file": false,
43 | "max-line-length": [
44 | true,
45 | 140
46 | ],
47 | "member-ordering": [
48 | true,
49 | {
50 | "order": [
51 | "static-field",
52 | "instance-field",
53 | "static-method",
54 | "instance-method"
55 | ]
56 | }
57 | ],
58 | "no-console": [
59 | true,
60 | "debug",
61 | "info",
62 | "time",
63 | "timeEnd",
64 | "trace"
65 | ],
66 | "no-empty": false,
67 | "no-inferrable-types": [
68 | true,
69 | "ignore-params"
70 | ],
71 | "no-non-null-assertion": true,
72 | "no-redundant-jsdoc": true,
73 | "no-switch-case-fall-through": true,
74 | "no-var-requires": false,
75 | "object-literal-key-quotes": [
76 | true,
77 | "as-needed"
78 | ],
79 | "quotemark": [
80 | true,
81 | "single"
82 | ],
83 | "semicolon": {
84 | "options": [
85 | "always"
86 | ]
87 | },
88 | "space-before-function-paren": {
89 | "options": {
90 | "anonymous": "never",
91 | "asyncArrow": "always",
92 | "constructor": "never",
93 | "method": "never",
94 | "named": "never"
95 | }
96 | },
97 | "typedef": [
98 | true,
99 | "call-signature"
100 | ],
101 | "typedef-whitespace": {
102 | "options": [
103 | {
104 | "call-signature": "nospace",
105 | "index-signature": "nospace",
106 | "parameter": "nospace",
107 | "property-declaration": "nospace",
108 | "variable-declaration": "nospace"
109 | },
110 | {
111 | "call-signature": "onespace",
112 | "index-signature": "onespace",
113 | "parameter": "onespace",
114 | "property-declaration": "onespace",
115 | "variable-declaration": "onespace"
116 | }
117 | ]
118 | },
119 | "variable-name": {
120 | "options": [
121 | "ban-keywords",
122 | "check-format",
123 | "allow-pascal-case"
124 | ]
125 | },
126 | "whitespace": {
127 | "options": [
128 | "check-branch",
129 | "check-decl",
130 | "check-operator",
131 | "check-separator",
132 | "check-type",
133 | "check-typecast"
134 | ]
135 | },
136 | "no-conflicting-lifecycle": true,
137 | "no-host-metadata-property": true,
138 | "no-input-rename": true,
139 | "no-inputs-metadata-property": true,
140 | "no-output-native": true,
141 | "no-output-on-prefix": true,
142 | "no-output-rename": true,
143 | "no-outputs-metadata-property": true,
144 | "template-banana-in-box": true,
145 | "template-no-negated-async": true,
146 | "use-lifecycle-interface": true,
147 | "use-pipe-transform-interface": true
148 | },
149 | "rulesDirectory": [
150 | "codelyzer"
151 | ]
152 | }
--------------------------------------------------------------------------------