mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-01-10 04:25:08 +00:00
Merge branch 'master' of https://github.com/withinpixels/fuse2
This commit is contained in:
commit
786180958d
918
package-lock.json
generated
918
package-lock.json
generated
|
@ -1299,7 +1299,6 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"anymatch": "1.3.0",
|
"anymatch": "1.3.0",
|
||||||
"async-each": "1.0.1",
|
"async-each": "1.0.1",
|
||||||
"fsevents": "1.1.2",
|
|
||||||
"glob-parent": "2.0.0",
|
"glob-parent": "2.0.0",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
"is-binary-path": "1.0.1",
|
"is-binary-path": "1.0.1",
|
||||||
|
@ -3443,905 +3442,6 @@
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"fsevents": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"nan": "2.6.2",
|
|
||||||
"node-pre-gyp": "0.6.36"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"abbrev": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"ajv": {
|
|
||||||
"version": "4.11.8",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"co": "4.6.0",
|
|
||||||
"json-stable-stringify": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"aproba": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"are-we-there-yet": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"delegates": "1.0.0",
|
|
||||||
"readable-stream": "2.2.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"asn1": {
|
|
||||||
"version": "0.2.3",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"asynckit": {
|
|
||||||
"version": "0.4.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"aws-sign2": {
|
|
||||||
"version": "0.6.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"aws4": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
|
||||||
"version": "0.4.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"bcrypt-pbkdf": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"tweetnacl": "0.14.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"block-stream": {
|
|
||||||
"version": "0.0.9",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"inherits": "2.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"boom": {
|
|
||||||
"version": "2.10.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"hoek": "2.16.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
|
||||||
"version": "1.1.7",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "0.4.2",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"buffer-shims": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"caseless": {
|
|
||||||
"version": "0.12.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"co": {
|
|
||||||
"version": "4.6.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"code-point-at": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"combined-stream": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"delayed-stream": "1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"console-control-strings": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"core-util-is": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"cryptiles": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"boom": "2.10.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dashdash": {
|
|
||||||
"version": "1.14.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"assert-plus": "1.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"version": "2.6.8",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"ms": "2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"deep-extend": {
|
|
||||||
"version": "0.4.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"delayed-stream": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"delegates": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"ecc-jsbn": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"jsbn": "0.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extend": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"extsprintf": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"forever-agent": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"form-data": {
|
|
||||||
"version": "2.1.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "0.4.0",
|
|
||||||
"combined-stream": "1.0.5",
|
|
||||||
"mime-types": "2.1.15"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"fstream": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "4.1.11",
|
|
||||||
"inherits": "2.0.3",
|
|
||||||
"mkdirp": "0.5.1",
|
|
||||||
"rimraf": "2.6.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fstream-ignore": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"fstream": "1.0.11",
|
|
||||||
"inherits": "2.0.3",
|
|
||||||
"minimatch": "3.0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gauge": {
|
|
||||||
"version": "2.7.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"aproba": "1.1.1",
|
|
||||||
"console-control-strings": "1.1.0",
|
|
||||||
"has-unicode": "2.0.1",
|
|
||||||
"object-assign": "4.1.1",
|
|
||||||
"signal-exit": "3.0.2",
|
|
||||||
"string-width": "1.0.2",
|
|
||||||
"strip-ansi": "3.0.1",
|
|
||||||
"wide-align": "1.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"getpass": {
|
|
||||||
"version": "0.1.7",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"assert-plus": "1.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"glob": {
|
|
||||||
"version": "7.1.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"fs.realpath": "1.0.0",
|
|
||||||
"inflight": "1.0.6",
|
|
||||||
"inherits": "2.0.3",
|
|
||||||
"minimatch": "3.0.4",
|
|
||||||
"once": "1.4.0",
|
|
||||||
"path-is-absolute": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"graceful-fs": {
|
|
||||||
"version": "4.1.11",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"har-schema": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"har-validator": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"ajv": "4.11.8",
|
|
||||||
"har-schema": "1.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"has-unicode": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"hawk": {
|
|
||||||
"version": "3.1.3",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"boom": "2.10.1",
|
|
||||||
"cryptiles": "2.0.5",
|
|
||||||
"hoek": "2.16.3",
|
|
||||||
"sntp": "1.0.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hoek": {
|
|
||||||
"version": "2.16.3",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"http-signature": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"assert-plus": "0.2.0",
|
|
||||||
"jsprim": "1.4.0",
|
|
||||||
"sshpk": "1.13.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"once": "1.4.0",
|
|
||||||
"wrappy": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ini": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"is-fullwidth-code-point": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"number-is-nan": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-typedarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"isarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"isstream": {
|
|
||||||
"version": "0.1.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"jodid25519": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"jsbn": "0.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsbn": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"json-schema": {
|
|
||||||
"version": "0.2.3",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"json-stable-stringify": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"jsonify": "0.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"json-stringify-safe": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"jsonify": {
|
|
||||||
"version": "0.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"jsprim": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"assert-plus": "1.0.0",
|
|
||||||
"extsprintf": "1.0.2",
|
|
||||||
"json-schema": "0.2.3",
|
|
||||||
"verror": "1.3.6"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mime-db": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"mime-types": {
|
|
||||||
"version": "2.1.15",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"mime-db": "1.27.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minimatch": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "1.1.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minimist": {
|
|
||||||
"version": "0.0.8",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"mkdirp": {
|
|
||||||
"version": "0.5.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"minimist": "0.0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ms": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"node-pre-gyp": {
|
|
||||||
"version": "0.6.36",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"mkdirp": "0.5.1",
|
|
||||||
"nopt": "4.0.1",
|
|
||||||
"npmlog": "4.1.0",
|
|
||||||
"rc": "1.2.1",
|
|
||||||
"request": "2.81.0",
|
|
||||||
"rimraf": "2.6.1",
|
|
||||||
"semver": "5.3.0",
|
|
||||||
"tar": "2.2.1",
|
|
||||||
"tar-pack": "3.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nopt": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"abbrev": "1.1.0",
|
|
||||||
"osenv": "0.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"npmlog": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"are-we-there-yet": "1.1.4",
|
|
||||||
"console-control-strings": "1.1.0",
|
|
||||||
"gauge": "2.7.4",
|
|
||||||
"set-blocking": "2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"number-is-nan": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"oauth-sign": {
|
|
||||||
"version": "0.8.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"object-assign": {
|
|
||||||
"version": "4.1.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"wrappy": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"os-homedir": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"os-tmpdir": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"osenv": {
|
|
||||||
"version": "0.1.4",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"os-homedir": "1.0.2",
|
|
||||||
"os-tmpdir": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"performance-now": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"process-nextick-args": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"punycode": {
|
|
||||||
"version": "1.4.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"qs": {
|
|
||||||
"version": "6.4.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"rc": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"deep-extend": "0.4.2",
|
|
||||||
"ini": "1.3.4",
|
|
||||||
"minimist": "1.2.0",
|
|
||||||
"strip-json-comments": "2.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"minimist": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"readable-stream": {
|
|
||||||
"version": "2.2.9",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"buffer-shims": "1.0.0",
|
|
||||||
"core-util-is": "1.0.2",
|
|
||||||
"inherits": "2.0.3",
|
|
||||||
"isarray": "1.0.0",
|
|
||||||
"process-nextick-args": "1.0.7",
|
|
||||||
"string_decoder": "1.0.1",
|
|
||||||
"util-deprecate": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request": {
|
|
||||||
"version": "2.81.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"aws-sign2": "0.6.0",
|
|
||||||
"aws4": "1.6.0",
|
|
||||||
"caseless": "0.12.0",
|
|
||||||
"combined-stream": "1.0.5",
|
|
||||||
"extend": "3.0.1",
|
|
||||||
"forever-agent": "0.6.1",
|
|
||||||
"form-data": "2.1.4",
|
|
||||||
"har-validator": "4.2.1",
|
|
||||||
"hawk": "3.1.3",
|
|
||||||
"http-signature": "1.1.1",
|
|
||||||
"is-typedarray": "1.0.0",
|
|
||||||
"isstream": "0.1.2",
|
|
||||||
"json-stringify-safe": "5.0.1",
|
|
||||||
"mime-types": "2.1.15",
|
|
||||||
"oauth-sign": "0.8.2",
|
|
||||||
"performance-now": "0.2.0",
|
|
||||||
"qs": "6.4.0",
|
|
||||||
"safe-buffer": "5.0.1",
|
|
||||||
"stringstream": "0.0.5",
|
|
||||||
"tough-cookie": "2.3.2",
|
|
||||||
"tunnel-agent": "0.6.0",
|
|
||||||
"uuid": "3.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rimraf": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"glob": "7.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"safe-buffer": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"semver": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"set-blocking": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"signal-exit": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"sntp": {
|
|
||||||
"version": "1.0.9",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"hoek": "2.16.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sshpk": {
|
|
||||||
"version": "1.13.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"asn1": "0.2.3",
|
|
||||||
"assert-plus": "1.0.0",
|
|
||||||
"bcrypt-pbkdf": "1.0.1",
|
|
||||||
"dashdash": "1.14.1",
|
|
||||||
"ecc-jsbn": "0.1.1",
|
|
||||||
"getpass": "0.1.7",
|
|
||||||
"jodid25519": "1.0.2",
|
|
||||||
"jsbn": "0.1.1",
|
|
||||||
"tweetnacl": "0.14.5"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string-width": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"code-point-at": "1.1.0",
|
|
||||||
"is-fullwidth-code-point": "1.0.0",
|
|
||||||
"strip-ansi": "3.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string_decoder": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stringstream": {
|
|
||||||
"version": "0.0.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "2.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-json-comments": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"tar": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"block-stream": "0.0.9",
|
|
||||||
"fstream": "1.0.11",
|
|
||||||
"inherits": "2.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tar-pack": {
|
|
||||||
"version": "3.4.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"debug": "2.6.8",
|
|
||||||
"fstream": "1.0.11",
|
|
||||||
"fstream-ignore": "1.0.5",
|
|
||||||
"once": "1.4.0",
|
|
||||||
"readable-stream": "2.2.9",
|
|
||||||
"rimraf": "2.6.1",
|
|
||||||
"tar": "2.2.1",
|
|
||||||
"uid-number": "0.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tough-cookie": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"punycode": "1.4.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tunnel-agent": {
|
|
||||||
"version": "0.6.0",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tweetnacl": {
|
|
||||||
"version": "0.14.5",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"uid-number": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"util-deprecate": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"verror": {
|
|
||||||
"version": "1.3.6",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"extsprintf": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wide-align": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"string-width": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"bundled": true,
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"fstream": {
|
"fstream": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
||||||
|
@ -8940,6 +8040,15 @@
|
||||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
@ -8967,15 +8076,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "5.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stringstream": {
|
"stringstream": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||||
|
|
|
@ -36,6 +36,10 @@ const appRoutes: Routes = [
|
||||||
path : 'apps/calendar',
|
path : 'apps/calendar',
|
||||||
loadChildren: './main/content/apps/calendar/calendar.module#FuseCalendarModule'
|
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',
|
path : 'apps/todo',
|
||||||
loadChildren: './main/content/apps/todo/todo.module#FuseTodoModule'
|
loadChildren: './main/content/apps/todo/todo.module#FuseTodoModule'
|
||||||
|
|
|
@ -82,10 +82,12 @@ export class FuseUtils
|
||||||
{
|
{
|
||||||
function S4()
|
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)
|
public static toggleInArray(item, array)
|
||||||
|
@ -99,4 +101,14 @@ export class FuseUtils
|
||||||
array.splice(array.indexOf(item), 1);
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,11 @@ $matColorHues: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400
|
||||||
// Generate material element colors
|
// Generate material element colors
|
||||||
// based on current contrast color
|
// based on current contrast color
|
||||||
@include generateMaterialElementColors($contrastColor);
|
@include generateMaterialElementColors($contrastColor);
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background-color: rgba($color, .12) !important;
|
||||||
|
color: rgba($contrastColor, .26) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$colorName}#{$hue}-fg {
|
.#{$colorName}#{$hue}-fg {
|
||||||
|
|
|
@ -96,7 +96,7 @@ $top-bg-image: url('assets/images/backgrounds/header-bg.png');
|
||||||
max-height: $carded-toolbar-height;
|
max-height: $carded-toolbar-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
> .content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
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
|
@ -15,6 +15,7 @@ import { ProjectsDashboardDb } from './projects-dashboard';
|
||||||
import { ScrumboardFakeDb } from './scrumboard';
|
import { ScrumboardFakeDb } from './scrumboard';
|
||||||
import { FaqFakeDb } from './faq';
|
import { FaqFakeDb } from './faq';
|
||||||
import { KnowledgeBaseFakeDb } from './knowledge-base';
|
import { KnowledgeBaseFakeDb } from './knowledge-base';
|
||||||
|
import { ECommerceFakeDb } from './e-commerce';
|
||||||
|
|
||||||
export class FuseFakeDbService implements InMemoryDbService
|
export class FuseFakeDbService implements InMemoryDbService
|
||||||
{
|
{
|
||||||
|
@ -48,7 +49,10 @@ export class FuseFakeDbService implements InMemoryDbService
|
||||||
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
|
'projects-dashboard-widgets' : ProjectsDashboardDb.widgets,
|
||||||
'scrumboard-boards' : ScrumboardFakeDb.boards,
|
'scrumboard-boards' : ScrumboardFakeDb.boards,
|
||||||
'faq' : FaqFakeDb.data,
|
'faq' : FaqFakeDb.data,
|
||||||
'knowledge-base' : KnowledgeBaseFakeDb.data
|
'knowledge-base' : KnowledgeBaseFakeDb.data,
|
||||||
|
'e-commerce-dashboard' : ECommerceFakeDb.dashboard,
|
||||||
|
'e-commerce-products' : ECommerceFakeDb.products,
|
||||||
|
'e-commerce-orders' : ECommerceFakeDb.orders
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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':true}}
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
{{product.quantity}}
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
{{product.total | currency:'USD':true}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="simple invoice-table-footer">
|
||||||
|
<tbody>
|
||||||
|
<tr class="subtotal">
|
||||||
|
<td>SUBTOTAL</td>
|
||||||
|
<td>{{order.subtotal | currency:'USD':true}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="tax">
|
||||||
|
<td>TAX</td>
|
||||||
|
<td>{{order.tax | currency:'USD':true}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="discount">
|
||||||
|
<td>DISCOUNT</td>
|
||||||
|
<td>-{{order.discount | currency:'USD':true}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="total">
|
||||||
|
<td>TOTAL</td>
|
||||||
|
<td>{{order.total | currency:'USD':true}}</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: 64px;
|
||||||
|
|
||||||
|
.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':true}}
|
||||||
|
</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="10">
|
||||||
|
</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" (remove)="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" (remove)="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" fxFlex="1 0 auto" 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':true}}
|
||||||
|
</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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,32 @@ export class NavigationModel
|
||||||
'icon' : 'today',
|
'icon' : 'today',
|
||||||
'url' : '/apps/calendar'
|
'url' : '/apps/calendar'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'id' : 'e-commerce',
|
||||||
|
'title' : 'E-Commerce',
|
||||||
|
'type' : 'collapse',
|
||||||
|
'icon' : 'shopping_cart',
|
||||||
|
'children': [
|
||||||
|
{
|
||||||
|
'id' : 'dashboard',
|
||||||
|
'title': 'Dashboard',
|
||||||
|
'type' : 'item',
|
||||||
|
'url' : '/apps/e-commerce/dashboard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : 'dashboard',
|
||||||
|
'title': 'Products',
|
||||||
|
'type' : 'item',
|
||||||
|
'url' : '/apps/e-commerce/products'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id' : 'dashboard',
|
||||||
|
'title': 'Orders',
|
||||||
|
'type' : 'item',
|
||||||
|
'url' : '/apps/e-commerce/orders'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'id' : 'mail',
|
'id' : 'mail',
|
||||||
'title': 'Mail',
|
'title': 'Mail',
|
||||||
|
@ -807,3 +833,4 @@ export class NavigationModel
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user