mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-22 10:17:07 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19fdbbdbcb | ||
|
|
8bbabd7437 | ||
|
|
5a9cd36282 | ||
|
|
297bb95a2e | ||
|
|
2511a03b66 | ||
|
|
76358f996e | ||
|
|
142fc982ca | ||
|
|
22d9279e3b | ||
|
|
a1bec98d44 | ||
|
|
e8449e340d | ||
|
|
4cb8009c69 | ||
|
|
7f357306eb | ||
|
|
06679343a4 | ||
|
|
f35d83567e | ||
|
|
c97fd77c13 | ||
|
|
62904cdb42 | ||
|
|
d9c36cad82 | ||
|
|
d2bfc152a0 | ||
|
|
f013b2b667 | ||
|
|
9fbcc20623 | ||
|
|
0fd8a75f7d | ||
|
|
99d9552813 | ||
|
|
3bca193bcc | ||
|
|
f73ff363a5 | ||
|
|
1bf689f154 | ||
|
|
3499d89098 | ||
|
|
685cd76da2 | ||
|
|
786180958d | ||
|
|
a2f72c92d5 | ||
|
|
6b368d2e79 | ||
|
|
47c2cc721e | ||
|
|
5574e3f729 | ||
|
|
1934bad3eb | ||
|
|
ee29f20304 | ||
|
|
93c2eab584 | ||
|
|
b0f45980be | ||
|
|
7b10b2ad86 | ||
|
|
3fc510469d | ||
|
|
5d56b3bcd6 | ||
|
|
aaa14eb1e9 | ||
|
|
f43608f93b | ||
|
|
9ecd921722 | ||
|
|
98e2ff0e1e | ||
|
|
b7cb09b087 | ||
|
|
fe8b44b14c | ||
|
|
ca8ed939ae | ||
|
|
4469a2c25a |
@@ -38,13 +38,28 @@
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**",
|
||||
"**/src/app/fuse-fake-db/**/*",
|
||||
"**/src/assets/angular-material-examples/**/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Fuse2
|
||||
|
||||
Material Design Admin Template with Angular 4+ and Angular Material 2
|
||||
Material Design Admin Template with Angular 5+ and Angular Material 2
|
||||
|
||||
## Development server
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Fuse2Page } from './app.po';
|
||||
|
||||
describe('fuse2 App', () => {
|
||||
let page: Fuse2Page;
|
||||
describe('Fuse2 App', () => {
|
||||
let page: Fuse2Page;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new Fuse2Page();
|
||||
});
|
||||
beforeEach(() => {
|
||||
page = new Fuse2Page();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!!');
|
||||
});
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class Fuse2Page {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
|
||||
4264
package-lock.json
generated
4264
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
78
package.json
78
package.json
@@ -1,73 +1,75 @@
|
||||
{
|
||||
"name": "fuse2",
|
||||
"version": "1.1.2",
|
||||
"version": "1.2.3",
|
||||
"license": "",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"start-hmr": "ng serve --hmr -e=hmr -sm=false",
|
||||
"start-hmr-sourcemaps": "ng serve --hmr -e=hmr",
|
||||
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build",
|
||||
"build-prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --prod",
|
||||
"build": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --dev",
|
||||
"build-prod": "node --max_old_space_size=6144 ./node_modules/@angular/cli/bin/ng build --prod",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@agm/core": "1.0.0-beta.1",
|
||||
"@angular/animations": "4.4.5",
|
||||
"@angular/cdk": "2.0.0-beta.12",
|
||||
"@angular/common": "4.4.5",
|
||||
"@angular/compiler": "4.4.5",
|
||||
"@angular/core": "4.4.5",
|
||||
"@angular/flex-layout": "2.0.0-beta.9",
|
||||
"@angular/forms": "4.4.5",
|
||||
"@angular/http": "4.4.5",
|
||||
"@angular/material": "2.0.0-beta.12",
|
||||
"@angular/platform-browser": "4.4.5",
|
||||
"@angular/platform-browser-dynamic": "4.4.5",
|
||||
"@angular/router": "4.4.5",
|
||||
"@swimlane/ngx-charts": "6.0.2",
|
||||
"@swimlane/ngx-datatable": "9.3.1",
|
||||
"@swimlane/ngx-dnd": "3.0.0",
|
||||
"angular-calendar": "0.21.2",
|
||||
"angular-in-memory-web-api": "0.5.0",
|
||||
"@agm/core": "1.0.0-beta.2",
|
||||
"@angular/animations": "5.0.3",
|
||||
"@angular/cdk": "5.0.0-rc.1",
|
||||
"@angular/common": "5.0.3",
|
||||
"@angular/compiler": "5.0.3",
|
||||
"@angular/core": "5.0.3",
|
||||
"@angular/flex-layout": "2.0.0-beta.10-4905443",
|
||||
"@angular/forms": "5.0.3",
|
||||
"@angular/http": "5.0.3",
|
||||
"@angular/material": "5.0.0-rc.1",
|
||||
"@angular/material-moment-adapter": "5.0.0-rc.1",
|
||||
"@angular/platform-browser": "5.0.3",
|
||||
"@angular/platform-browser-dynamic": "5.0.3",
|
||||
"@angular/router": "5.0.3",
|
||||
"@ngx-translate/core": "8.0.0",
|
||||
"@swimlane/ngx-charts": "7.0.1",
|
||||
"@swimlane/ngx-datatable": "11.1.4",
|
||||
"@withinpixels/ngx-dnd": "3.1.0",
|
||||
"angular-calendar": "0.22.1",
|
||||
"angular-in-memory-web-api": "0.5.1",
|
||||
"angular2-markdown": "1.6.0",
|
||||
"classlist.js": "1.1.20150312",
|
||||
"core-js": "2.5.1",
|
||||
"d3": "4.10.0",
|
||||
"d3": "4.12.0",
|
||||
"hammerjs": "2.0.8",
|
||||
"highlight.js": "9.12.0",
|
||||
"intl": "1.2.5",
|
||||
"moment": "2.19.1",
|
||||
"ngx-color-picker": "4.4.0",
|
||||
"moment": "2.19.2",
|
||||
"ngx-color-picker": "5.0.4",
|
||||
"ngx-cookie-service": "1.0.9",
|
||||
"perfect-scrollbar": "1.0.3",
|
||||
"rxjs": "5.4.3",
|
||||
"perfect-scrollbar": "1.2.0",
|
||||
"rxjs": "5.5.2",
|
||||
"web-animations-js": "2.3.1",
|
||||
"zone.js": "0.8.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.4.7",
|
||||
"@angular/compiler-cli": "4.4.5",
|
||||
"@angular/language-service": "4.4.5",
|
||||
"@angular/cli": "1.5.4",
|
||||
"@angular/compiler-cli": "5.0.3",
|
||||
"@angular/language-service": "5.0.3",
|
||||
"@angularclass/hmr": "2.1.3",
|
||||
"@types/jasmine": "2.6.0",
|
||||
"@types/jasminewd2": "2.0.2",
|
||||
"@types/node": "6.0.88",
|
||||
"codelyzer": "3.2.0",
|
||||
"jasmine-core": "2.6.2",
|
||||
"jasmine-spec-reporter": "4.1.0",
|
||||
"@types/jasmine": "2.5.54",
|
||||
"@types/jasminewd2": "2.0.3",
|
||||
"@types/node": "6.0.92",
|
||||
"codelyzer": "4.0.1",
|
||||
"jasmine-core": "2.6.4",
|
||||
"jasmine-spec-reporter": "4.1.1",
|
||||
"karma": "1.7.1",
|
||||
"karma-chrome-launcher": "2.1.1",
|
||||
"karma-cli": "1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "1.2.1",
|
||||
"karma-coverage-istanbul-reporter": "1.3.0",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-jasmine-html-reporter": "0.2.2",
|
||||
"protractor": "5.1.2",
|
||||
"ts-node": "3.2.0",
|
||||
"ts-node": "3.2.2",
|
||||
"tslint": "5.7.0",
|
||||
"typescript": "2.3.3"
|
||||
"typescript": "2.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,25 @@
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-root',
|
||||
@@ -8,7 +9,18 @@ import { FuseSplashScreenService } from './core/services/splash-screen.service';
|
||||
})
|
||||
export class AppComponent
|
||||
{
|
||||
constructor(private fuseSplashScreen: FuseSplashScreenService)
|
||||
constructor(
|
||||
private fuseSplashScreen: FuseSplashScreenService,
|
||||
private translate: TranslateService
|
||||
)
|
||||
{
|
||||
// Add languages
|
||||
this.translate.addLangs(['en', 'tr']);
|
||||
|
||||
// Set the default language
|
||||
this.translate.setDefaultLang('en');
|
||||
|
||||
// Use a language
|
||||
this.translate.use('en');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ComponentsThirdPartyModule } from './main/content/components-third-part
|
||||
import { ServicesModule } from './main/content/services/services.module';
|
||||
import { FuseAngularMaterialModule } from './main/content/components/angular-material/angular-material.module';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
@@ -35,6 +36,10 @@ const appRoutes: Routes = [
|
||||
path : 'apps/calendar',
|
||||
loadChildren: './main/content/apps/calendar/calendar.module#FuseCalendarModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/e-commerce',
|
||||
loadChildren: './main/content/apps/e-commerce/e-commerce.module#FuseEcommerceModule'
|
||||
},
|
||||
{
|
||||
path : 'apps/todo',
|
||||
loadChildren: './main/content/apps/todo/todo.module#FuseTodoModule'
|
||||
@@ -69,6 +74,7 @@ const appRoutes: Routes = [
|
||||
RouterModule.forRoot(appRoutes),
|
||||
SharedModule,
|
||||
MarkdownModule.forRoot(),
|
||||
TranslateModule.forRoot(),
|
||||
|
||||
InMemoryWebApiModule.forRoot(FuseFakeDbService, {
|
||||
delay : 0,
|
||||
|
||||
@@ -33,21 +33,21 @@ export const fuseAnimations = [
|
||||
stagger('50ms', [
|
||||
animateChild()
|
||||
])
|
||||
])),
|
||||
], {optional: true})),
|
||||
transition('void => 100',
|
||||
query('@*',
|
||||
[
|
||||
stagger('100ms', [
|
||||
animateChild()
|
||||
])
|
||||
])),
|
||||
], {optional: true})),
|
||||
transition('void => 200',
|
||||
query('@*',
|
||||
[
|
||||
stagger('200ms', [
|
||||
animateChild()
|
||||
])
|
||||
]))
|
||||
], {optional: true}))
|
||||
]),
|
||||
|
||||
trigger('fadeInOut', [
|
||||
@@ -129,6 +129,17 @@ export const fuseAnimations = [
|
||||
transition('* => void', animate('300ms'))
|
||||
]),
|
||||
|
||||
trigger('expandCollapse', [
|
||||
state('void', style({
|
||||
height: '0px'
|
||||
})),
|
||||
state('*', style({
|
||||
height: '*'
|
||||
})),
|
||||
transition('void => *', animate('300ms ease-out')),
|
||||
transition('* => void', animate('300ms ease-in'))
|
||||
]),
|
||||
|
||||
trigger('routerTransitionLeft', [
|
||||
|
||||
transition('* => *', [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/interval';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-countdown',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
type="button"
|
||||
class="mat-elevation-z1"
|
||||
[matMenuTriggerFor]="colorMenu"
|
||||
(onMenuOpen)="onMenuOpen()"
|
||||
(menuOpened)="onMenuOpen()"
|
||||
[ngClass]="'mat-'+selectedPalette+'-'+selectedHue+'-bg'">
|
||||
<mat-icon>palette</mat-icon>
|
||||
</button>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active" matRipple>
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<fuse-nav-horizontal-collapse *ngIf="item.type=='group'" [item]="item"></fuse-nav-horizontal-collapse>
|
||||
<fuse-nav-horizontal-collapse *ngIf="item.type=='collapse'" [item]="item"></fuse-nav-horizontal-collapse>
|
||||
<fuse-nav-horizontal-item *ngIf="item.type=='nav-item'" [item]="item"></fuse-nav-horizontal-item>
|
||||
<fuse-nav-horizontal-item *ngIf="item.type=='item'" [item]="item"></fuse-nav-horizontal-item>
|
||||
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ export class FuseNavVerticalCollapseComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
if ( parent.children[i].url === url )
|
||||
if ( parent.children[i].url === url || url.includes(parent.children[i].url) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active" matRipple>
|
||||
<a class="nav-link" *ngIf="item.url" [routerLink]="[item.url]" routerLinkActive="active"
|
||||
[routerLinkActiveOptions]="{exact: item.exactMatch || false}" matRipple>
|
||||
<mat-icon class="nav-link-icon" *ngIf="item.icon">{{item.icon}}</mat-icon>
|
||||
<span class="nav-link-title">{{item.title}}</span>
|
||||
<span class="nav-link-badge" *ngIf="item.badge"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="addMenu" matTooltip="Click to add/remove shortcut"
|
||||
(onMenuOpen)="onMenuOpen()">
|
||||
(menuOpened)="onMenuOpen()">
|
||||
<mat-icon class="amber-600-fg">star</mat-icon>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -149,7 +149,9 @@ export class FuseShortcutsComponent implements OnInit, OnDestroy
|
||||
|
||||
onMenuOpen()
|
||||
{
|
||||
this.searchInputField.nativeElement.focus();
|
||||
setTimeout(() => {
|
||||
this.searchInputField.nativeElement.focus();
|
||||
});
|
||||
}
|
||||
|
||||
showMobileShortcutsPanel()
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
<mat-radio-button class="mr-8 mb-8" value="none">None</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
<h3>Navigation Fold (for vertical navigation):</h3>
|
||||
<mat-slide-toggle [(ngModel)]="fuseSettings.layout.navigationFolded"
|
||||
(change)="onSettingsChange()">
|
||||
Folded
|
||||
</mat-slide-toggle>
|
||||
|
||||
<h3 class="mt-24">Toolbar:</h3>
|
||||
<mat-radio-group [(ngModel)]="fuseSettings.layout.toolbar" (ngModelChange)="onSettingsChange()"
|
||||
fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign="start start" fxLayoutWrap>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Directive, Input, OnInit, HostListener, OnDestroy, HostBinding } from '@angular/core';
|
||||
import { MatSidenav } from '@angular/material';
|
||||
import { FuseMatSidenavHelperService } from 'app/core/directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { FuseMatchMedia } from '../../services/match-media.service';
|
||||
import { ObservableMedia } from '@angular/flex-layout';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FuseMatchMedia } from '../../services/match-media.service';
|
||||
import { FuseMatSidenavHelperService } from './fuse-mat-sidenav-helper.service';
|
||||
|
||||
@Directive({
|
||||
selector: '[fuseMatSidenavHelper]'
|
||||
@@ -13,7 +13,6 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
|
||||
matchMediaSubscription: Subscription;
|
||||
|
||||
@HostBinding('class.mat-is-locked-open') isLockedOpen = true;
|
||||
@HostBinding('class.mat-stop-transition') stopTransition = true;
|
||||
|
||||
@Input('fuseMatSidenavHelper') id: string;
|
||||
@Input('mat-is-locked-open') matIsLockedOpenBreakpoint: string;
|
||||
@@ -33,45 +32,31 @@ export class FuseMatSidenavHelperDirective implements OnInit, OnDestroy
|
||||
|
||||
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.open();
|
||||
});
|
||||
this.stopTransition = false;
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.close();
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.stopTransition = false;
|
||||
}, 3000);
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.toggle(false);
|
||||
}
|
||||
|
||||
this.matchMediaSubscription = this.fuseMatchMedia.onMediaChange.subscribe(() => {
|
||||
if ( this.observableMedia.isActive(this.matIsLockedOpenBreakpoint) )
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.open();
|
||||
});
|
||||
this.isLockedOpen = true;
|
||||
this.matSidenav.mode = 'side';
|
||||
this.matSidenav.toggle(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(() => {
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.close();
|
||||
});
|
||||
this.isLockedOpen = false;
|
||||
this.matSidenav.mode = 'over';
|
||||
this.matSidenav.toggle(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
@@ -82,10 +82,12 @@ export class FuseUtils
|
||||
{
|
||||
function S4()
|
||||
{
|
||||
return (((1 + Math.random()) * 0x10000) || 0).toString(16).substring(1);
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
return (S4() + S4());
|
||||
return S4() + S4();
|
||||
}
|
||||
|
||||
public static toggleInArray(item, array)
|
||||
@@ -99,4 +101,14 @@ export class FuseUtils
|
||||
array.splice(array.indexOf(item), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static handleize(text)
|
||||
{
|
||||
return text.toString().toLowerCase()
|
||||
.replace(/\s+/g, '-') // Replace spaces with -
|
||||
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
|
||||
.replace(/\-\-+/g, '-') // Replace multiple - with single -
|
||||
.replace(/^-+/, '') // Trim - from start of text
|
||||
.replace(/-+$/, ''); // Trim - from end of text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,6 +681,7 @@ const matColors = {
|
||||
}
|
||||
};
|
||||
|
||||
// tslint:disable-next-line
|
||||
const matPresetColors = [
|
||||
'#ffebee', '#ffcdd2', '#ef9a9a', '#e57373', '#ef5350', '#f44336', '#e53935', '#d32f2f', '#c62828', '#b71c1c', '#ff8a80', '#ff5252', '#ff1744', '#d50000', '#fce4ec', '#f8bbd0', '#f48fb1', '#f06292', '#ec407a', '#e91e63', '#d81b60', '#c2185b', '#ad1457', '#880e4f', '#ff80ab', '#ff4081', '#f50057', '#c51162', '#f3e5f5', '#e1bee7', '#ce93d8', '#ba68c8', '#ab47bc', '#9c27b0', '#8e24aa', '#7b1fa2', '#6a1b9a', '#4a148c', '#ea80fc', '#e040fb', '#d500f9', '#aa00ff', '#ede7f6', '#d1c4e9', '#b39ddb', '#9575cd', '#7e57c2', '#673ab7', '#5e35b1', '#512da8', '#4527a0', '#311b92', '#b388ff', '#7c4dff', '#651fff', '#6200ea', '#e8eaf6', '#c5cae9', '#9fa8da', '#7986cb', '#5c6bc0', '#3f51b5', '#3949ab', '#303f9f', '#283593', '#1a237e', '#8c9eff', '#536dfe', '#3d5afe', '#304ffe', '#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5', '#2196f3', '#1e88e5', '#1976d2', '#1565c0', '#0d47a1', '#82b1ff', '#448aff', '#2979ff', '#2962ff', '#e1f5fe', '#b3e5fc', '#81d4fa', '#4fc3f7', '#29b6f6', '#03a9f4', '#039be5', '#0288d1', '#0277bd', '#01579b', '#80d8ff', '#40c4ff', '#00b0ff', '#0091ea', '#e0f7fa', '#b2ebf2', '#80deea', '#4dd0e1', '#26c6da', '#00bcd4', '#00acc1', '#0097a7', '#00838f', '#006064', '#84ffff', '#18ffff', '#00e5ff', '#00b8d4', '#e0f2f1', '#b2dfdb', '#80cbc4', '#4db6ac', '#26a69a', '#009688', '#00897b', '#00796b', '#00695c', '#004d40', '#a7ffeb', '#64ffda', '#1de9b6', '#00bfa5', '#e8f5e9', '#c8e6c9', '#a5d6a7', '#81c784', '#66bb6a', '#4caf50', '#43a047', '#388e3c', '#2e7d32', '#1b5e20', '#b9f6ca', '#69f0ae', '#00e676', '#00c853', '#f1f8e9', '#dcedc8', '#c5e1a5', '#aed581', '#9ccc65', '#8bc34a', '#7cb342', '#689f38', '#558b2f', '#33691e', '#ccff90', '#b2ff59', '#76ff03', '#64dd17', '#f9fbe7', '#f0f4c3', '#e6ee9c', '#dce775', '#d4e157', '#cddc39', '#c0ca33', '#afb42b', '#9e9d24', '#827717', '#f4ff81', '#eeff41', '#c6ff00', '#aeea00', '#fffde7', '#fff9c4', '#fff59d', '#fff176', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825', '#f57f17', '#ffff8d', '#ffff00', '#ffea00', '#ffd600', '#fff8e1', '#ffecb3', '#ffe082', '#ffd54f', '#ffca28', '#ffc107', '#ffb300', '#ffa000', '#ff8f00', '#ff6f00', '#ffe57f', '#ffd740', '#ffc400', '#ffab00', '#fff3e0', '#ffe0b2', '#ffcc80', '#ffb74d', '#ffa726', '#ff9800', '#fb8c00', '#f57c00', '#ef6c00', '#e65100', '#ffd180', '#ffab40', '#ff9100', '#ff6d00', '#fbe9e7', '#ffccbc', '#ffab91', '#ff8a65', '#ff7043', '#ff5722', '#f4511e', '#e64a19', '#d84315', '#bf360c', '#ff9e80', '#ff6e40', '#ff3d00', '#dd2c00', '#efebe9', '#d7ccc8', '#bcaaa4', '#a1887f', '#8d6e63', '#795548', '#6d4c41', '#5d4037', '#4e342e', '#3e2723', '#d7ccc8', '#bcaaa4', '#8d6e63', '#5d4037', '#fafafa', '#f5f5f5', '#eeeeee', '#e0e0e0', '#bdbdbd', '#9e9e9e', '#757575', '#616161', '#424242', '#212121', '#ffffff', '#eeeeee', '#bdbdbd', '#616161', '#eceff1', '#cfd8dc', '#b0bec5', '#90a4ae', '#78909c', '#607d8b', '#546e7a', '#455a64', '#37474f', '#263238', '#cfd8dc', '#b0bec5', '#78909c', '#455a64'
|
||||
];
|
||||
|
||||
@@ -5,22 +5,24 @@ import { CommonModule } from '@angular/common';
|
||||
import { MaterialModule } from './material.module';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { NgxDnDModule } from '@swimlane/ngx-dnd';
|
||||
import { NgxDnDModule } from '@withinpixels/ngx-dnd';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
|
||||
import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '../directives/mat-sidenav-helper/mat-sidenav-helper.directive';
|
||||
import { FuseMatSidenavHelperDirective, FuseMatSidenavTogglerDirective } from '../directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.directive';
|
||||
import { FuseMatSidenavHelperService } from '../directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.service';
|
||||
import { FusePipesModule } from '../pipes/pipes.module';
|
||||
import { FuseConfirmDialogComponent } from '../components/confirm-dialog/confirm-dialog.component';
|
||||
import { FuseCountdownComponent } from '../components/countdown/countdown.component';
|
||||
import { FuseMatchMedia } from '../services/match-media.service';
|
||||
import { FuseNavbarVerticalService } from '../../main/navbar/vertical/navbar-vertical.service';
|
||||
import { FuseMatSidenavHelperService } from '../directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { FuseHljsComponent } from '../components/hljs/hljs.component';
|
||||
import { FusePerfectScrollbarDirective } from '../directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive';
|
||||
import { FuseIfOnDomDirective } from '../directives/fuse-if-on-dom/fuse-if-on-dom.directive';
|
||||
import { FuseMaterialColorPickerComponent } from '../components/material-color-picker/material-color-picker.component';
|
||||
import { FuseTranslationLoaderService } from '../services/translation-loader.service';
|
||||
import { CookieService } from 'ngx-cookie-service';
|
||||
import { MarkdownModule } from 'angular2-markdown';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@NgModule({
|
||||
declarations : [
|
||||
@@ -62,7 +64,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
NgxDatatableModule,
|
||||
FuseIfOnDomDirective,
|
||||
FuseMaterialColorPickerComponent,
|
||||
MarkdownModule
|
||||
MarkdownModule,
|
||||
TranslateModule
|
||||
],
|
||||
entryComponents: [
|
||||
FuseConfirmDialogComponent
|
||||
@@ -71,7 +74,8 @@ import { MarkdownModule } from 'angular2-markdown';
|
||||
CookieService,
|
||||
FuseMatchMedia,
|
||||
FuseNavbarVerticalService,
|
||||
FuseMatSidenavHelperService
|
||||
FuseMatSidenavHelperService,
|
||||
FuseTranslationLoaderService
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import "partials/angular-material-fix";
|
||||
@import "partials/typography";
|
||||
@import "partials/page-layouts";
|
||||
@import "partials/cards";
|
||||
@import "partials/navigation";
|
||||
@import "partials/forms";
|
||||
@import "partials/toolbar";
|
||||
|
||||
@@ -6,42 +6,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: "Sidenav opening with animations for the first time"
|
||||
mat-sidenav-container {
|
||||
|
||||
mat-sidenav {
|
||||
|
||||
&[mat-is-locked-open].mat-stop-transition {
|
||||
transition: none !important;
|
||||
transform: translate3d(0, 0, 0) !important;
|
||||
opacity: 0;
|
||||
|
||||
~ .mat-sidenav-content,
|
||||
~ .mat-drawer-content {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.mat-sidenav-opened {
|
||||
|
||||
&.mat-drawer-side {
|
||||
|
||||
~ .mat-sidenav-content,
|
||||
~ .mat-drawer-content {
|
||||
transition: none !important;
|
||||
transform: translate3d(0, 0, 0) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mat-drawer-end {
|
||||
}
|
||||
}
|
||||
|
||||
.mat-drawer-content {
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: "Inconsistent font sizes across elements"
|
||||
.mat-input-wrapper {
|
||||
font-size: 16px;
|
||||
@@ -59,3 +23,8 @@ mat-sidenav-container {
|
||||
width: 14px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
// Fix: "Input underlines has wrong color opacity value"
|
||||
.mat-form-field-underline {
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
154
src/app/core/scss/partials/_cards.scss
Normal file
154
src/app/core/scss/partials/_cards.scss
Normal file
@@ -0,0 +1,154 @@
|
||||
.fuse-card {
|
||||
max-width: 320px;
|
||||
min-width: 320px;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
@include mat-elevation(2);
|
||||
|
||||
&.variable-width {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.card-rich-media {
|
||||
position: relative;
|
||||
|
||||
.card-title {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.card-media-header {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
|
||||
&.medium {
|
||||
align-items: flex-start;
|
||||
|
||||
.card-rich-media {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
&.large {
|
||||
align-items: flex-start;
|
||||
|
||||
.card-rich-media {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-primary-title {
|
||||
padding: 0 16px 0 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-rich-media {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
+ div {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-avatar-header {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
|
||||
.card-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 100%;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.card-avatar-title {
|
||||
|
||||
.card-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-primary-title {
|
||||
padding: 16px;
|
||||
|
||||
.card-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
+ div {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-supporting-text {
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.75;
|
||||
|
||||
+ div {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
padding: 8px;
|
||||
|
||||
&.icon-buttons {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
&.align-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.align-right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.mat-button {
|
||||
min-width: 0 !important;
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
|
||||
.card-expander {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
+ div {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-expand-area {
|
||||
overflow: hidden;
|
||||
|
||||
.card-expanded-supporting-text {
|
||||
padding: 8px 16px 16px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,11 @@ $matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400
|
||||
// Generate material element colors
|
||||
// based on current contrast color
|
||||
@include generateMaterialElementColors($contrastColor);
|
||||
|
||||
&[disabled] {
|
||||
background-color: rgba($color, .12) !important;
|
||||
color: rgba($contrastColor, .26) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$colorName}#{$hue}-fg {
|
||||
|
||||
@@ -195,6 +195,10 @@
|
||||
|
||||
> .nav-item {
|
||||
|
||||
> .nav-link {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
&.nav-collapse {
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
|
||||
max-height: $carded-toolbar-height;
|
||||
}
|
||||
|
||||
.content {
|
||||
> .content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
@@ -222,6 +222,62 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tabbed
|
||||
&.tabbed {
|
||||
|
||||
> mat-sidenav-container {
|
||||
|
||||
> .mat-sidenav-content,
|
||||
> .mat-drawer-content {
|
||||
width: calc(100% - 240px);
|
||||
|
||||
.center {
|
||||
width: calc(100% - 32px);
|
||||
|
||||
@include media-breakpoint-down('md') {
|
||||
width: calc(100% - 64px);
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.content-card {
|
||||
|
||||
.content {
|
||||
|
||||
.mat-tab-group {
|
||||
overflow: hidden;
|
||||
|
||||
.mat-tab-header {
|
||||
|
||||
.mat-tab-label {
|
||||
height: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-body {
|
||||
overflow: hidden;
|
||||
|
||||
.mat-tab-body-content {
|
||||
overflow: hidden;
|
||||
|
||||
.tab-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Left sidenav
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
min-height: 48px;
|
||||
transition: none;
|
||||
padding: 0 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +83,16 @@
|
||||
|
||||
.datatable-pager {
|
||||
margin: 0 0 0 24px;
|
||||
|
||||
.pager {
|
||||
|
||||
li {
|
||||
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,11 @@ export class FuseConfigService
|
||||
// Set the default settings
|
||||
this.defaultSettings = {
|
||||
layout : {
|
||||
navigation: 'left', // 'right', 'left', 'top', 'none'
|
||||
toolbar : 'below', // 'above', 'below', 'none'
|
||||
footer : 'below', // 'above', 'below', 'none'
|
||||
mode : 'fullwidth' // 'boxed', 'fullwidth'
|
||||
navigation : 'left', // 'right', 'left', 'top', 'none'
|
||||
navigationFolded: false, // true, false
|
||||
toolbar : 'below', // 'above', 'below', 'none'
|
||||
footer : 'below', // 'above', 'below', 'none'
|
||||
mode : 'fullwidth' // 'boxed', 'fullwidth'
|
||||
},
|
||||
colorClasses : {
|
||||
toolbar: 'mat-white-500-bg',
|
||||
@@ -44,6 +45,7 @@ export class FuseConfigService
|
||||
this.defaultSettings.customScrollbars = false;
|
||||
}
|
||||
|
||||
// Set the settings from the default settings
|
||||
this.settings = Object.assign({}, this.defaultSettings);
|
||||
|
||||
// Reload the default settings on every navigation start
|
||||
@@ -58,7 +60,6 @@ export class FuseConfigService
|
||||
|
||||
// Create the behavior subject
|
||||
this.onSettingsChanged = new BehaviorSubject(this.settings);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +68,10 @@ export class FuseConfigService
|
||||
*/
|
||||
setSettings(settings)
|
||||
{
|
||||
// Set the settings from the given object
|
||||
this.settings = Object.assign({}, this.settings, settings);
|
||||
|
||||
// Trigger the event
|
||||
this.onSettingsChanged.next(this.settings);
|
||||
}
|
||||
}
|
||||
|
||||
27
src/app/core/services/translation-loader.service.ts
Normal file
27
src/app/core/services/translation-loader.service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
export interface Locale
|
||||
{
|
||||
lang: string;
|
||||
data: Object;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class FuseTranslationLoaderService
|
||||
{
|
||||
constructor(private translate: TranslateService)
|
||||
{
|
||||
}
|
||||
|
||||
public loadTranslations(...args: Locale[]): void
|
||||
{
|
||||
const locales = [...args];
|
||||
|
||||
locales.forEach((locale) => {
|
||||
// use setTranslation() with the third argument set to true
|
||||
// to append translations instead of replacing them
|
||||
this.translate.setTranslation(locale.lang, locale.data, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
3962
src/app/fuse-fake-db/e-commerce.ts
Normal file
3962
src/app/fuse-fake-db/e-commerce.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,8 @@ import { IconsFakeDb } from './icons';
|
||||
import { ProjectsDashboardDb } from './projects-dashboard';
|
||||
import { ScrumboardFakeDb } from './scrumboard';
|
||||
import { FaqFakeDb } from './faq';
|
||||
import { KnowledgeBaseFakeDb } from './knowledge-base';
|
||||
import { ECommerceFakeDb } from './e-commerce';
|
||||
|
||||
export class FuseFakeDbService implements InMemoryDbService
|
||||
{
|
||||
@@ -46,7 +48,11 @@ export class FuseFakeDbService implements InMemoryDbService
|
||||
'projects-dashboard-projects': ProjectsDashboardDb.projects,
|
||||
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
|
||||
'scrumboard-boards' : ScrumboardFakeDb.boards,
|
||||
'faq' : FaqFakeDb.data
|
||||
'faq' : FaqFakeDb.data,
|
||||
'knowledge-base' : KnowledgeBaseFakeDb.data,
|
||||
'e-commerce-dashboard' : ECommerceFakeDb.dashboard,
|
||||
'e-commerce-products' : ECommerceFakeDb.products,
|
||||
'e-commerce-orders' : ECommerceFakeDb.orders
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
113
src/app/fuse-fake-db/knowledge-base.ts
Normal file
113
src/app/fuse-fake-db/knowledge-base.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
export class KnowledgeBaseFakeDb
|
||||
{
|
||||
public static data = [
|
||||
{
|
||||
'title' : 'Your Account',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 17,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'Account limits',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my username?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my password?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I change my email address?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I close my account?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Selling',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 12,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'A guide to the upload process',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Author collaboration',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Exclusivity policy',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Promises you make as an author',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'An author’s introduction',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Buying',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 19,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'Where is my purchase code?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Can I get a refund?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Contact us',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How do I purchase an item?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'I\'m trying to find a specific item',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title' : 'Item Support',
|
||||
'path' : '/pages/knowledge-base',
|
||||
'articlesCount' : 24,
|
||||
'featuredArticles': [
|
||||
{
|
||||
'title' : 'What is Item Support?',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'How to contact an author',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Rating or review removal policy',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Purchasing unsupported items',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
},
|
||||
{
|
||||
'title' : 'Item installation guide',
|
||||
'content': '<p><b>The standard Lorem Ipsum passage, used since the 1500s</b></p>\n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\n sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n</p>\n<p><b>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</b></p>\n<p>Sed ut perspiciatis unde omnis iste natus error sit\n voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et\n quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,\n qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt\n ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam\n corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui\n in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\n pariatur?\n</p>\n<p><b>1914 translation by H. Rackham</b></p>\n<p>\n But I must explain to you how all this mistaken idea of denouncing pleasure\n and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of\n the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure\n itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter\n consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of\n itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some\n great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain\n some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no\n annoying consequences, or one who avoids a pain that produces no resultant pleasure?\n</p>\n'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import { CalendarEvent } from 'angular-calendar';
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
|
||||
import { CalendarEventModel } from '../event.model';
|
||||
import { MatColors } from '../../../../../core/matColors';
|
||||
import 'rxjs/Rx';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-calendar-event-form-dialog',
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- LEFT SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||
<mat-sidenav class="sidenav" align="start" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="chat-left-sidenav" mat-is-locked-open="gt-md">
|
||||
<fuse-chat-left-sidenav></fuse-chat-left-sidenav>
|
||||
</mat-sidenav>
|
||||
@@ -26,7 +26,7 @@
|
||||
<!-- / CONTENT -->
|
||||
|
||||
<!-- RIGHT SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="end" opened="false" mode="over"
|
||||
<mat-sidenav class="sidenav" align="end" opened="false" mode="over"
|
||||
fuseMatSidenavHelper="chat-right-sidenav">
|
||||
<fuse-chat-right-sidenav></fuse-chat-right-sidenav>
|
||||
</mat-sidenav>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<!-- USER AVATAR WRAPPER -->
|
||||
<div class="avatar-wrapper">
|
||||
@@ -16,7 +16,8 @@
|
||||
alt="{{user.name}}"/>
|
||||
<!-- / USER AVATAR -->
|
||||
|
||||
<mat-icon class="s-16 status" [ngClass]="user.status" [matMenuTriggerFor]="userStatusMenu"></mat-icon>
|
||||
<mat-icon class="s-16 status" [ngClass]="user.status"
|
||||
[matMenuTriggerFor]="userStatusMenu"></mat-icon>
|
||||
|
||||
<!-- USER STATUS -->
|
||||
<mat-menu id="user-status-menu" #userStatusMenu="matMenu">
|
||||
@@ -69,7 +70,8 @@
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ChatService } from '../../../chat.service';
|
||||
import { FuseMatSidenavHelperService } from '../../../../../../../core/directives/mat-sidenav-helper/mat-sidenav-helper.service';
|
||||
import { ObservableMedia } from '@angular/flex-layout';
|
||||
import { fuseAnimations } from '../../../../../../../core/animations';
|
||||
import { FuseMatSidenavHelperService } from '../../../../../../../core/directives/fuse-mat-sidenav-helper/fuse-mat-sidenav-helper.service';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-chat-chats-sidenav',
|
||||
|
||||
@@ -5,20 +5,19 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<button mat-button class="mat-icon-button" (click)="changeLeftSidenavView('chats')" aria-label="back">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
<mat-toolbar-row class="toolbar-bottom" fxLayout="column" fxLayoutAlign="center center">
|
||||
|
||||
<img [src]="user.avatar" class="avatar user-avatar huge" alt="{{user.name}}"/>
|
||||
|
||||
<div class="user-name my-8">{{user.name}}</div>
|
||||
|
||||
</mat-toolbar-row>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ChatService } from '../../../chat.service';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import 'rxjs/Rx';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-chat-user-sidenav',
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<mat-toolbar>
|
||||
|
||||
<!-- TOOLBAR TOP -->
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<div>Contact Info</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
<!-- / TOOLBAR TOP -->
|
||||
|
||||
<!-- TOOLBAR BOTTOM -->
|
||||
@@ -37,9 +37,9 @@
|
||||
<mat-card>
|
||||
|
||||
<mat-form-field fxFlex>
|
||||
<textarea matInput placeholder="Mood" name="mood"
|
||||
[value]="contact.mood" rows="3" disabled>
|
||||
</textarea>
|
||||
<textarea matInput placeholder="Mood" name="mood"
|
||||
[value]="contact.mood" rows="3" disabled>
|
||||
</textarea>
|
||||
</mat-form-field>
|
||||
|
||||
</mat-card>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<div class="dialog-content-wrapper">
|
||||
<mat-toolbar matDialogTitle class="mat-accent m-0">
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-toolbar-row fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<span class="title dialog-title">{{dialogTitle}}</span>
|
||||
<button mat-button class="mat-icon-button"
|
||||
(click)="dialogRef.close()"
|
||||
aria-label="Close dialog">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-toolbar-row>
|
||||
|
||||
<mat-toolbar-row class="toolbar-bottom py-8 py-sm-16" fxLayout="column" fxLayoutAlign="center center">
|
||||
<img [src]="contact.avatar" class=" avatar contact-avatar huge"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
.contact-form-dialog {
|
||||
|
||||
.mat-dialog-container {
|
||||
@@ -5,6 +7,10 @@
|
||||
width: 400px;
|
||||
overflow: hidden;
|
||||
|
||||
@include media-breakpoint('xs') {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.mat-toolbar {
|
||||
min-height: initial;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
import { CalendarEvent } from 'angular-calendar';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import 'rxjs/Rx';
|
||||
import { Contact } from '../contact.model';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
:host {
|
||||
fuse-contacts-contact-list {
|
||||
flex: 1;
|
||||
|
||||
.mat-table {
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
.mat-column-checkbox {
|
||||
flex: 0 1 48px;
|
||||
|
||||
.mat-checkbox-ripple {
|
||||
display: none !important; //fix for broken rendering
|
||||
}
|
||||
}
|
||||
|
||||
.mat-column-avatar {
|
||||
@@ -40,12 +44,9 @@
|
||||
}
|
||||
|
||||
#add-contact-button {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
padding: 0;
|
||||
|
||||
@include media-breakpoint-down('xs') {
|
||||
top: 12px;
|
||||
}
|
||||
}
|
||||
z-index: 99;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ContactsService } from '../contacts.service';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { FuseContactsContactFormDialogComponent } from '../contact-form/contact-form.component';
|
||||
@@ -7,14 +7,16 @@ import { FuseConfirmDialogComponent } from '../../../../../core/components/confi
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-contacts-contact-list',
|
||||
templateUrl: './contact-list.component.html',
|
||||
styleUrls : ['./contact-list.component.scss'],
|
||||
animations : fuseAnimations
|
||||
selector : 'fuse-contacts-contact-list',
|
||||
templateUrl : './contact-list.component.html',
|
||||
styleUrls : ['./contact-list.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseContactsContactListComponent implements OnInit
|
||||
export class FuseContactsContactListComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@ViewChild('dialogContent') dialogContent: TemplateRef<any>;
|
||||
|
||||
@@ -25,6 +27,10 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
selectedContacts: any[];
|
||||
checkboxes: {};
|
||||
|
||||
onContactsChangedSubscription: Subscription;
|
||||
onSelectedContactsChangedSubscription: Subscription;
|
||||
onUserDataChangedSubscription: Subscription;
|
||||
|
||||
dialogRef: any;
|
||||
|
||||
confirmDialogRef: MatDialogRef<FuseConfirmDialogComponent>;
|
||||
@@ -34,27 +40,35 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
public dialog: MatDialog
|
||||
)
|
||||
{
|
||||
this.contactsService.onContactsChanged.subscribe(contacts => {
|
||||
this.onContactsChangedSubscription =
|
||||
this.contactsService.onContactsChanged.subscribe(contacts => {
|
||||
|
||||
this.contacts = contacts;
|
||||
this.contacts = contacts;
|
||||
|
||||
this.checkboxes = {};
|
||||
contacts.map(contact => {
|
||||
this.checkboxes[contact.id] = false;
|
||||
this.checkboxes = {};
|
||||
contacts.map(contact => {
|
||||
this.checkboxes[contact.id] = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
|
||||
for ( const id in this.checkboxes )
|
||||
{
|
||||
this.checkboxes[id] = selectedContacts.includes(id);
|
||||
}
|
||||
this.selectedContacts = selectedContacts;
|
||||
});
|
||||
this.onSelectedContactsChangedSubscription =
|
||||
this.contactsService.onSelectedContactsChanged.subscribe(selectedContacts => {
|
||||
for ( const id in this.checkboxes )
|
||||
{
|
||||
if ( !this.checkboxes.hasOwnProperty(id) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
this.checkboxes[id] = selectedContacts.includes(id);
|
||||
}
|
||||
this.selectedContacts = selectedContacts;
|
||||
});
|
||||
|
||||
this.onUserDataChangedSubscription =
|
||||
this.contactsService.onUserDataChanged.subscribe(user => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -63,6 +77,13 @@ export class FuseContactsContactListComponent implements OnInit
|
||||
this.dataSource = new FilesDataSource(this.contactsService);
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onContactsChangedSubscription.unsubscribe();
|
||||
this.onSelectedContactsChangedSubscription.unsubscribe();
|
||||
this.onUserDataChangedSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
editContact(contact)
|
||||
{
|
||||
this.dialogRef = this.dialog.open(FuseContactsContactFormDialogComponent, {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="start" opened="true" mode="side"
|
||||
<mat-sidenav class="sidenav" align="start" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="contacts-main-sidenav" mat-is-locked-open="gt-sm">
|
||||
|
||||
<fuse-contacts-main-sidenav *fuseIfOnDom [@animate]="{value:'*'}"></fuse-contacts-main-sidenav>
|
||||
|
||||
@@ -3,12 +3,4 @@
|
||||
.content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
#add-contact-button {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 12px;
|
||||
padding: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ContactsService } from './contacts.service';
|
||||
import { fuseAnimations } from '../../../../core/animations';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { FuseContactsContactFormDialogComponent } from './contact-form/contact-form.component';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-contacts',
|
||||
@@ -12,11 +14,12 @@ import { MatDialog } from '@angular/material';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseContactsComponent implements OnInit
|
||||
export class FuseContactsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
hasSelectedContacts: boolean;
|
||||
searchInput: FormControl;
|
||||
dialogRef: any;
|
||||
onSelectedContactsChangedSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private contactsService: ContactsService,
|
||||
@@ -50,11 +53,11 @@ export class FuseContactsComponent implements OnInit
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
|
||||
this.contactsService.onSelectedContactsChanged
|
||||
.subscribe(selectedContacts => {
|
||||
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||
});
|
||||
this.onSelectedContactsChangedSubscription =
|
||||
this.contactsService.onSelectedContactsChanged
|
||||
.subscribe(selectedContacts => {
|
||||
this.hasSelectedContacts = selectedContacts.length > 0;
|
||||
});
|
||||
|
||||
this.searchInput.valueChanges
|
||||
.debounceTime(300)
|
||||
@@ -64,4 +67,8 @@ export class FuseContactsComponent implements OnInit
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onSelectedContactsChangedSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center" fxFlex fusePerfectScrollbar>
|
||||
<div class="center" fusePerfectScrollbar>
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header mat-accent-bg p-24 pb-0" fxLayout="column" fxLayoutAlign="space-between">
|
||||
@@ -566,7 +566,7 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let row of widgets.widget10.table.rows">
|
||||
<td *ngFor="let cell of row">
|
||||
<span class="p-4" [class]="cell.classes">
|
||||
<span class="p-4" [ngClass]="cell.classes">
|
||||
{{cell.value}}
|
||||
</span>
|
||||
<mat-icon *ngIf="cell.icon" class="s-16">{{cell.icon}}</mat-icon>
|
||||
@@ -688,7 +688,7 @@
|
||||
<!-- / CENTER -->
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="end" mode="side" opened="true" fuseMatSidenavHelper="dashboards-right-sidenav" mat-is-locked-open="gt-md">
|
||||
<mat-sidenav class="sidenav" align="end" mode="side" opened="true" fuseMatSidenavHelper="dashboards-right-sidenav" mat-is-locked-open="gt-md">
|
||||
|
||||
<div class="sidenav-content" fusePerfectScrollbar>
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
mat-sidenav-container {
|
||||
|
||||
.mat-drawer-content,
|
||||
.mat-sidenav-content {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
|
||||
> .header {
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
<div id="e-commerce-dashboard" class="page-layout simple fullwidth">
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="content p-24 w-100-p">
|
||||
|
||||
<!-- WIDGET GROUP -->
|
||||
<div class="widget-group" fxLayout="row" fxFlex="100" fxLayoutWrap fxLayoutAlign="start start" *fuseIfOnDom [@animateStagger]="{value:'50'}">
|
||||
|
||||
<!-- WIDGET 1 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-form-field>
|
||||
<mat-select class="simplified font-size-16" [(ngModel)]="widgets.widget1.currentRange"
|
||||
aria-label="Change range">
|
||||
<mat-option *ngFor="let range of widgets.widget1.ranges | keys"
|
||||
[value]="range.key">
|
||||
{{range.value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button mat-icon-button fuseWidgetToggle aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div class="light-blue-fg font-size-72 line-height-72">
|
||||
{{widgets.widget1.data.count[widgets.widget1.currentRange]}}
|
||||
</div>
|
||||
<div class="h3 secondary-text font-weight-500">{{widgets.widget1.data.label}}</div>
|
||||
</div>
|
||||
|
||||
<div class="p-16 grey-50-bg border-top" fxLayout="row" fxLayoutAlign="start center">
|
||||
<span class="h4 secondary-text text-truncate">{{widgets.widget1.data.extra.label}}:</span>
|
||||
<span class="h4 ml-8">{{widgets.widget1.data.extra.count[widgets.widget1.currentRange]}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
<!-- Back -->
|
||||
<div class="fuse-widget-back p-16 pt-32 mat-white-bg mat-elevation-z2">
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
|
||||
aria-label="Flip widget">
|
||||
<mat-icon class="s-16">close</mat-icon>
|
||||
</button>
|
||||
|
||||
<div>
|
||||
{{widgets.widget1.detail}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Back -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 1 -->
|
||||
|
||||
<!-- WIDGET 2 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h3">{{widgets.widget2.title}}</div>
|
||||
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button" aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div class="red-fg font-size-72 line-height-72">
|
||||
{{widgets.widget2.data.count}}
|
||||
</div>
|
||||
<div class="h3 secondary-text font-weight-500">{{widgets.widget2.data.label}}</div>
|
||||
</div>
|
||||
|
||||
<div class="p-16 grey-50-bg border-top" fxLayout="row" fxLayoutAlign="start center">
|
||||
<span class="h4 secondary-text text-truncate">{{widgets.widget2.data.extra.label}}:</span>
|
||||
<span class="h4 ml-8">{{widgets.widget2.data.extra.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
<!-- Back -->
|
||||
<div class="fuse-widget-back p-16 pt-32 mat-white-bg mat-elevation-z2">
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
|
||||
aria-label="Flip widget">
|
||||
<mat-icon class="s-16">close</mat-icon>
|
||||
</button>
|
||||
|
||||
<div>
|
||||
{{widgets.widget2.detail}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Back -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 2 -->
|
||||
|
||||
<!-- WIDGET 3 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h3">{{widgets.widget3.title}}</div>
|
||||
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button" aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div class="orange-fg font-size-72 line-height-72">
|
||||
{{widgets.widget3.data.count}}
|
||||
</div>
|
||||
<div class="h3 secondary-text font-weight-500">{{widgets.widget3.data.label}}</div>
|
||||
</div>
|
||||
|
||||
<div class="p-16 grey-50-bg border-top" fxLayout="row" fxLayoutAlign="start center">
|
||||
<span class="h4 secondary-text text-truncate">{{widgets.widget3.data.extra.label}}:</span>
|
||||
<span class="h4 ml-8">{{widgets.widget3.data.extra.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
<!-- Back -->
|
||||
<div class="fuse-widget-back p-16 pt-32 mat-white-bg mat-elevation-z2">
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
|
||||
aria-label="Flip widget">
|
||||
<mat-icon class="s-16">close</mat-icon>
|
||||
</button>
|
||||
|
||||
<div>
|
||||
{{widgets.widget3.detail}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Back -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 3 -->
|
||||
|
||||
<!-- WIDGET 4 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-xs="50" fxFlex.gt-md="25">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
<div class="pl-16 pr-8 py-16 h-52" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h3">{{widgets.widget4.title}}</div>
|
||||
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button" aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pt-8 pb-32" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div class="blue-grey-fg font-size-72 line-height-72">{{widgets.widget4.data.count}}
|
||||
</div>
|
||||
<div class="h3 secondary-text font-weight-500">{{widgets.widget4.data.label}}</div>
|
||||
</div>
|
||||
|
||||
<div class="p-16 grey-50-bg border-top" fxLayout="row" fxLayoutAlign="start center">
|
||||
<span class="h4 secondary-text text-truncate">{{widgets.widget4.data.extra.label}}:</span>
|
||||
<span class="h4 ml-8">{{widgets.widget4.data.extra.count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
<!-- Back -->
|
||||
<div class="fuse-widget-back p-16 pt-32 mat-white-bg mat-elevation-z2">
|
||||
<button mat-icon-button fuseWidgetToggle class="fuse-widget-flip-button"
|
||||
aria-label="Flip widget">
|
||||
<mat-icon class="s-16">close</mat-icon>
|
||||
</button>
|
||||
|
||||
<div>
|
||||
{{widgets.widget4.detail}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Back -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 4 -->
|
||||
|
||||
|
||||
<!-- WIDGET 5 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="row" fxFlex="100">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
|
||||
<div class="px-16 border-bottom" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutWrap>
|
||||
|
||||
<div fxFlex class="py-8 h3">{{widgets.widget5.title}}</div>
|
||||
|
||||
<div fxFlex="0 1 auto" class="py-8" fxLayout="row">
|
||||
<button mat-button class="px-16"
|
||||
*ngFor="let range of widgets.widget5.ranges | keys"
|
||||
(click)="widget5.currentRange = range.key"
|
||||
[disabled]="widget5.currentRange == range.key">
|
||||
{{range.value}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-420">
|
||||
<ngx-charts-bar-vertical-stacked
|
||||
*fuseIfOnDom
|
||||
[scheme]="widget5.scheme"
|
||||
[results]="this.widgets.widget5.mainChart[this.widget5.currentRange]"
|
||||
[gradient]="widget5.gradient"
|
||||
[xAxis]="widget5.xAxis"
|
||||
[yAxis]="widget5.yAxis"
|
||||
[legend]="widget5.legend"
|
||||
[showXAxisLabel]="widget5.showXAxisLabel"
|
||||
[showYAxisLabel]="widget5.showYAxisLabel"
|
||||
[xAxisLabel]="widget5.xAxisLabel"
|
||||
[yAxisLabel]="widget5.yAxisLabel"
|
||||
(select)="widget5.onSelect($event)">
|
||||
</ngx-charts-bar-vertical-stacked>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 5 -->
|
||||
|
||||
<!-- WIDGET 6 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-sm="50">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
|
||||
<div class="px-16 border-bottom" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h3">{{widgets.widget6.title}}</div>
|
||||
<mat-form-field>
|
||||
<mat-select class="simplified" [(ngModel)]="widget6.currentRange" aria-label="Change range">
|
||||
<mat-option *ngFor="let range of widgets.widget6.ranges | keys"
|
||||
[value]="range.key">
|
||||
{{range.value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="h-400">
|
||||
<ngx-charts-pie-chart
|
||||
*fuseIfOnDom
|
||||
[scheme]="widget6.scheme"
|
||||
[results]="widgets.widget6.mainChart[widget6.currentRange]"
|
||||
[legend]="widget6.showLegend"
|
||||
[explodeSlices]="widget6.explodeSlices"
|
||||
[labels]="widget6.labels"
|
||||
[doughnut]="widget6.doughnut"
|
||||
[gradient]="widget6.gradient"
|
||||
(select)="widget6.onSelect($event)">
|
||||
</ngx-charts-pie-chart>
|
||||
</div>
|
||||
|
||||
<div class="py-8 mh-16 border-top" fxLayout="row" fxLayoutAlign="start center" fxLayoutWrap>
|
||||
<div class="py-8 border-right" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" fxFlex.gt-sm="50">
|
||||
<span class="mat-display-1 mb-0">{{widgets.widget6.footerLeft.count[widget6.currentRange]}}</span>
|
||||
<span class="h4">{{widgets.widget6.footerLeft.title}}</span>
|
||||
</div>
|
||||
|
||||
<div class="py-8" fxLayout="column" fxLayoutAlign="center center" fxFlex="100" fxFlex.gt-sm="50">
|
||||
<span class="mat-display-1 mb-0">{{widgets.widget6.footerRight.count[widget6.currentRange]}}</span>
|
||||
<span class="h4">{{widgets.widget6.footerRight.title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 6 -->
|
||||
|
||||
<!-- WIDGET 7 -->
|
||||
<fuse-widget [@animate]="{value:'*',params:{y:'100%'}}" class="widget" fxLayout="column" fxFlex="100" fxFlex.gt-sm="50">
|
||||
|
||||
<!-- Front -->
|
||||
<div class="fuse-widget-front mat-white-bg mat-elevation-z2">
|
||||
|
||||
<div class="px-16 border-bottom" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="h3">{{widgets.widget7.title}}</div>
|
||||
<mat-form-field>
|
||||
<mat-select class="simplified" [(ngModel)]="widget7.currentRange"
|
||||
aria-label="Change range">
|
||||
<mat-option *ngFor="let range of widgets.widget7.ranges | keys"
|
||||
[value]="range.key">
|
||||
{{range.value}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="p-16" fxLayout="row" fxLayoutAlign="space-between center"
|
||||
*ngFor="let customer of widgets.widget7.customers[widget7.currentRange]">
|
||||
<div>
|
||||
<div class="h3">{{customer.name}}</div>
|
||||
<div>
|
||||
<span *ngIf="customer.location">{{customer.location}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button mat-icon-button aria-label="More information">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- / Front -->
|
||||
|
||||
</fuse-widget>
|
||||
<!-- / WIDGET 7 -->
|
||||
|
||||
</div>
|
||||
<!-- / WIDGET GROUP -->
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT -->
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
#e-commerce-dashboard {
|
||||
|
||||
.content {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { EcommerceDashboardService } from './dashboard.service';
|
||||
import * as shape from 'd3-shape';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-e-commerce-dashboard',
|
||||
templateUrl : './dashboard.component.html',
|
||||
styleUrls : ['./dashboard.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseEcommerceDashboardComponent implements OnInit, OnDestroy
|
||||
{
|
||||
projects: any[];
|
||||
selectedProject: any;
|
||||
|
||||
widgets: any;
|
||||
widget5: any = {};
|
||||
widget6: any = {};
|
||||
widget7: any = {};
|
||||
|
||||
dateNow = Date.now();
|
||||
|
||||
constructor(private projectsDashboardService: EcommerceDashboardService)
|
||||
{
|
||||
this.projects = this.projectsDashboardService.projects;
|
||||
|
||||
this.selectedProject = this.projects[0];
|
||||
|
||||
this.widgets = this.projectsDashboardService.widgets;
|
||||
|
||||
/**
|
||||
* Widget 5
|
||||
*/
|
||||
this.widget5 = {
|
||||
currentRange : 'TW',
|
||||
xAxis : true,
|
||||
yAxis : true,
|
||||
gradient : false,
|
||||
legend : false,
|
||||
showXAxisLabel: false,
|
||||
xAxisLabel : 'Days',
|
||||
showYAxisLabel: false,
|
||||
yAxisLabel : 'Isues',
|
||||
scheme : {
|
||||
domain: ['#42BFF7', '#C6ECFD', '#C7B42C', '#AAAAAA']
|
||||
},
|
||||
onSelect : (ev) => {
|
||||
console.log(ev);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Widget 6
|
||||
*/
|
||||
this.widget6 = {
|
||||
currentRange : 'TW',
|
||||
legend : false,
|
||||
explodeSlices: false,
|
||||
labels : true,
|
||||
doughnut : true,
|
||||
gradient : false,
|
||||
scheme : {
|
||||
domain: ['#f44336', '#9c27b0', '#03a9f4', '#e91e63']
|
||||
},
|
||||
onSelect : (ev) => {
|
||||
console.log(ev);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Widget 7
|
||||
*/
|
||||
this.widget7 = {
|
||||
currentRange: 'T'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class EcommerceDashboardService implements Resolve<any>
|
||||
{
|
||||
projects: any[];
|
||||
widgets: any[];
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getProjects(),
|
||||
this.getWidgets()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getProjects(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/projects-dashboard-projects')
|
||||
.subscribe((response: any) => {
|
||||
this.projects = response;
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
getWidgets(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/e-commerce-dashboard')
|
||||
.subscribe((response: any) => {
|
||||
this.widgets = response;
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
91
src/app/main/content/apps/e-commerce/e-commerce.module.ts
Normal file
91
src/app/main/content/apps/e-commerce/e-commerce.module.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
import { FuseEcommerceDashboardComponent } from './dashboard/dashboard.component';
|
||||
import { EcommerceDashboardService } from './dashboard/dashboard.service';
|
||||
import { SharedModule } from '../../../../core/modules/shared.module';
|
||||
import { FuseWidgetModule } from '../../../../core/components/widget/widget.module';
|
||||
import { FuseEcommerceProductsComponent } from './products/products.component';
|
||||
import { EcommerceProductsService } from './products/products.service';
|
||||
import { FuseEcommerceProductComponent } from './product/product.component';
|
||||
import { EcommerceProductService } from './product/product.service';
|
||||
import { FuseEcommerceOrdersComponent } from './orders/orders.component';
|
||||
import { EcommerceOrdersService } from './orders/orders.service';
|
||||
import { FuseEcommerceOrderComponent } from './order/order.component';
|
||||
import { EcommerceOrderService } from './order/order.service';
|
||||
import { AgmCoreModule } from '@agm/core';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path : 'dashboard',
|
||||
component: FuseEcommerceDashboardComponent,
|
||||
resolve : {
|
||||
data: EcommerceDashboardService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'products',
|
||||
component: FuseEcommerceProductsComponent,
|
||||
resolve : {
|
||||
data: EcommerceProductsService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'products/:id',
|
||||
component: FuseEcommerceProductComponent,
|
||||
resolve : {
|
||||
data: EcommerceProductService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'products/:id/:handle',
|
||||
component: FuseEcommerceProductComponent,
|
||||
resolve : {
|
||||
data: EcommerceProductService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'orders',
|
||||
component: FuseEcommerceOrdersComponent,
|
||||
resolve : {
|
||||
data: EcommerceOrdersService
|
||||
}
|
||||
},
|
||||
{
|
||||
path : 'orders/:id',
|
||||
component: FuseEcommerceOrderComponent,
|
||||
resolve : {
|
||||
data: EcommerceOrderService
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports : [
|
||||
SharedModule,
|
||||
RouterModule.forChild(routes),
|
||||
FuseWidgetModule,
|
||||
NgxChartsModule,
|
||||
AgmCoreModule.forRoot({
|
||||
apiKey: 'AIzaSyD81ecsCj4yYpcXSLFcYU97PvRsE_X8Bx8'
|
||||
})
|
||||
],
|
||||
declarations: [
|
||||
FuseEcommerceDashboardComponent,
|
||||
FuseEcommerceProductsComponent,
|
||||
FuseEcommerceProductComponent,
|
||||
FuseEcommerceOrdersComponent,
|
||||
FuseEcommerceOrderComponent
|
||||
],
|
||||
providers : [
|
||||
EcommerceDashboardService,
|
||||
EcommerceProductsService,
|
||||
EcommerceProductService,
|
||||
EcommerceOrdersService,
|
||||
EcommerceOrderService
|
||||
]
|
||||
})
|
||||
export class FuseEcommerceModule
|
||||
{
|
||||
}
|
||||
72
src/app/main/content/apps/e-commerce/order/order-statuses.ts
Normal file
72
src/app/main/content/apps/e-commerce/order/order-statuses.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
export const orderStatuses = [
|
||||
{
|
||||
'id' : 1,
|
||||
'name' : 'Awaiting check payment',
|
||||
'color': 'mat-blue-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 2,
|
||||
'name' : 'Payment accepted',
|
||||
'color': 'mat-green-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 3,
|
||||
'name' : 'Preparing the order',
|
||||
'color': 'mat-orange-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 4,
|
||||
'name' : 'Shipped',
|
||||
'color': 'mat-purple-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 5,
|
||||
'name' : 'Delivered',
|
||||
'color': 'mat-green-800-bg'
|
||||
},
|
||||
{
|
||||
'id' : 6,
|
||||
'name' : 'Canceled',
|
||||
'color': 'mat-pink-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 7,
|
||||
'name' : 'Refunded',
|
||||
'color': 'mat-red-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 8,
|
||||
'name' : 'Payment error',
|
||||
'color': 'mat-red-900-bg'
|
||||
},
|
||||
{
|
||||
'id' : 9,
|
||||
'name' : 'On pre-order (paid)',
|
||||
'color': 'mat-purple-300-bg'
|
||||
},
|
||||
{
|
||||
'id' : 10,
|
||||
'name' : 'Awaiting bank wire payment',
|
||||
'color': 'mat-blue-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 11,
|
||||
'name' : 'Awaiting PayPal payment',
|
||||
'color': 'mat-blue-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 12,
|
||||
'name' : 'Remote payment accepted',
|
||||
'color': 'mat-green-500-bg'
|
||||
},
|
||||
{
|
||||
'id' : 13,
|
||||
'name' : 'On pre-order (not paid)',
|
||||
'color': 'mat-purple-300-bg'
|
||||
},
|
||||
{
|
||||
'id' : 14,
|
||||
'name' : 'Awaiting Cash-on-delivery payment',
|
||||
'color': 'mat-blue-500-bg'
|
||||
}
|
||||
];
|
||||
429
src/app/main/content/apps/e-commerce/order/order.component.html
Normal file
429
src/app/main/content/apps/e-commerce/order/order.component.html
Normal file
@@ -0,0 +1,429 @@
|
||||
<div id="order" class="page-layout carded fullwidth" fusePerfectScrollbar>
|
||||
|
||||
<!-- TOP BACKGROUND -->
|
||||
<div class="top-bg mat-accent-bg"></div>
|
||||
<!-- / TOP BACKGROUND -->
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header white-fg"
|
||||
fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<!-- APP TITLE -->
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
|
||||
<button class="mr-16" mat-icon-button [routerLink]="'/apps/e-commerce/orders'">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
|
||||
<div fxLayout="column" fxLayoutAlign="start start"
|
||||
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">
|
||||
<div class="h2">
|
||||
Order {{order.reference}}
|
||||
</div>
|
||||
<div class="subtitle secondary-text">
|
||||
<span>from</span>
|
||||
<span>{{order.customer.firstName}} {{order.customer.lastName}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / APP TITLE -->
|
||||
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT CARD -->
|
||||
<div class="content-card mat-white-bg">
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="content">
|
||||
|
||||
<mat-tab-group>
|
||||
|
||||
<mat-tab label="Order Details">
|
||||
|
||||
<div class="order-details tab-content p-24" fusePerfectScrollbar>
|
||||
|
||||
<div class="section pb-48">
|
||||
|
||||
<div class="pb-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="m-0 mr-16">account_circle</mat-icon>
|
||||
<div class="h2 secondary-text">Customer</div>
|
||||
</div>
|
||||
|
||||
<div class="customer">
|
||||
<table class="simple">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Phone</th>
|
||||
<th>Company</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<img class="avatar" [src]="order.customer.avatar">
|
||||
<span class="name text-truncate">{{order.customer.firstName}} {{order.customer.lastName}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="email text-truncate">{{order.customer.email}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="phone text-truncate">{{order.customer.phone}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="company text-truncate">{{order.customer.company}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<mat-tab-group class="addresses">
|
||||
|
||||
<mat-tab label="Shipping Address">
|
||||
<div fxFlex fxLayout="column" *fuseIfOnDom>
|
||||
<div class="address h4 py-24">{{order.customer.shippingAddress.address}}</div>
|
||||
<agm-map class="w-100-p h-400" [zoom]="15"
|
||||
[latitude]="order.customer.shippingAddress.lat"
|
||||
[longitude]="order.customer.shippingAddress.lng">
|
||||
<agm-marker [latitude]="order.customer.shippingAddress.lat"
|
||||
[longitude]="order.customer.shippingAddress.lng">
|
||||
</agm-marker>
|
||||
</agm-map>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Invoice Address" fxLayout="column">
|
||||
<div fxFlex fxLayout="column" *fuseIfOnDom>
|
||||
<div class="address h4 py-24">{{order.customer.invoiceAddress.address}}</div>
|
||||
<agm-map class="w-100-p h-400" [zoom]="15"
|
||||
[latitude]="order.customer.invoiceAddress.lat"
|
||||
[longitude]="order.customer.invoiceAddress.lng">
|
||||
<agm-marker [latitude]="order.customer.invoiceAddress.lat"
|
||||
[longitude]="order.customer.invoiceAddress.lng">
|
||||
</agm-marker>
|
||||
</agm-map>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
<div class="section pb-48">
|
||||
|
||||
<div class="pb-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="m-0 mr-16">access_time</mat-icon>
|
||||
<div class="h2 secondary-text">Order Status</div>
|
||||
</div>
|
||||
|
||||
<table class="simple">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Status</th>
|
||||
<th>Updated On</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<tr *ngFor="let status of order.status">
|
||||
<td>
|
||||
<span class="status h6 p-4" [ngClass]="status.color">
|
||||
{{status.name}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>
|
||||
{{status.date | date}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<form class="update-status p-24"
|
||||
(ngSubmit)="updateStatus()"
|
||||
[formGroup]="statusForm"
|
||||
fxLayout="row" fxLayoutAlign="start center">
|
||||
|
||||
<mat-form-field class="mr-16" fxFlex>
|
||||
<mat-select formControlName="newStatus"
|
||||
placeholder="Select a status" required>
|
||||
<mat-option *ngFor="let status of orderStatuses"
|
||||
[value]="status.id">
|
||||
{{status.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-raised-button class="mat-accent"
|
||||
[disabled]="statusForm.invalid">
|
||||
Update Status
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section pb-48">
|
||||
|
||||
<div class="pb-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="m-0 mr-16">attach_money</mat-icon>
|
||||
<div class="h2 secondary-text">Payment</div>
|
||||
</div>
|
||||
|
||||
<table class="simple">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>TransactionID</th>
|
||||
<th>Payment Method</th>
|
||||
<th>Amount</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="text-truncate">
|
||||
{{order.payment.transactionId}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-truncate">
|
||||
{{order.payment.method}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-truncate">
|
||||
{{order.payment.amount}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-truncate">
|
||||
{{order.payment.date | date}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section pb-48">
|
||||
|
||||
<div class="pb-16" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="m-0 mr-16">local_shipping</mat-icon>
|
||||
<div class="h2 secondary-text">Shipping</div>
|
||||
</div>
|
||||
|
||||
<table class="simple">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tracking Code</th>
|
||||
<th>Carrier</th>
|
||||
<th>Weight</th>
|
||||
<th>Fee</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let shipping of order.shippingDetails">
|
||||
<td class="tracking-code">
|
||||
{{shipping.tracking}}
|
||||
</td>
|
||||
<td>
|
||||
{{shipping.carrier}}
|
||||
</td>
|
||||
<td>
|
||||
{{shipping.weight}}
|
||||
</td>
|
||||
<td>
|
||||
{{shipping.fee}}
|
||||
</td>
|
||||
<td>
|
||||
{{shipping.date}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Products">
|
||||
<div class="products tab-content p-24" fusePerfectScrollbar>
|
||||
<table class="simple">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Image</th>
|
||||
<th>Name</th>
|
||||
<th>Price</th>
|
||||
<th>Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="product-row"
|
||||
*ngFor="let product of order.products"
|
||||
[routerLink]="'/apps/e-commerce/products/'+product.id+'/'+product.handle">
|
||||
<td class="w-64">
|
||||
{{product.id}}
|
||||
</td>
|
||||
<td class="w-80">
|
||||
<img class="product-image" [src]="product.image">
|
||||
</td>
|
||||
<td>
|
||||
{{product.name}}
|
||||
</td>
|
||||
<td>
|
||||
{{product.price}}
|
||||
</td>
|
||||
<td>
|
||||
{{product.quantity}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Invoice">
|
||||
|
||||
<div class="invoice tab-content p-24" fusePerfectScrollbar>
|
||||
|
||||
<div id="invoice" class="compact page-layout blank" fxLayout="row" fusePerfectScrollbar>
|
||||
|
||||
<div class="invoice-container">
|
||||
|
||||
<!-- INVOICE -->
|
||||
<div class="card">
|
||||
|
||||
<div class="header">
|
||||
<div class="invoice-date">{{order.date}}</div>
|
||||
|
||||
<div fxLayout="row" fxLayoutAlign="space-between stretch">
|
||||
<div class="client">
|
||||
<div class="invoice-number" fxLayout="row" fxLayoutAlign="start center">
|
||||
<span class="title">INVOICE</span>
|
||||
<span class="number">{{order.reference}}</span>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="title">
|
||||
{{order.customer.firstName}}
|
||||
{{order.customer.lastName}}
|
||||
</div>
|
||||
<div class="address">{{order.customer.invoiceAddress}}</div>
|
||||
<div class="phone">{{order.customer.phone}}</div>
|
||||
<div class="email">{{order.customer.email}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="issuer mat-accent-bg" fxLayout="row" fxLayoutAlign="start center">
|
||||
<div class="logo">
|
||||
<img src="assets/images/logos/fuse.svg">
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="title">FUSE INC.</div>
|
||||
<div class="address">2810 Country Club Road Cranford, NJ 07016</div>
|
||||
<div class="phone">+66 123 455 87</div>
|
||||
<div class="email">hello@fuseinc.com</div>
|
||||
<div class="website">www.fuseinc.com</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<table class="simple invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PRODUCT</th>
|
||||
<th class="text-right">PRICE</th>
|
||||
<th class="text-right">QUANTITY</th>
|
||||
<th class="text-right">TOTAL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let product of order.products">
|
||||
<td>
|
||||
<div class="title">
|
||||
{{product.name}}
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{product.price | currency:'USD':'symbol'}}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{product.quantity}}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{product.total | currency:'USD':'symbol'}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="simple invoice-table-footer">
|
||||
<tbody>
|
||||
<tr class="subtotal">
|
||||
<td>SUBTOTAL</td>
|
||||
<td>{{order.subtotal | currency:'USD':'symbol'}}</td>
|
||||
</tr>
|
||||
<tr class="tax">
|
||||
<td>TAX</td>
|
||||
<td>{{order.tax | currency:'USD':'symbol'}}</td>
|
||||
</tr>
|
||||
<tr class="discount">
|
||||
<td>DISCOUNT</td>
|
||||
<td>-{{order.discount | currency:'USD':'symbol'}}</td>
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td>TOTAL</td>
|
||||
<td>{{order.total | currency:'USD':'symbol'}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="note">Please pay within 15 days. Thank you for your business.</div>
|
||||
<div fxLayout="row" fxLayoutAlign="start start">
|
||||
<div class="logo">
|
||||
<img src="assets/images/logos/fuse.svg">
|
||||
</div>
|
||||
<div class="small-note">
|
||||
In condimentum malesuada efficitur. Mauris volutpat placerat auctor. Ut ac congue dolor. Quisque
|
||||
scelerisque lacus sed feugiat fermentum. Cras aliquet facilisis pellentesque. Nunc hendrerit
|
||||
quam at leo commodo, a suscipit tellus dapibus. Etiam at felis volutpat est mollis lacinia.
|
||||
Mauris placerat sem sit amet velit mollis, in porttitor ex finibus. Proin eu nibh id libero
|
||||
tincidunt lacinia et eget eros.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / INVOICE -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
</mat-tab-group>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT -->
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT CARD -->
|
||||
|
||||
</div>
|
||||
<!-- / CENTER -->
|
||||
</div>
|
||||
395
src/app/main/content/apps/e-commerce/order/order.component.scss
Normal file
395
src/app/main/content/apps/e-commerce/order/order.component.scss
Normal file
@@ -0,0 +1,395 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
#order {
|
||||
|
||||
.header {
|
||||
|
||||
.subtitle {
|
||||
margin: 6px 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.mat-tab-group,
|
||||
.mat-tab-body-wrapper,
|
||||
.tab-content {
|
||||
flex: 1 1 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
flex: 1 1 auto;
|
||||
|
||||
&.products {
|
||||
|
||||
.product-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.invoice {
|
||||
|
||||
#invoice {
|
||||
|
||||
&.compact {
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
|
||||
.invoice-container {
|
||||
padding: 16px;
|
||||
|
||||
.card {
|
||||
width: 1020px;
|
||||
min-width: 1020px;
|
||||
max-width: 1020px;
|
||||
padding: 64px 88px;
|
||||
overflow: hidden;
|
||||
background: #FFFFFF;
|
||||
@include mat-elevation(7);
|
||||
|
||||
.header {
|
||||
|
||||
.invoice-date {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.client {
|
||||
|
||||
.invoice-number {
|
||||
font-size: 18px;
|
||||
padding-bottom: 2px;
|
||||
|
||||
.title {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.number {
|
||||
padding-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.due-date {
|
||||
font-size: 18px;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.title {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.date {
|
||||
padding-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.issuer {
|
||||
margin-right: -88px;
|
||||
padding-right: 66px;
|
||||
|
||||
.logo {
|
||||
width: 96px;
|
||||
padding: 0 8px;
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.invoice-table {
|
||||
margin-top: 64px;
|
||||
font-size: 15px;
|
||||
|
||||
thead {
|
||||
|
||||
tr {
|
||||
|
||||
th {
|
||||
|
||||
&:first-child {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
|
||||
tr {
|
||||
|
||||
td {
|
||||
|
||||
&:first-child {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
max-width: 360px;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-table-footer {
|
||||
margin: 32px 0 72px 0;
|
||||
|
||||
tr {
|
||||
|
||||
td {
|
||||
text-align: right;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
border-bottom: none;
|
||||
padding: 4px 8px;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
&.discount {
|
||||
|
||||
td {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
&.total {
|
||||
|
||||
td {
|
||||
padding: 24px 8px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
.note {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
// IE10 fix
|
||||
.logo, .small-note {
|
||||
-ms-flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 32px;
|
||||
min-width: 32px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.small-note {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PRINT STYLES */
|
||||
@media print {
|
||||
|
||||
/* Invoice Specific Styles */
|
||||
#invoice {
|
||||
|
||||
&.compact {
|
||||
|
||||
.invoice-container {
|
||||
padding: 0;
|
||||
|
||||
.card {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
|
||||
.header {
|
||||
|
||||
.invoice-date {
|
||||
margin-bottom: 16pt;
|
||||
}
|
||||
|
||||
.issuer {
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.invoice-table {
|
||||
margin-top: 16pt;
|
||||
|
||||
thead {
|
||||
|
||||
tr {
|
||||
|
||||
th {
|
||||
font-size: 10pt;
|
||||
max-width: 60pt;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
|
||||
tr {
|
||||
|
||||
td {
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin-top: 4pt;
|
||||
font-size: 9pt;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-table-footer {
|
||||
margin: 16pt 0;
|
||||
|
||||
tr {
|
||||
|
||||
td {
|
||||
font-size: 13pt;
|
||||
padding: 4pt 4pt;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.discount {
|
||||
|
||||
td {
|
||||
padding-bottom: 16pt;
|
||||
}
|
||||
}
|
||||
|
||||
&.total {
|
||||
|
||||
td {
|
||||
padding: 16pt 4pt 0 4pt;
|
||||
font-size: 16pt;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
|
||||
.note {
|
||||
font-size: 10pt;
|
||||
margin-bottom: 8pt;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-right: 8pt;
|
||||
}
|
||||
|
||||
.small-note {
|
||||
font-size: 8pt;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-body-content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mat-tab-label {
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Component, ElementRef, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { EcommerceOrderService } from './order.service';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/observable/merge';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/observable/fromEvent';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { Order } from './order.model';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Location } from '@angular/common';
|
||||
import { orderStatuses } from './order-statuses';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-e-commerce-order',
|
||||
templateUrl : './order.component.html',
|
||||
styleUrls : ['./order.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseEcommerceOrderComponent implements OnInit, OnDestroy
|
||||
{
|
||||
order = new Order();
|
||||
onOrderChanged: Subscription;
|
||||
statusForm: FormGroup;
|
||||
orderStatuses = orderStatuses;
|
||||
|
||||
constructor(
|
||||
private orderService: EcommerceOrderService,
|
||||
private formBuilder: FormBuilder,
|
||||
public snackBar: MatSnackBar,
|
||||
private location: Location
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// Subscribe to update order on changes
|
||||
this.onOrderChanged =
|
||||
this.orderService.onOrderChanged
|
||||
.subscribe(order => {
|
||||
this.order = new Order(order);
|
||||
});
|
||||
|
||||
this.statusForm = this.formBuilder.group({
|
||||
newStatus: ['']
|
||||
});
|
||||
}
|
||||
|
||||
updateStatus()
|
||||
{
|
||||
const newStatusId = Number.parseInt(this.statusForm.get('newStatus').value);
|
||||
|
||||
if ( !newStatusId )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const newStatus = this.orderStatuses.find((status) => {
|
||||
return status.id === newStatusId;
|
||||
});
|
||||
|
||||
newStatus['date'] = new Date().toString();
|
||||
|
||||
this.order.status.unshift(newStatus);
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onOrderChanged.unsubscribe();
|
||||
}
|
||||
}
|
||||
34
src/app/main/content/apps/e-commerce/order/order.model.ts
Normal file
34
src/app/main/content/apps/e-commerce/order/order.model.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
|
||||
export class Order
|
||||
{
|
||||
id: string;
|
||||
reference: string;
|
||||
subtotal: string;
|
||||
tax: string;
|
||||
discount: string;
|
||||
total: string;
|
||||
date: string;
|
||||
customer: any;
|
||||
products: any[];
|
||||
status: any[];
|
||||
payment: any;
|
||||
shippingDetails: any[];
|
||||
|
||||
constructor(order?)
|
||||
{
|
||||
order = order || {};
|
||||
this.id = order.id || FuseUtils.generateGUID();
|
||||
this.reference = order.reference || FuseUtils.generateGUID();
|
||||
this.subtotal = order.subtotal || 0;
|
||||
this.tax = order.tax || 0;
|
||||
this.discount = order.discount || 0;
|
||||
this.total = order.total || 0;
|
||||
this.date = order.date || '';
|
||||
this.customer = order.customer || {};
|
||||
this.products = order.products || [];
|
||||
this.status = order.status || [];
|
||||
this.payment = order.payment || {};
|
||||
this.shippingDetails = order.shippingDetails || [];
|
||||
}
|
||||
}
|
||||
75
src/app/main/content/apps/e-commerce/order/order.service.ts
Normal file
75
src/app/main/content/apps/e-commerce/order/order.service.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class EcommerceOrderService implements Resolve<any>
|
||||
{
|
||||
routeParams: any;
|
||||
order: any;
|
||||
onOrderChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
|
||||
this.routeParams = route.params;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getOrder()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getOrder(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/e-commerce-orders/' + this.routeParams.id)
|
||||
.subscribe((response: any) => {
|
||||
this.order = response;
|
||||
this.onOrderChanged.next(this.order);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
saveOrder(order)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.post('api/e-commerce-orders/' + order.id, order)
|
||||
.subscribe((response: any) => {
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
addOrder(order)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.post('api/e-commerce-orders/', order)
|
||||
.subscribe((response: any) => {
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<div id="orders" class="page-layout carded fullwidth" fusePerfectScrollbar>
|
||||
|
||||
<!-- TOP BACKGROUND -->
|
||||
<div class="top-bg mat-accent-bg"></div>
|
||||
<!-- / TOP BACKGROUND -->
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header white-fg"
|
||||
fxLayout="column" fxLayoutAlign="center center"
|
||||
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="space-between center">
|
||||
|
||||
<!-- APP TITLE -->
|
||||
<div class="logo"
|
||||
fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="logo-icon mr-16" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">shopping_basket</mat-icon>
|
||||
<span class="logo-text h1" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">Orders</span>
|
||||
</div>
|
||||
<!-- / APP TITLE -->
|
||||
|
||||
<!-- SEARCH -->
|
||||
<div class="search-input-wrapper ml-8 m-sm-0"
|
||||
fxFlex="1 0 auto" fxLayout="row" fxLayoutAlign="start center">
|
||||
<label for="search" class="mr-8">
|
||||
<mat-icon class="secondary-text">search</mat-icon>
|
||||
</label>
|
||||
<mat-form-field floatPlaceholder="never" fxFlex="1 0 auto">
|
||||
<input id="search" matInput #filter placeholder="Search">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- / SEARCH -->
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT CARD -->
|
||||
<div class="content-card mat-white-bg">
|
||||
|
||||
<mat-table class="orders-table"
|
||||
#table [dataSource]="dataSource"
|
||||
matSort
|
||||
[@animateStagger]="{value:'50'}"
|
||||
fusePerfectScrollbar>
|
||||
|
||||
<!-- ID Column -->
|
||||
<ng-container cdkColumnDef="id">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header>ID</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order">
|
||||
<p class="text-truncate">{{order.id}}</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Reference Column -->
|
||||
<ng-container cdkColumnDef="reference">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-sm>Reference</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order" fxHide fxShow.gt-sm>
|
||||
<p class="text-truncate">{{order.reference}}</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container cdkColumnDef="customer">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header>Customer</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order">
|
||||
<p class="text-truncate">
|
||||
{{order.customer.firstName}}
|
||||
{{order.customer.lastName}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Total Price Column -->
|
||||
<ng-container cdkColumnDef="total">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-md>Total</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order" fxHide fxShow.gt-md>
|
||||
<p class="total-price text-truncate">
|
||||
{{order.total | currency:'USD':'symbol'}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Payment Column -->
|
||||
<ng-container cdkColumnDef="payment">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-sm>Payment</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order" fxHide fxShow.gt-sm>
|
||||
<p class="text-truncate">
|
||||
{{order.payment.method}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Status Column -->
|
||||
<ng-container cdkColumnDef="status">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header >Status</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order">
|
||||
<p class="status text-truncate h6 p-4" [ngClass]="order.status[0].color">
|
||||
{{order.status[0].name}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Date Column -->
|
||||
<ng-container cdkColumnDef="date">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-sm>Date</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let order" fxHide fxShow.gt-sm>
|
||||
<p class="text-truncate">
|
||||
{{order.date}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
|
||||
<mat-row *cdkRowDef="let order; columns: displayedColumns;"
|
||||
class="order"
|
||||
matRipple
|
||||
[routerLink]="'/apps/e-commerce/orders/'+order.id">
|
||||
</mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator #paginator
|
||||
[length]="dataSource.filteredData.length"
|
||||
[pageIndex]="0"
|
||||
[pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 25, 100]">
|
||||
</mat-paginator>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT CARD -->
|
||||
</div>
|
||||
<!-- / CENTER -->
|
||||
</div>
|
||||
@@ -0,0 +1,73 @@
|
||||
:host {
|
||||
|
||||
.header {
|
||||
|
||||
.search-input-wrapper {
|
||||
max-width: 480px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-group,
|
||||
.mat-tab-body-wrapper,
|
||||
.tab-content{
|
||||
flex: 1 1 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
flex: 1 1 auto;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, .12);
|
||||
|
||||
.mat-header-row {
|
||||
min-height: 64px;
|
||||
}
|
||||
|
||||
.order {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 84px;
|
||||
}
|
||||
|
||||
.mat-cell {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-column-id {
|
||||
flex: 0 1 84px;
|
||||
}
|
||||
|
||||
.mat-column-image {
|
||||
flex: 0 1 84px;
|
||||
|
||||
.product-image {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border: 1px solid rgba(0, 0, 0, .12);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-column-buttons {
|
||||
flex: 0 1 80px;
|
||||
}
|
||||
|
||||
.quantity-indicator {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
|
||||
& + span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.active-icon {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
169
src/app/main/content/apps/e-commerce/orders/orders.component.ts
Normal file
169
src/app/main/content/apps/e-commerce/orders/orders.component.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { EcommerceOrdersService } from './orders.service';
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import { MatPaginator, MatSort } from '@angular/material';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/observable/merge';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/observable/fromEvent';
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-e-commerce-orders',
|
||||
templateUrl: './orders.component.html',
|
||||
styleUrls : ['./orders.component.scss'],
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseEcommerceOrdersComponent implements OnInit
|
||||
{
|
||||
dataSource: FilesDataSource | null;
|
||||
displayedColumns = ['id', 'reference', 'customer', 'total', 'payment', 'status', 'date'];
|
||||
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild('filter') filter: ElementRef;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
constructor(
|
||||
private ordersService: EcommerceOrdersService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.dataSource = new FilesDataSource(this.ordersService, this.paginator, this.sort);
|
||||
|
||||
Observable.fromEvent(this.filter.nativeElement, 'keyup')
|
||||
.debounceTime(150)
|
||||
.distinctUntilChanged()
|
||||
.subscribe(() => {
|
||||
if ( !this.dataSource )
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.dataSource.filter = this.filter.nativeElement.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FilesDataSource extends DataSource<any>
|
||||
{
|
||||
_filterChange = new BehaviorSubject('');
|
||||
_filteredDataChange = new BehaviorSubject('');
|
||||
|
||||
get filteredData(): any
|
||||
{
|
||||
return this._filteredDataChange.value;
|
||||
}
|
||||
|
||||
set filteredData(value: any)
|
||||
{
|
||||
this._filteredDataChange.next(value);
|
||||
}
|
||||
|
||||
get filter(): string
|
||||
{
|
||||
return this._filterChange.value;
|
||||
}
|
||||
|
||||
set filter(filter: string)
|
||||
{
|
||||
this._filterChange.next(filter);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private ordersService: EcommerceOrdersService,
|
||||
private _paginator: MatPaginator,
|
||||
private _sort: MatSort
|
||||
)
|
||||
{
|
||||
super();
|
||||
this.filteredData = this.ordersService.orders;
|
||||
}
|
||||
|
||||
/** Connect function called by the table to retrieve one stream containing the data to render. */
|
||||
connect(): Observable<any[]>
|
||||
{
|
||||
const displayDataChanges = [
|
||||
this.ordersService.onOrdersChanged,
|
||||
this._paginator.page,
|
||||
this._filterChange,
|
||||
this._sort.sortChange
|
||||
];
|
||||
return Observable.merge(...displayDataChanges).map(() => {
|
||||
let data = this.ordersService.orders.slice();
|
||||
|
||||
data = this.filterData(data);
|
||||
|
||||
this.filteredData = [...data];
|
||||
|
||||
data = this.sortData(data);
|
||||
|
||||
// Grab the page's slice of data.
|
||||
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
|
||||
return data.splice(startIndex, this._paginator.pageSize);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
filterData(data)
|
||||
{
|
||||
if ( !this.filter )
|
||||
{
|
||||
return data;
|
||||
}
|
||||
return FuseUtils.filterArrayByString(data, this.filter);
|
||||
}
|
||||
|
||||
sortData(data): any[]
|
||||
{
|
||||
if ( !this._sort.active || this._sort.direction === '' )
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
return data.sort((a, b) => {
|
||||
let propertyA: number | string = '';
|
||||
let propertyB: number | string = '';
|
||||
|
||||
switch ( this._sort.active )
|
||||
{
|
||||
case 'id':
|
||||
[propertyA, propertyB] = [a.id, b.id];
|
||||
break;
|
||||
case 'reference':
|
||||
[propertyA, propertyB] = [a.reference, b.reference];
|
||||
break;
|
||||
case 'customer':
|
||||
[propertyA, propertyB] = [a.customer.firstName, b.customer.firstName];
|
||||
break;
|
||||
case 'total':
|
||||
[propertyA, propertyB] = [a.total, b.total];
|
||||
break;
|
||||
case 'payment':
|
||||
[propertyA, propertyB] = [a.payment.method, b.payment.method];
|
||||
break;
|
||||
case 'status':
|
||||
[propertyA, propertyB] = [a.status[0].name, b.status[0].name];
|
||||
break;
|
||||
case 'date':
|
||||
[propertyA, propertyB] = [a.date, b.date];
|
||||
break;
|
||||
}
|
||||
|
||||
const valueA = isNaN(+propertyA) ? propertyA : +propertyA;
|
||||
const valueB = isNaN(+propertyB) ? propertyB : +propertyB;
|
||||
|
||||
return (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1);
|
||||
});
|
||||
}
|
||||
|
||||
disconnect()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class EcommerceOrdersService implements Resolve<any>
|
||||
{
|
||||
orders: any[];
|
||||
onOrdersChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getOrders()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getOrders(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/e-commerce-orders')
|
||||
.subscribe((response: any) => {
|
||||
this.orders = response;
|
||||
this.onOrdersChanged.next(this.orders);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
<div id="product" class="page-layout carded fullwidth" fusePerfectScrollbar>
|
||||
|
||||
<!-- TOP BACKGROUND -->
|
||||
<div class="top-bg mat-accent-bg"></div>
|
||||
<!-- / TOP BACKGROUND -->
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header white-fg" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
|
||||
<!-- APP TITLE -->
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
|
||||
<button class="mr-0 mr-sm-16" mat-icon-button [routerLink]="'/apps/e-commerce/products'">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</button>
|
||||
|
||||
<div class="product-image mr-8 mr-sm-16" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">
|
||||
<img *ngIf="product.images[0]" [src]="product.images[0].url">
|
||||
<img *ngIf="!product.images[0]" [src]="'assets/images/ecommerce/product-image-placeholder.png'">
|
||||
</div>
|
||||
|
||||
<div fxLayout="column" fxLayoutAlign="start start"
|
||||
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">
|
||||
<div class="h2" *ngIf="pageType ==='edit'">
|
||||
{{product.name}}
|
||||
</div>
|
||||
<div class="h2" *ngIf="pageType ==='new'">
|
||||
New Product
|
||||
</div>
|
||||
<div class="subtitle secondary-text">
|
||||
<span>Product Detail</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / APP TITLE -->
|
||||
|
||||
<button mat-raised-button
|
||||
class="save-product-button mat-white-bg mt-16 mt-sm-0"
|
||||
[disabled]="productForm.invalid"
|
||||
*ngIf="pageType ==='new'" (click)="addProduct()">
|
||||
<span>ADD</span>
|
||||
</button>
|
||||
|
||||
<button mat-raised-button
|
||||
class="save-product-button mat-white-bg mt-16 mt-sm-0"
|
||||
[disabled]="productForm.invalid || productForm.pristine"
|
||||
*ngIf="pageType ==='edit'" (click)="saveProduct()">
|
||||
<span>SAVE</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT CARD -->
|
||||
<div class="content-card mat-white-bg">
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="content">
|
||||
|
||||
<form name="productForm" [formGroup]="productForm" class="product w-100-p" fxLayout="column" fxFlex>
|
||||
|
||||
<mat-tab-group>
|
||||
|
||||
<mat-tab label="Basic Info">
|
||||
<div class="tab-content p-24" fusePerfectScrollbar>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="name"
|
||||
formControlName="name"
|
||||
placeholder="Product Name"
|
||||
required>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<textarea matInput
|
||||
name="description"
|
||||
formControlName="description"
|
||||
placeholder="Product Description"
|
||||
rows="5">
|
||||
</textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<h3 class="mb-0">Categories</h3>
|
||||
<mat-form-field class="w-100-p" floatPlaceholder="never">
|
||||
<mat-chip-list matPrefix #categoryList
|
||||
name="categories"
|
||||
formControlName="categories">
|
||||
|
||||
<mat-chip *ngFor="let category of product.categories"
|
||||
removable="true" (removed)="product.removeCategory(category)">
|
||||
{{category}}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
<input matInput
|
||||
matChipInputAddOnBlur="true"
|
||||
(matChipInputTokenEnd)="product.addCategory($event)"
|
||||
placeholder="Add category..."
|
||||
[matChipInputFor]="categoryList"/>
|
||||
</mat-form-field>
|
||||
|
||||
<h3 class="mb-0">Tags</h3>
|
||||
<mat-form-field class="w-100-p" floatPlaceholder="never">
|
||||
<mat-chip-list matPrefix #tagList
|
||||
name="tags"
|
||||
formControlName="tags">
|
||||
|
||||
<mat-chip *ngFor="let tag of product.tags"
|
||||
removable="true" (removed)="product.removeTag(tag)">
|
||||
{{tag}}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
<input matInput
|
||||
matChipInputAddOnBlur="true"
|
||||
(matChipInputTokenEnd)="product.addTag($event)"
|
||||
placeholder="Add tag..."
|
||||
[matChipInputFor]="tagList"/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Product Images">
|
||||
<div class="tab-content p-24" fusePerfectScrollbar>
|
||||
<div fxLayout="row" fxLayoutAlign="start start" fxLayoutWrap>
|
||||
|
||||
<div *ngIf="product.images.length === 0"
|
||||
class="product-image" fxlayout="row" fxLayoutAlign="center center">
|
||||
<img class="media" [src]="'assets/images/ecommerce/product-image-placeholder.png'">
|
||||
</div>
|
||||
|
||||
<div *ngFor="let image of product.images">
|
||||
<div *ngIf="product.images.length > 0"
|
||||
class="product-image" fxlayout="row" fxLayoutAlign="center center">
|
||||
<img class="media" [src]="image.url">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Pricing">
|
||||
<div class="tab-content p-24" fusePerfectScrollbar>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="priceTaxExcl"
|
||||
formControlName="priceTaxExcl"
|
||||
placeholder="Tax Excluded Price" type="number">
|
||||
<span matPrefix>$ </span>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="priceTaxIncl"
|
||||
formControlName="priceTaxIncl"
|
||||
placeholder="Tax Included Price" type="number">
|
||||
<span matPrefix>$ </span>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="taxRate"
|
||||
formControlName="taxRate"
|
||||
placeholder="Tax Rate" type="number">
|
||||
<span matPrefix>%</span>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="comparedPrice"
|
||||
formControlName="comparedPrice"
|
||||
placeholder="Compared Price" type="number">
|
||||
<span matPrefix>$ </span>
|
||||
<mat-hint align="start">Add a compare price to show next to the real price</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Inventory">
|
||||
<div class="tab-content p-24" fusePerfectScrollbar>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="sku"
|
||||
formControlName="sku"
|
||||
placeholder="SKU">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="quantity"
|
||||
formControlName="quantity"
|
||||
placeholder="Quantity" type="number">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab label="Shipping">
|
||||
<div class="tab-content p-24" fusePerfectScrollbar fxLayout="column">
|
||||
|
||||
<div class="py-16" fxLayout="row">
|
||||
<mat-form-field fxFlex>
|
||||
<input matInput
|
||||
name="Width"
|
||||
formControlName="width"
|
||||
placeholder="Width">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input matInput
|
||||
name="Height"
|
||||
formControlName="height"
|
||||
placeholder="Height">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input matInput
|
||||
name="Depth"
|
||||
formControlName="depth"
|
||||
placeholder="Depth">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="Weight"
|
||||
formControlName="weight"
|
||||
placeholder="Weight">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="w-100-p">
|
||||
<input matInput
|
||||
name="extraShippingFee"
|
||||
formControlName="extraShippingFee"
|
||||
placeholder="Extra Shipping Fee" type="number">
|
||||
<span matPrefix>$ </span>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
</mat-tab-group>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT -->
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT CARD -->
|
||||
|
||||
</div>
|
||||
<!-- / CENTER -->
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
#product {
|
||||
|
||||
.header {
|
||||
|
||||
.product-image {
|
||||
overflow: hidden;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 3px solid rgba(0, 0, 0, 0.12);
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 6px 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.mat-tab-group,
|
||||
.mat-tab-body-wrapper,
|
||||
.tab-content{
|
||||
flex: 1 1 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.mat-tab-body-content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mat-tab-label {
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
overflow: hidden;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
border: 3px solid rgba(0, 0, 0, 0.12);
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { Component, ElementRef, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { EcommerceProductService } from './product.service';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/observable/merge';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/observable/fromEvent';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { Product } from './product.model';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Location } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-e-commerce-product',
|
||||
templateUrl : './product.component.html',
|
||||
styleUrls : ['./product.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseEcommerceProductComponent implements OnInit, OnDestroy
|
||||
{
|
||||
product = new Product();
|
||||
onProductChanged: Subscription;
|
||||
pageType: string;
|
||||
productForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
private productService: EcommerceProductService,
|
||||
private formBuilder: FormBuilder,
|
||||
public snackBar: MatSnackBar,
|
||||
private location: Location
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
// Subscribe to update product on changes
|
||||
this.onProductChanged =
|
||||
this.productService.onProductChanged
|
||||
.subscribe(product => {
|
||||
|
||||
if ( product )
|
||||
{
|
||||
this.product = new Product(product);
|
||||
this.pageType = 'edit';
|
||||
}
|
||||
else
|
||||
{
|
||||
this.pageType = 'new';
|
||||
this.product = new Product();
|
||||
}
|
||||
|
||||
this.productForm = this.createProductForm();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
createProductForm()
|
||||
{
|
||||
return this.formBuilder.group({
|
||||
id : [this.product.id],
|
||||
name : [this.product.name],
|
||||
handle : [this.product.handle],
|
||||
description : [this.product.description],
|
||||
categories : [this.product.categories],
|
||||
tags : [this.product.tags],
|
||||
images : [this.product.images],
|
||||
priceTaxExcl : [this.product.priceTaxExcl],
|
||||
priceTaxIncl : [this.product.priceTaxIncl],
|
||||
taxRate : [this.product.taxRate],
|
||||
comparedPrice : [this.product.comparedPrice],
|
||||
quantity : [this.product.quantity],
|
||||
sku : [this.product.sku],
|
||||
width : [this.product.width],
|
||||
height : [this.product.height],
|
||||
depth : [this.product.depth],
|
||||
weight : [this.product.weight],
|
||||
extraShippingFee: [this.product.extraShippingFee],
|
||||
active : [this.product.active]
|
||||
});
|
||||
}
|
||||
|
||||
saveProduct()
|
||||
{
|
||||
const data = this.productForm.getRawValue();
|
||||
data.handle = FuseUtils.handleize(data.name);
|
||||
this.productService.saveProduct(data)
|
||||
.then(() => {
|
||||
|
||||
// Trigger the subscription with new data
|
||||
this.productService.onProductChanged.next(data);
|
||||
|
||||
// Show the success message
|
||||
this.snackBar.open('Product saved', 'OK', {
|
||||
verticalPosition: 'top',
|
||||
duration : 2000
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addProduct()
|
||||
{
|
||||
const data = this.productForm.getRawValue();
|
||||
data.handle = FuseUtils.handleize(data.name);
|
||||
this.productService.addProduct(data)
|
||||
.then(() => {
|
||||
|
||||
// Trigger the subscription with new data
|
||||
this.productService.onProductChanged.next(data);
|
||||
|
||||
// Show the success message
|
||||
this.snackBar.open('Product added', 'OK', {
|
||||
verticalPosition: 'top',
|
||||
duration : 2000
|
||||
});
|
||||
|
||||
// Change the location with new one
|
||||
this.location.go('apps/e-commerce/products/' + this.product.id + '/' + this.product.handle);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
this.onProductChanged.unsubscribe();
|
||||
}
|
||||
}
|
||||
110
src/app/main/content/apps/e-commerce/product/product.model.ts
Normal file
110
src/app/main/content/apps/e-commerce/product/product.model.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
import { MatChipInputEvent } from '@angular/material';
|
||||
|
||||
export class Product
|
||||
{
|
||||
id: string;
|
||||
name: string;
|
||||
handle: string;
|
||||
description: string;
|
||||
categories: string[];
|
||||
tags: string[];
|
||||
images: {
|
||||
default: boolean,
|
||||
id: string,
|
||||
url: string,
|
||||
type: string
|
||||
}[];
|
||||
priceTaxExcl: number;
|
||||
priceTaxIncl: number;
|
||||
taxRate: number;
|
||||
comparedPrice: number;
|
||||
quantity: number;
|
||||
sku: string;
|
||||
width: string;
|
||||
height: string;
|
||||
depth: string;
|
||||
weight: string;
|
||||
extraShippingFee: number;
|
||||
active: boolean;
|
||||
|
||||
constructor(product?)
|
||||
{
|
||||
product = product || {};
|
||||
this.id = product.id || FuseUtils.generateGUID();
|
||||
this.name = product.name || '';
|
||||
this.handle = product.handle || FuseUtils.handleize(this.name);
|
||||
this.description = product.description || '';
|
||||
this.categories = product.categories || [];
|
||||
this.tags = product.tags || [];
|
||||
this.images = product.images || [];
|
||||
this.priceTaxExcl = product.priceTaxExcl || 0;
|
||||
this.priceTaxIncl = product.priceTaxIncl || 0;
|
||||
this.taxRate = product.taxRate || 0;
|
||||
this.comparedPrice = product.comparedPrice || 0;
|
||||
this.quantity = product.quantity || 0;
|
||||
this.sku = product.sku || 0;
|
||||
this.width = product.width || 0;
|
||||
this.height = product.height || 0;
|
||||
this.depth = product.depth || 0;
|
||||
this.weight = product.weight || 0;
|
||||
this.extraShippingFee = product.extraShippingFee || 0;
|
||||
this.active = product.active || true;
|
||||
}
|
||||
|
||||
addCategory(event: MatChipInputEvent): void
|
||||
{
|
||||
const input = event.input;
|
||||
const value = event.value;
|
||||
|
||||
// Add category
|
||||
if ( value )
|
||||
{
|
||||
this.categories.push(value);
|
||||
}
|
||||
|
||||
// Reset the input value
|
||||
if ( input )
|
||||
{
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
removeCategory(category)
|
||||
{
|
||||
const index = this.categories.indexOf(category);
|
||||
|
||||
if ( index >= 0 )
|
||||
{
|
||||
this.categories.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
addTag(event: MatChipInputEvent): void
|
||||
{
|
||||
const input = event.input;
|
||||
const value = event.value;
|
||||
|
||||
// Add tag
|
||||
if ( value )
|
||||
{
|
||||
this.tags.push(value);
|
||||
}
|
||||
|
||||
// Reset the input value
|
||||
if ( input )
|
||||
{
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
removeTag(tag)
|
||||
{
|
||||
const index = this.tags.indexOf(tag);
|
||||
|
||||
if ( index >= 0 )
|
||||
{
|
||||
this.tags.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class EcommerceProductService implements Resolve<any>
|
||||
{
|
||||
routeParams: any;
|
||||
product: any;
|
||||
onProductChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
|
||||
this.routeParams = route.params;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getProduct()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getProduct(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
if ( this.routeParams.id === 'new' )
|
||||
{
|
||||
this.onProductChanged.next(false);
|
||||
resolve(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.http.get('api/e-commerce-products/' + this.routeParams.id)
|
||||
.subscribe((response: any) => {
|
||||
this.product = response;
|
||||
this.onProductChanged.next(this.product);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveProduct(product)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.post('api/e-commerce-products/' + product.id, product)
|
||||
.subscribe((response: any) => {
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
addProduct(product)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.post('api/e-commerce-products/', product)
|
||||
.subscribe((response: any) => {
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<div id="products" class="page-layout carded fullwidth" fusePerfectScrollbar>
|
||||
|
||||
<!-- TOP BACKGROUND -->
|
||||
<div class="top-bg mat-accent-bg"></div>
|
||||
<!-- / TOP BACKGROUND -->
|
||||
|
||||
<!-- CENTER -->
|
||||
<div class="center">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header white-fg"
|
||||
fxLayout="column" fxLayoutAlign="center center"
|
||||
fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="space-between center">
|
||||
|
||||
<!-- APP TITLE -->
|
||||
<div class="logo my-12 m-sm-0"
|
||||
fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="logo-icon mr-16" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">shopping_basket</mat-icon>
|
||||
<span class="logo-text h1" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">Products</span>
|
||||
</div>
|
||||
<!-- / APP TITLE -->
|
||||
|
||||
<!-- SEARCH -->
|
||||
<div class="search-input-wrapper mx-12 m-md-0"
|
||||
fxFlex="1 0 auto" fxLayout="row" fxLayoutAlign="start center">
|
||||
<label for="search" class="mr-8">
|
||||
<mat-icon class="secondary-text">search</mat-icon>
|
||||
</label>
|
||||
<mat-form-field floatPlaceholder="never" fxFlex="1 0 auto">
|
||||
<input id="search" matInput #filter placeholder="Search">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- / SEARCH -->
|
||||
|
||||
<button mat-raised-button
|
||||
[routerLink]="'/apps/e-commerce/products/new'"
|
||||
class="add-product-button mat-white-bg my-12 mt-sm-0">
|
||||
<span>ADD NEW PRODUCT</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<!-- CONTENT CARD -->
|
||||
<div class="content-card mat-white-bg">
|
||||
|
||||
<mat-table class="products-table"
|
||||
#table [dataSource]="dataSource"
|
||||
matSort
|
||||
[@animateStagger]="{value:'50'}"
|
||||
fusePerfectScrollbar>
|
||||
|
||||
<!-- ID Column -->
|
||||
<ng-container cdkColumnDef="id">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header>ID</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product">
|
||||
<p class="text-truncate">{{product.id}}</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Image Column -->
|
||||
<ng-container cdkColumnDef="image">
|
||||
<mat-header-cell *cdkHeaderCellDef></mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product">
|
||||
<img class="product-image"
|
||||
*ngIf="product.images[0]" [alt]="product.name"
|
||||
[src]="product.images[0].url"/>
|
||||
<img *ngIf="!product.images[0]" [src]="'assets/images/ecommerce/product-image-placeholder.png'">
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container cdkColumnDef="name">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header>Name</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product">
|
||||
<p class="text-truncate">{{product.name}}</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Category Column -->
|
||||
<ng-container cdkColumnDef="category">
|
||||
<mat-header-cell *cdkHeaderCellDef fxHide mat-sort-header fxShow.gt-md>Category</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product" fxHide fxShow.gt-md>
|
||||
<p class="category text-truncate">
|
||||
{{product.categories[0]}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Price Column -->
|
||||
<ng-container cdkColumnDef="price">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-xs>Price</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product" fxHide fxShow.gt-xs>
|
||||
<p class="price text-truncate">
|
||||
{{product.priceTaxIncl | currency:'USD':'symbol'}}
|
||||
</p>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Quantity Column -->
|
||||
<ng-container cdkColumnDef="quantity">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-sm>Quantity</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product" fxHide fxShow.gt-sm>
|
||||
|
||||
<span class="quantity-indicator text-truncate"
|
||||
[ngClass]="{'mat-red-500-bg':product.quantity <= 5, 'mat-amber-500-bg':product.quantity > 5 && product.quantity <= 25,'mat-green-600-bg':product.quantity > 25}">
|
||||
</span>
|
||||
<span>
|
||||
{{product.quantity}}
|
||||
</span>
|
||||
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Active Column -->
|
||||
<ng-container cdkColumnDef="active">
|
||||
<mat-header-cell *cdkHeaderCellDef mat-sort-header fxHide fxShow.gt-xs>Active</mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let product" fxHide fxShow.gt-xs>
|
||||
<mat-icon *ngIf="product.active" class="active-icon mat-green-600-bg s-16">check</mat-icon>
|
||||
<mat-icon *ngIf="!product.active" class="active-icon mat-red-500-bg s-16">close</mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
|
||||
<mat-row *cdkRowDef="let product; columns: displayedColumns;"
|
||||
class="product"
|
||||
matRipple
|
||||
[routerLink]="'/apps/e-commerce/products/'+product.id+'/'+product.handle">
|
||||
</mat-row>
|
||||
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator #paginator
|
||||
[length]="dataSource.filteredData.length"
|
||||
[pageIndex]="0"
|
||||
[pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 25, 100]">
|
||||
</mat-paginator>
|
||||
|
||||
</div>
|
||||
<!-- / CONTENT CARD -->
|
||||
</div>
|
||||
<!-- / CENTER -->
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
@import "src/app/core/scss/fuse";
|
||||
|
||||
:host {
|
||||
|
||||
.header {
|
||||
|
||||
.search-input-wrapper {
|
||||
max-width: 480px;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
height: 176px !important;
|
||||
min-height: 176px !important;
|
||||
max-height: 176px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bg {
|
||||
@include media-breakpoint-down(xs) {
|
||||
height: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.products-table {
|
||||
flex: 1 1 auto;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, .12);
|
||||
|
||||
.mat-header-row {
|
||||
min-height: 64px;
|
||||
}
|
||||
|
||||
.product {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 84px;
|
||||
}
|
||||
|
||||
.mat-cell {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-column-id {
|
||||
flex: 0 1 84px;
|
||||
}
|
||||
|
||||
.mat-column-image {
|
||||
flex: 0 1 84px;
|
||||
|
||||
.product-image {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border: 1px solid rgba(0, 0, 0, .12);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-column-buttons {
|
||||
flex: 0 1 80px;
|
||||
}
|
||||
|
||||
.quantity-indicator {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
|
||||
& + span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.active-icon {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { EcommerceProductsService } from './products.service';
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import { MatPaginator, MatSort } from '@angular/material';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import 'rxjs/add/operator/startWith';
|
||||
import 'rxjs/add/observable/merge';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/debounceTime';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
import 'rxjs/add/observable/fromEvent';
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-e-commerce-products',
|
||||
templateUrl: './products.component.html',
|
||||
styleUrls : ['./products.component.scss'],
|
||||
animations : fuseAnimations
|
||||
})
|
||||
export class FuseEcommerceProductsComponent implements OnInit
|
||||
{
|
||||
dataSource: FilesDataSource | null;
|
||||
displayedColumns = ['id', 'image', 'name', 'category', 'price', 'quantity', 'active'];
|
||||
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild('filter') filter: ElementRef;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
constructor(
|
||||
private productsService: EcommerceProductsService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.dataSource = new FilesDataSource(this.productsService, this.paginator, this.sort);
|
||||
Observable.fromEvent(this.filter.nativeElement, 'keyup')
|
||||
.debounceTime(150)
|
||||
.distinctUntilChanged()
|
||||
.subscribe(() => {
|
||||
if ( !this.dataSource )
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.dataSource.filter = this.filter.nativeElement.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class FilesDataSource extends DataSource<any>
|
||||
{
|
||||
_filterChange = new BehaviorSubject('');
|
||||
_filteredDataChange = new BehaviorSubject('');
|
||||
|
||||
get filteredData(): any
|
||||
{
|
||||
return this._filteredDataChange.value;
|
||||
}
|
||||
|
||||
set filteredData(value: any)
|
||||
{
|
||||
this._filteredDataChange.next(value);
|
||||
}
|
||||
|
||||
get filter(): string
|
||||
{
|
||||
return this._filterChange.value;
|
||||
}
|
||||
|
||||
set filter(filter: string)
|
||||
{
|
||||
this._filterChange.next(filter);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private productsService: EcommerceProductsService,
|
||||
private _paginator: MatPaginator,
|
||||
private _sort: MatSort
|
||||
)
|
||||
{
|
||||
super();
|
||||
this.filteredData = this.productsService.products;
|
||||
}
|
||||
|
||||
/** Connect function called by the table to retrieve one stream containing the data to render. */
|
||||
connect(): Observable<any[]>
|
||||
{
|
||||
const displayDataChanges = [
|
||||
this.productsService.onProductsChanged,
|
||||
this._paginator.page,
|
||||
this._filterChange,
|
||||
this._sort.sortChange
|
||||
];
|
||||
|
||||
return Observable.merge(...displayDataChanges).map(() => {
|
||||
let data = this.productsService.products.slice();
|
||||
|
||||
data = this.filterData(data);
|
||||
|
||||
this.filteredData = [...data];
|
||||
|
||||
data = this.sortData(data);
|
||||
|
||||
// Grab the page's slice of data.
|
||||
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
|
||||
return data.splice(startIndex, this._paginator.pageSize);
|
||||
});
|
||||
}
|
||||
|
||||
filterData(data)
|
||||
{
|
||||
if ( !this.filter )
|
||||
{
|
||||
return data;
|
||||
}
|
||||
return FuseUtils.filterArrayByString(data, this.filter);
|
||||
}
|
||||
|
||||
sortData(data): any[]
|
||||
{
|
||||
if ( !this._sort.active || this._sort.direction === '' )
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
return data.sort((a, b) => {
|
||||
let propertyA: number | string = '';
|
||||
let propertyB: number | string = '';
|
||||
|
||||
switch ( this._sort.active )
|
||||
{
|
||||
case 'id':
|
||||
[propertyA, propertyB] = [a.id, b.id];
|
||||
break;
|
||||
case 'name':
|
||||
[propertyA, propertyB] = [a.name, b.name];
|
||||
break;
|
||||
case 'categories':
|
||||
[propertyA, propertyB] = [a.categories[0], b.categories[0]];
|
||||
break;
|
||||
case 'price':
|
||||
[propertyA, propertyB] = [a.priceTaxIncl, b.priceTaxIncl];
|
||||
break;
|
||||
case 'quantity':
|
||||
[propertyA, propertyB] = [a.quantity, b.quantity];
|
||||
break;
|
||||
case 'active':
|
||||
[propertyA, propertyB] = [a.active, b.active];
|
||||
break;
|
||||
}
|
||||
|
||||
const valueA = isNaN(+propertyA) ? propertyA : +propertyA;
|
||||
const valueB = isNaN(+propertyB) ? propertyB : +propertyB;
|
||||
|
||||
return (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1);
|
||||
});
|
||||
}
|
||||
|
||||
disconnect()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class EcommerceProductsService implements Resolve<any>
|
||||
{
|
||||
products: any[];
|
||||
onProductsChanged: BehaviorSubject<any> = new BehaviorSubject({});
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @param {RouterStateSnapshot} state
|
||||
* @returns {Observable<any> | Promise<any> | any}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any
|
||||
{
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Promise.all([
|
||||
this.getProducts()
|
||||
]).then(
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getProducts(): Promise<any>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
this.http.get('api/e-commerce-products')
|
||||
.subscribe((response: any) => {
|
||||
this.products = response;
|
||||
this.onProductsChanged.next(this.products);
|
||||
resolve(response);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<ng-container cdkColumnDef="icon">
|
||||
<mat-header-cell *cdkHeaderCellDef fxFlex="64px"></mat-header-cell>
|
||||
<mat-cell *cdkCellDef="let row" fxFlex="64px">
|
||||
<mat-icon class="type-icon" [class]="row.type"></mat-icon>
|
||||
<mat-icon class="type-icon" [ngClass]="row.type"></mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<!-- / CENTER -->
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav right-sidenav mat-sidenav-opened" align="end" opened="true" mode="side"
|
||||
<mat-sidenav class="sidenav right-sidenav " align="end" opened="true" mode="side"
|
||||
fuseMatSidenavHelper="file-manager-right-sidenav" mat-is-locked-open="gt-md">
|
||||
<fuse-file-manager-details-sidenav></fuse-file-manager-details-sidenav>
|
||||
</mat-sidenav>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*fuseIfOnDom [@animate]="{value:'*',params:{delay:'200ms'}}">
|
||||
|
||||
<div class="preview file-icon" fxLayout="row" fxLayoutAlign="center center">
|
||||
<mat-icon class="type-icon s-48" [class]="selected.type"></mat-icon>
|
||||
<mat-icon class="type-icon s-48" [ngClass]="selected.type"></mat-icon>
|
||||
</div>
|
||||
|
||||
<div class="offline-switch">
|
||||
|
||||
14
src/app/main/content/apps/mail/i18n/en.ts
Normal file
14
src/app/main/content/apps/mail/i18n/en.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const locale = {
|
||||
lang: 'en',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE' : 'COMPOSE',
|
||||
'FOLDERS' : 'FOLDERS',
|
||||
'FILTERS' : 'FILTERS',
|
||||
'LABELS' : 'LABELS',
|
||||
'NO_MESSAGES' : 'There are no messages!',
|
||||
'SELECT_A_MESSAGE_TO_READ': 'Select a message to read',
|
||||
'SEARCH_PLACEHOLDER': 'Search for an e-mail or contact'
|
||||
}
|
||||
}
|
||||
};
|
||||
14
src/app/main/content/apps/mail/i18n/tr.ts
Normal file
14
src/app/main/content/apps/mail/i18n/tr.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const locale = {
|
||||
lang: 'tr',
|
||||
data: {
|
||||
'MAIL': {
|
||||
'COMPOSE' : 'YENİ E-POSTA',
|
||||
'FOLDERS' : 'KLASÖRLER',
|
||||
'FILTERS' : 'FİLTRELER',
|
||||
'LABELS' : 'ETİKETLER',
|
||||
'NO_MESSAGES' : 'Mesajiniz bulunmamakta!',
|
||||
'SELECT_A_MESSAGE_TO_READ': 'Okumak için bir mesaj seçin',
|
||||
'SEARCH_PLACEHOLDER' : 'E-mail yada bir kişi arayın'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,10 @@
|
||||
<div *ngIf="!mail" fxLayout="column" fxLayoutAlign="center center" fxFlex>
|
||||
<mat-icon class="s-128 mb-16 select-message-icon" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'300ms',scale:'0.2'}}">email</mat-icon>
|
||||
<span class="select-message-text hint-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'400ms'}}">Select a message to read</span>
|
||||
<mat-icon class="s-128 mb-16 select-message-icon" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'300ms',scale:'0.2'}}">
|
||||
email
|
||||
</mat-icon>
|
||||
<span class="select-message-text hint-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'400ms'}}">
|
||||
<span>{{ 'MAIL.SELECT_A_MESSAGE_TO_READ' | translate }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="mail">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div *ngIf="mails.length === 0" fxLayout="column" fxLayoutAlign="center center" fxFlexFill>
|
||||
<span class="no-messages-text hint-text">There are no messages!</span>
|
||||
<span class="no-messages-text hint-text">{{ 'MAIL.NO_MESSAGES' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mail-list" *fuseIfOnDom [@animateStagger]="{value:'50'}">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<mat-sidenav-container>
|
||||
|
||||
<!-- SIDENAV -->
|
||||
<mat-sidenav class="sidenav mat-sidenav-opened" align="start" mode="side" opened="true"
|
||||
<mat-sidenav class="sidenav" align="start" mode="side" opened="true"
|
||||
fuseMatSidenavHelper="carded-left-sidenav" mat-is-locked-open="gt-md">
|
||||
<fuse-mail-main-sidenav></fuse-mail-main-sidenav>
|
||||
</mat-sidenav>
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<div class="search mat-white-bg" flex fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon>search</mat-icon>
|
||||
<input [formControl]="searchInput" placeholder="Search for an e-mail or contact" fxFlex>
|
||||
<input [formControl]="searchInput" [placeholder]="'MAIL.SEARCH_PLACEHOLDER' | translate" fxFlex>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ import { MailService } from './mail.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { Mail } from './mail.model';
|
||||
import { FuseTranslationLoaderService } from '../../../../core/services/translation-loader.service';
|
||||
import { locale as english } from './i18n/en';
|
||||
import { locale as turkish } from './i18n/tr';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-mail',
|
||||
@@ -25,9 +28,13 @@ export class FuseMailComponent implements OnInit, OnDestroy
|
||||
onLabelsChanged: Subscription;
|
||||
onCurrentMailChanged: Subscription;
|
||||
|
||||
constructor(private mailService: MailService)
|
||||
constructor(
|
||||
private mailService: MailService,
|
||||
private translationLoader: FuseTranslationLoaderService
|
||||
)
|
||||
{
|
||||
this.searchInput = new FormControl('');
|
||||
this.translationLoader.loadTranslations(english, turkish);
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- SIDENAV HEADER -->
|
||||
<div fxLayout="column" fxLayoutAlign="space-between start"
|
||||
class="header p-24 pb-4 mat-accent-bg" class.gt-md="header p-24 pb-4 white-fg">
|
||||
class="header p-24 pb-4" ngClass="mat-accent-bg" ngClass.gt-md="white-fg">
|
||||
|
||||
<div class="logo" fxFlex fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="logo-icon s-32" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">mail</mat-icon>
|
||||
@@ -30,13 +30,13 @@
|
||||
class="mat-accent compose-dialog-button"
|
||||
(click)="composeDialog()"
|
||||
aria-label="Compose">
|
||||
COMPOSE
|
||||
{{ 'MAIL.COMPOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
|
||||
<div class="nav-subheader">FOLDERS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.FOLDERS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let folder of folders">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/' + folder.handle" routerLinkActive="active">
|
||||
@@ -45,7 +45,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-subheader">FILTERS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.FILTERS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let filter of filters">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/filter/' + filter.handle" routerLinkActive="active">
|
||||
@@ -54,7 +54,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-subheader">LABELS</div>
|
||||
<div class="nav-subheader">{{ 'MAIL.LABELS' | translate }}</div>
|
||||
|
||||
<div class="nav-item" *ngFor="let label of labels">
|
||||
<a class="nav-link" matRipple [routerLink]="'/apps/mail/label/' + label.handle" routerLinkActive="active">
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<div id="board">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="header mat-accent-bg p-16 p-mat-24" [class]="'mat-'+board.settings.color+'-bg'" fxLayout="column">
|
||||
<div class="header mat-accent-bg p-16 p-mat-24" [ngClass]="'mat-'+board.settings.color+'-bg'" fxLayout="column">
|
||||
|
||||
<div class="header-content" fxLayout="row" fxLayoutAlign="space-between" fxFlex="1 0 auto" fxLayoutWrap>
|
||||
|
||||
<!-- BOARD SELECTION BUTTON -->
|
||||
<div fxLayout="row" fxLayoutAlign="center center" fxFlexOrder="2" fxFlexOrder.gt-xs="1">
|
||||
<button mat-raised-button class="mat-accent header-boards-button"
|
||||
[class]="'mat-'+board.settings.color+'-700-bg'"
|
||||
[ngClass]="'mat-'+board.settings.color+'-700-bg'"
|
||||
routerLink="/apps/scrumboard/boards"
|
||||
aria-label="boards button">
|
||||
<mat-icon>assessment</mat-icon>
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<!-- / HEADER -->
|
||||
|
||||
<div fxFlex class="board-content-wrapper p-16 p-mat-24" [class]="board.settings.color+'-100-bg'">
|
||||
<div fxFlex class="board-content-wrapper p-16 p-mat-24" [ngClass]="board.settings.color+'-100-bg'">
|
||||
|
||||
<!-- BOARD -->
|
||||
<div class="board-content ngx-dnd-container p-16 p-mat-24" fxLayout="row"
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<!-- CHECKLIST -->
|
||||
<div class="due-date " fxFlex="0 1 auto">
|
||||
|
||||
<button mat-icon-button class="" [matMenuTriggerFor]="checklistMenu" #checklistMenuTrigger="matMenuTrigger" (onMenuOpen)="onChecklistMenuOpen()">
|
||||
<button mat-icon-button class="" [matMenuTriggerFor]="checklistMenu" #checklistMenuTrigger="matMenuTrigger" (menuOpened)="onChecklistMenuOpen()">
|
||||
<mat-icon>check_box</mat-icon>
|
||||
</button>
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<mat-chip-list class="label-chips">
|
||||
<mat-chip class="label-chip mb-4"
|
||||
*ngFor="let labelId of card.idLabels"
|
||||
[class]="board.labels | getById:labelId:'color'"
|
||||
[ngClass]="board.labels | getById:labelId:'color'"
|
||||
fxLayout="row" fxLayoutAlign="start center">
|
||||
<span>{{board.labels|getById:labelId:'name'}}</span>
|
||||
<mat-icon class="ml-8 s-16 chip-remove" (click)="toggleInArray(labelId, card.idLabels);updateCard()">close</mat-icon>
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
.mat-form-field-flex {
|
||||
align-items: center;
|
||||
|
||||
.mat-form-field-infix {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-input-element {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div [ngSwitch]="labelsMenuView" class="views" (click)="$event.stopPropagation()">
|
||||
|
||||
<div class="view " *ngSwitchCase="'labels'" [@slideInLeft] fxFlex fxLayout="column">
|
||||
<div class="view" *ngSwitchCase="'labels'" fxFlex fxLayout="column">
|
||||
|
||||
<div class="header mb-12 pb-4 px-8" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="header" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div>Labels</div>
|
||||
<button mat-button (click)="labelsMenuView ='add'">
|
||||
<mat-icon class="s-16">add</mat-icon>
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
<div fxFlex fxLayout="column" fusePerfectScrollbar>
|
||||
|
||||
<div class="label pl-12 mx-8 mb-8" *ngFor="let label of board.labels" fxFlex="0 0 auto" fxLayout="row" fxFlexAlign="space-between center"
|
||||
[class]="label.color">
|
||||
<div class="label" *ngFor="let label of board.labels" fxFlex="0 0 auto" fxLayout="row" fxFlexAlign="space-between center"
|
||||
[ngClass]="label.color">
|
||||
|
||||
<mat-checkbox fxFlex fxLayout="row" fxLayoutAlign="start center" [checked]="card.idLabels.indexOf(label.id) > -1"
|
||||
(change)="toggleInArray(label.id, card.idLabels);cardLabelsChanged()">
|
||||
@@ -27,16 +27,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="view px-8" *ngSwitchCase="'edit'" [@slideInRight] fxFlex fxLayout="column">
|
||||
<div class="view edit" *ngSwitchCase="'edit'" fxFlex fxLayout="column">
|
||||
|
||||
<div class="header mb-12 pb-4" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div>Edit Label</div>
|
||||
<div class="header" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button mat-icon-button (click)="labelsMenuView ='labels'">
|
||||
<mat-icon class="s-16">arrow_back</mat-icon>
|
||||
</button>
|
||||
<div>Edit Label</div>
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="content" fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="Name" [(ngModel)]="selectedLabel.name" (change)="onLabelChange()">
|
||||
</mat-form-field>
|
||||
@@ -46,26 +46,26 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="view px-8" *ngSwitchCase="'add'" [@slideInRight] fxFlex fxLayout="column">
|
||||
<div class="view add" *ngSwitchCase="'add'" fxFlex fxLayout="column">
|
||||
|
||||
<div class="header mb-12 pb-4" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div>Add Label</div>
|
||||
<div class="header" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button mat-icon-button (click)="labelsMenuView ='labels'">
|
||||
<mat-icon class="s-16">arrow_back</mat-icon>
|
||||
</button>
|
||||
<div>Add Label</div>
|
||||
</div>
|
||||
|
||||
<form (submit)="addNewLabel()" #newLabelForm="ngForm" fxFlex fxLayout="column" fxLayoutAlign="start end">
|
||||
|
||||
<div class="w-100-p" fxFlex="0 1 auto" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div fxFlex="0 1 auto" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-form-field fxFlex>
|
||||
<input matInput placeholder="Name" [(ngModel)]="newLabel.name" name="labelName" required>
|
||||
</mat-form-field>
|
||||
|
||||
<fuse-material-color-picker [(selectedClass)]="newLabel.color" name="labelColor" class="ml-8"></fuse-material-color-picker>
|
||||
<fuse-material-color-picker class="ml-8" [(selectedClass)]="newLabel.color" name="labelColor"></fuse-material-color-picker>
|
||||
</div>
|
||||
|
||||
<button mat-raised-button class="mat-accent mt-16" [disabled]="!newLabelForm.valid">Add</button>
|
||||
<button mat-raised-button class="mat-accent mt-16" [disabled]="!newLabelForm.valid">ADD NEW LABEL</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,37 @@
|
||||
|
||||
> .header {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding: 4px 8px 8px 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin: 0 8px 8px 8px;
|
||||
padding: 4px 4px 4px 16px;
|
||||
}
|
||||
|
||||
&.edit,
|
||||
&.add {
|
||||
|
||||
> .header {
|
||||
padding: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 0 16px 8px 16px;
|
||||
|
||||
.mat-form-field-infix {
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 8px 16px 8px 16px;
|
||||
|
||||
.mat-form-field-infix {
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="view" *ngSwitchCase="'main'" [@slideInLeft]>
|
||||
|
||||
<!-- SIDENAV HEADER -->
|
||||
<div class="header mat-accent-bg px-24" [class]="'mat-'+board.settings.color+'-bg'" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div class="header mat-accent-bg px-24" [ngClass]="'mat-'+board.settings.color+'-bg'" fxLayout="column" fxLayoutAlign="center center">
|
||||
<div>Settings</div>
|
||||
</div>
|
||||
<!-- / SIDENAV HEADER -->
|
||||
@@ -58,7 +58,7 @@
|
||||
<div class="view" *ngSwitchCase="'board-color'" [@slideInRight]>
|
||||
|
||||
<!-- SIDENAV HEADER -->
|
||||
<div class="header mat-accent-bg px-24" [class]="'mat-'+board.settings.color+'-bg'" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div class="header mat-accent-bg px-24" [ngClass]="'mat-'+board.settings.color+'-bg'" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<div>Background Color</div>
|
||||
<button mat-icon-button (click)="view ='main'">
|
||||
<mat-icon class="s-16">arrow_back</mat-icon>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- SIDENAV HEADER -->
|
||||
<div fxLayout="column" fxLayoutAlign="space-between start"
|
||||
class="header p-24 pb-4 mat-accent-bg" class.gt-md="header p-24 pb-4 white-fg">
|
||||
class="header p-24 pb-4" ngClass="mat-accent-bg" ngClass.gt-md="white-fg">
|
||||
<div class="logo" fxFlex fxLayout="row" fxLayoutAlign="start center">
|
||||
<mat-icon class="logo-icon s-32" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'50ms',scale:'0.2'}}">check_box</mat-icon>
|
||||
<span class="logo-text" *fuseIfOnDom [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">To-do</span>
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
name="title"
|
||||
formControlName="title"
|
||||
placeholder="Title"
|
||||
matTextareaAutosize
|
||||
matAutosizeMinRows="1"
|
||||
matAutosizeMaxRows="2"
|
||||
required>
|
||||
</textarea>
|
||||
</mat-form-field>
|
||||
@@ -96,10 +93,7 @@
|
||||
name="notes"
|
||||
formControlName="notes"
|
||||
placeholder="Notes"
|
||||
maxlength="500"
|
||||
matTextareaAutosize
|
||||
matAutosizeMinRows="1"
|
||||
matAutosizeMaxRows="6">
|
||||
maxlength="500">
|
||||
</textarea>
|
||||
<mat-hint align="end">{{notes.value.length}} / 500</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
padding: 24px;
|
||||
|
||||
.todo-header {
|
||||
padding-bottom: 24px;
|
||||
margin-bottom: 8px;
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
|
||||
.actions {
|
||||
min-width: 88px;
|
||||
@@ -19,6 +18,7 @@
|
||||
}
|
||||
|
||||
.todo-content {
|
||||
padding: 24px;
|
||||
|
||||
.title {
|
||||
font-size: 17px;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Subscription } from 'rxjs/Subscription';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FuseUtils } from '../../../../../core/fuseUtils';
|
||||
import { fuseAnimations } from '../../../../../core/animations';
|
||||
import 'rxjs/add/operator/distinctUntilChanged';
|
||||
|
||||
@Component({
|
||||
selector : 'fuse-todo-details',
|
||||
@@ -48,12 +49,13 @@ export class FuseTodoDetailsComponent implements OnInit, OnDestroy
|
||||
|
||||
this.todoForm = this.createTodoForm();
|
||||
|
||||
this.onFormChange = this.todoForm.valueChanges
|
||||
.debounceTime(500)
|
||||
.distinctUntilChanged()
|
||||
.subscribe(data => {
|
||||
this.todoService.updateTodo(data);
|
||||
});
|
||||
this.onFormChange =
|
||||
this.todoForm.valueChanges
|
||||
.debounceTime(500)
|
||||
.distinctUntilChanged()
|
||||
.subscribe(data => {
|
||||
this.todoService.updateTodo(data);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -65,15 +67,16 @@ export class FuseTodoDetailsComponent implements OnInit, OnDestroy
|
||||
});
|
||||
|
||||
// Subscribe to update on tag change
|
||||
this.onNewTodoClicked = this.todoService.onNewTodoClicked
|
||||
.subscribe(() => {
|
||||
this.todo = new Todo({});
|
||||
this.todo.id = FuseUtils.generateGUID();
|
||||
this.formType = 'new';
|
||||
this.todoForm = this.createTodoForm();
|
||||
this.focusTitleField();
|
||||
this.todoService.onCurrentTodoChanged.next([this.todo, 'new']);
|
||||
});
|
||||
this.onNewTodoClicked =
|
||||
this.todoService.onNewTodoClicked
|
||||
.subscribe(() => {
|
||||
this.todo = new Todo({});
|
||||
this.todo.id = FuseUtils.generateGUID();
|
||||
this.formType = 'new';
|
||||
this.todoForm = this.createTodoForm();
|
||||
this.focusTitleField();
|
||||
this.todoService.onCurrentTodoChanged.next([this.todo, 'new']);
|
||||
});
|
||||
}
|
||||
|
||||
focusTitleField()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</mat-icon>
|
||||
|
||||
<mat-checkbox [(ngModel)]="selected" (ngModelChange)="onSelectedChange()"
|
||||
class="mr-16" fxFlex="0 1 auto">
|
||||
class="mr-16" fxFlex="0 1 auto" (click)="$event.stopPropagation()">
|
||||
</mat-checkbox>
|
||||
|
||||
<div fxLayout="row" fxLayoutAlign="start center" fxFlex>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user