Project is created
This commit is contained in:
commit
b2dd82ef08
13
.editorconfig
Executable file
13
.editorconfig
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
46
.gitignore
vendored
Executable file
46
.gitignore
vendored
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
yarn\.lock
|
||||||
|
.angulardoc.json
|
||||||
|
/dev
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
|
\.mongod/
|
15
.vscode/settings.json
vendored
Executable file
15
.vscode/settings.json
vendored
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.autoClosingBrackets": true,
|
||||||
|
"editor.trimAutoWhitespace": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.trimFinalNewlines": true,
|
||||||
|
"git.ignoreLimitWarning": true,
|
||||||
|
|
||||||
|
"prettier.singleQuote": true,
|
||||||
|
"debug.node.autoAttach": "on"
|
||||||
|
}
|
||||||
|
|
28
README.md
Executable file
28
README.md
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
# AngularUniversal
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.0.6.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
|
`
|
166
angular.json
Executable file
166
angular.json
Executable file
|
@ -0,0 +1,166 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"2nd-round": {
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "app",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/2nd-round",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "src/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hmr": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.hmr.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.test.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "2nd-round:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "2nd-round:build:production"
|
||||||
|
},
|
||||||
|
"hmr": {
|
||||||
|
"hmrWarning": false,
|
||||||
|
"hmr": true,
|
||||||
|
"browserTarget": "2nd-round:build:hmr"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"hmrWarning": false,
|
||||||
|
"hmr": true,
|
||||||
|
"browserTarget": "2nd-round:build:test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "2nd-round:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "src/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "src/karma.conf.js",
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": [],
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"src/tsconfig.app.json",
|
||||||
|
"src/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2nd-round-e2e": {
|
||||||
|
"root": "e2e/",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "2nd-round:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "2nd-round:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "2nd-round"
|
||||||
|
}
|
28
e2e/protractor.conf.js
Executable file
28
e2e/protractor.conf.js
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
14
e2e/src/app.e2e-spec.ts
Executable file
14
e2e/src/app.e2e-spec.ts
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
import { AppPage } from './app.po';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getTitleText()).toEqual('Welcome to 2nd-round!');
|
||||||
|
});
|
||||||
|
});
|
11
e2e/src/app.po.ts
Executable file
11
e2e/src/app.po.ts
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitleText() {
|
||||||
|
return element(by.css('app-root h1')).getText();
|
||||||
|
}
|
||||||
|
}
|
13
e2e/tsconfig.e2e.json
Executable file
13
e2e/tsconfig.e2e.json
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/app",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
15
nodemon.json
Executable file
15
nodemon.json
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"ignore": [
|
||||||
|
"**/client/**",
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.spec.ts",
|
||||||
|
".git",
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"watch": [
|
||||||
|
"src/server",
|
||||||
|
"src/shared"
|
||||||
|
],
|
||||||
|
"exec": "yarn start:server",
|
||||||
|
"ext": "ts"
|
||||||
|
}
|
138
package.json
Executable file
138
package.json
Executable file
|
@ -0,0 +1,138 @@
|
||||||
|
{
|
||||||
|
"name": "2nd-round",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "npm-run-all -p start:server start:client:hmr",
|
||||||
|
"start:client": "ng serve",
|
||||||
|
"start:client:hmr": "ng serve --configuration hmr",
|
||||||
|
"start:client:test": "ng serve --configuration=test --host 0.0.0.0 --port 4200",
|
||||||
|
"start:server": "cross-env TS_NODE_PROJECT=\"src/tsconfig.server.json\" node --inspect -r ts-node/register ./src/server/main.ts",
|
||||||
|
"start:server:nodemon": "nodemon",
|
||||||
|
"build": "ng build",
|
||||||
|
"build:server": "webpack --config webpack.server.config.js --progress --colors",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "~7.0.4",
|
||||||
|
"@angular/cdk": "^7.1.0",
|
||||||
|
"@angular/cdk-experimental": "^7.2.0",
|
||||||
|
"@angular/common": "~7.0.4",
|
||||||
|
"@angular/compiler": "~7.0.4",
|
||||||
|
"@angular/core": "~7.0.4",
|
||||||
|
"@angular/flex-layout": "^7.0.0-beta.19",
|
||||||
|
"@angular/forms": "~7.0.4",
|
||||||
|
"@angular/http": "~7.0.4",
|
||||||
|
"@angular/material": "^7.1.0",
|
||||||
|
"@angular/platform-browser": "~7.0.4",
|
||||||
|
"@angular/platform-browser-dynamic": "~7.0.4",
|
||||||
|
"@angular/router": "~7.0.4",
|
||||||
|
"@ngrx/effects": "^6.1.2",
|
||||||
|
"@ngrx/router-store": "^6.1.2",
|
||||||
|
"@ngrx/schematics": "^6.1.2",
|
||||||
|
"@ngrx/store": "^6.1.2",
|
||||||
|
"@ngrx/store-devtools": "^6.1.2",
|
||||||
|
"@ngx-translate/core": "^11.0.1",
|
||||||
|
"@ngx-translate/http-loader": "^4.0.0",
|
||||||
|
"@tsed/common": "^5.0.8",
|
||||||
|
"@tsed/core": "^5.0.8",
|
||||||
|
"@tsed/di": "^5.0.8",
|
||||||
|
"@tsed/mongoose": "^5.0.8",
|
||||||
|
"@tsed/multipartfiles": "^5.0.8",
|
||||||
|
"@tsed/swagger": "^5.0.8",
|
||||||
|
"@tsed/testing": "^5.0.8",
|
||||||
|
"@tsed/typeorm": "^5.0.8",
|
||||||
|
"axios": "^0.18.0",
|
||||||
|
"body-parser": "^1.18.3",
|
||||||
|
"compression": "^1.7.3",
|
||||||
|
"cookie-parser": "^1.4.3",
|
||||||
|
"core-js": "^2.5.4",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"cropperjs": "^1.4.3",
|
||||||
|
"cross-env": "^5.2.0",
|
||||||
|
"express": "^4.16.4",
|
||||||
|
"fs-extra": "^7.0.1",
|
||||||
|
"gifshot": "^0.4.5",
|
||||||
|
"hammerjs": "^2.0.8",
|
||||||
|
"jimp": "^0.6.0",
|
||||||
|
"jsonwebtoken": "^8.4.0",
|
||||||
|
"method-override": "^3.0.0",
|
||||||
|
"mongodb": "^3.1.10",
|
||||||
|
"mongoose": "^5.4.4",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"multer": "^1.4.1",
|
||||||
|
"ngx-clipboard": "^11.1.9",
|
||||||
|
"ngx-cookie-service": "^2.0.2",
|
||||||
|
"ngx-hm-carousel": "^1.4.0",
|
||||||
|
"ngx-image-cropper": "^1.3.7",
|
||||||
|
"ngx-virtual-scroller": "^1.0.16",
|
||||||
|
"oneall": "^0.1.5",
|
||||||
|
"passport": "^0.4.0",
|
||||||
|
"passport-jwt": "^4.0.0",
|
||||||
|
"passport-kakao": "^0.0.5",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
|
"passport-naver": "^1.0.6",
|
||||||
|
"reflect-metadata": "^0.1.12",
|
||||||
|
"rxjs": "~6.3.3",
|
||||||
|
"short-uuid": "^3.1.0",
|
||||||
|
"typeorm": "^0.2.9",
|
||||||
|
"uuid": "^3.3.2",
|
||||||
|
"zone.js": "~0.8.26"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "~0.10.0",
|
||||||
|
"@angular/cli": "~7.0.6",
|
||||||
|
"@angular/compiler-cli": "~7.0.4",
|
||||||
|
"@angular/language-service": "~7.0.4",
|
||||||
|
"@angularclass/hmr": "^2.1.3",
|
||||||
|
"@types/bcrypt": "^3.0.0",
|
||||||
|
"@types/cropperjs": "^1.1.4",
|
||||||
|
"@types/express": "^4.16.0",
|
||||||
|
"@types/fs-extra": "^5.0.4",
|
||||||
|
"@types/jasmine": "~2.8.8",
|
||||||
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"@types/jimp": "^0.2.28",
|
||||||
|
"@types/jsonwebtoken": "^8.3.0",
|
||||||
|
"@types/mongoose": "^5.3.7",
|
||||||
|
"@types/ms": "^0.7.30",
|
||||||
|
"@types/multer": "^1.3.7",
|
||||||
|
"@types/node": "~8.9.4",
|
||||||
|
"@types/passport": "^0.4.7",
|
||||||
|
"@types/passport-jwt": "^3.0.1",
|
||||||
|
"@types/passport-kakao": "^0.2.0",
|
||||||
|
"@types/passport-local": "^1.0.33",
|
||||||
|
"@types/passport-naver": "^0.2.0",
|
||||||
|
"@types/swagger-schema-official": "^2.0.13",
|
||||||
|
"@types/unzipper": "^0.9.1",
|
||||||
|
"@types/uuid": "^3.4.4",
|
||||||
|
"@types/webpack": "^4.4.19",
|
||||||
|
"awesome-typescript-loader": "^5.2.1",
|
||||||
|
"codelyzer": "~4.5.0",
|
||||||
|
"jasmine-core": "~2.99.1",
|
||||||
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
"json-loader": "^0.5.7",
|
||||||
|
"karma": "~3.0.0",
|
||||||
|
"karma-chrome-launcher": "~2.2.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||||
|
"karma-jasmine": "~1.1.2",
|
||||||
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
|
"mocha": "^5.2.0",
|
||||||
|
"mongodb-memory-server": "^2.9.1",
|
||||||
|
"nodemon": "^1.18.7",
|
||||||
|
"npm-run-all": "^4.1.3",
|
||||||
|
"protractor": "~5.4.0",
|
||||||
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
|
"sqlite3": "^4.0.4",
|
||||||
|
"ts-node": "^7.0.1",
|
||||||
|
"tslint": "~5.11.0",
|
||||||
|
"typescript": "~3.1.6",
|
||||||
|
"unzipper": "^0.9.8",
|
||||||
|
"webpack-cli": "^3.1.2"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"**/event-stream": "^4.0.1"
|
||||||
|
}
|
||||||
|
}
|
76
src/app/app-provider.module.ts
Executable file
76
src/app/app-provider.module.ts
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app-provider.module.ts
|
||||||
|
* 작성일자: 2018-12-23
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app 영역의 provider를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||||
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { CookieService } from 'ngx-cookie-service';
|
||||||
|
import { ClipboardModule, ClipboardService } from 'ngx-clipboard';
|
||||||
|
|
||||||
|
import { AccountsModule } from '../modules/accounts/accounts.module';
|
||||||
|
import { ArticleModule } from '../modules/article/article.module';
|
||||||
|
import { AttachmentsModule } from '../modules/attachments/attachments.module';
|
||||||
|
import { CartoonsModule } from '../modules/cartoons/cartoons.module';
|
||||||
|
import { ContentsModule } from '../modules/contents/contents.module';
|
||||||
|
import { IllustrationsModule } from '../modules/illustrations/illustrations.module';
|
||||||
|
import { NovelModule } from '../modules/novel/novel.module';
|
||||||
|
import { TagModule } from '../modules/tag/tag.module';
|
||||||
|
import { UserModule } from '../modules/user/user.module';
|
||||||
|
import { UserAnalysisModule } from '../modules/user-analysis/user-analysis.module';
|
||||||
|
import { UserSupportModule } from '../modules/user-support/user-support.module';
|
||||||
|
import { MetaModule } from '../modules/meta/meta.module';
|
||||||
|
|
||||||
|
import { AuthHttpInterceptor } from './service/auth.http.interceptor';
|
||||||
|
import { AppService } from './service/app.service';
|
||||||
|
import { GUARDS } from './guard';
|
||||||
|
|
||||||
|
export function initApp(appService: AppService) {
|
||||||
|
return () => appService.initApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
AccountsModule.forRoot(),
|
||||||
|
ArticleModule.forRoot(),
|
||||||
|
AttachmentsModule.forRoot(),
|
||||||
|
CartoonsModule.forRoot(),
|
||||||
|
ContentsModule.forRoot(),
|
||||||
|
IllustrationsModule.forRoot(),
|
||||||
|
NovelModule.forRoot(),
|
||||||
|
TagModule.forRoot(),
|
||||||
|
UserModule.forRoot(),
|
||||||
|
UserAnalysisModule.forRoot(),
|
||||||
|
UserSupportModule.forRoot(),
|
||||||
|
MetaModule.forRoot(),
|
||||||
|
ClipboardModule
|
||||||
|
],
|
||||||
|
exports: [],
|
||||||
|
providers: [
|
||||||
|
AppService,
|
||||||
|
...GUARDS,
|
||||||
|
CookieService,
|
||||||
|
ClipboardService,
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: initApp,
|
||||||
|
deps: [AppService],
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
{ provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true },
|
||||||
|
{ provide: 'virtualScroller.scrollThrottlingTime', useValue: 0 },
|
||||||
|
{ provide: 'virtualScroller.scrollDebounceTime', useValue: 0 },
|
||||||
|
{ provide: 'virtualScroller.scrollAnimationTime', useValue: 750 },
|
||||||
|
{ provide: 'virtualScroller.scrollbarWidth', useValue: undefined },
|
||||||
|
{ provide: 'virtualScroller.scrollbarHeight', useValue: undefined },
|
||||||
|
{ provide: 'virtualScroller.checkResizeInterval', useValue: 1000 },
|
||||||
|
{ provide: 'virtualScroller.resizeBypassRefreshThreshold', useValue: 5 }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AppProviderModule { }
|
41
src/app/app-routing.module.ts
Executable file
41
src/app/app-routing.module.ts
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app-routing.module.ts
|
||||||
|
* 작성일자: 2018-12-17
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app 영역의 routing을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
loadChildren: './pages/main/main.page.module#MainPageModule'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'accounts',
|
||||||
|
loadChildren: './pages/accounts/accounts.page.module#AccountsPageModule'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'user',
|
||||||
|
loadChildren: './pages/user/user.page.module#UserPageModule'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'article',
|
||||||
|
loadChildren: './pages/article/article.page.module#ArticlePageModule'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'admin',
|
||||||
|
loadChildren: './pages/admin/admin.page.module#AdminPageModule'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
59
src/app/app-store.module.ts
Executable file
59
src/app/app-store.module.ts
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app-store.module.ts
|
||||||
|
* 작성일자: 2018-12-17
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app 영역의 ngrx를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { StoreModule } from '@ngrx/store';
|
||||||
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||||
|
import {
|
||||||
|
StoreRouterConnectingModule,
|
||||||
|
} from '@ngrx/router-store';
|
||||||
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
|
|
||||||
|
import { environment } from '../environments/environment';
|
||||||
|
import { REDUCERS, META_REDUCERS, EFFECTS } from './store';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
exports: [
|
||||||
|
StoreModule,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
StoreModule.forRoot(REDUCERS, { metaReducers: META_REDUCERS }),
|
||||||
|
/**
|
||||||
|
* @ngrx/router-store keeps router state up-to-date in the store.
|
||||||
|
*/
|
||||||
|
StoreRouterConnectingModule.forRoot({
|
||||||
|
/*
|
||||||
|
They stateKey defines the name of the state used by the router-store reducer.
|
||||||
|
This matches the key defined in the map of reducers
|
||||||
|
*/
|
||||||
|
stateKey: 'router',
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* Store devtools instrument the store retaining past versions of state
|
||||||
|
* and recalculating new states. This enables powerful time-travel
|
||||||
|
* debugging.
|
||||||
|
*
|
||||||
|
* To use the debugger, install the Redux Devtools extension for either
|
||||||
|
* Chrome or Firefox
|
||||||
|
*
|
||||||
|
* See: https://github.com/zalmoxisus/redux-devtools-extension
|
||||||
|
*/
|
||||||
|
StoreDevtoolsModule.instrument({
|
||||||
|
name: 'WebApp DevTools',
|
||||||
|
maxAge: 50,
|
||||||
|
logOnly: environment.production,
|
||||||
|
}),
|
||||||
|
EffectsModule.forRoot(EFFECTS),
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
|
||||||
|
})
|
||||||
|
export class AppStoreModule { }
|
36
src/app/app-translate.module.ts
Executable file
36
src/app/app-translate.module.ts
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app-tanslate.module.ts
|
||||||
|
* 작성일자: 2018-12-17
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app 영역의 i18n을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||||
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
// AoT requires an exported function for factories
|
||||||
|
export function createTranslateLoader(http: HttpClient) {
|
||||||
|
return new TranslateHttpLoader(http, '../assets/i18n/', '.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: (createTranslateLoader),
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AppTranslateModule { }
|
1
src/app/app.component.html
Executable file
1
src/app/app.component.html
Executable file
|
@ -0,0 +1 @@
|
||||||
|
<router-outlet></router-outlet>
|
29
src/app/app.component.scss
Executable file
29
src/app/app.component.scss
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
app-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp-root>app-component-sidenav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
app-root {
|
||||||
|
top: 92px;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: visible;
|
||||||
|
}
|
||||||
|
}
|
35
src/app/app.component.spec.ts
Executable file
35
src/app/app.component.spec.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title '2nd-round'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('2nd-round');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title in a h1 tag', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to 2nd-round!');
|
||||||
|
});
|
||||||
|
});
|
320
src/app/app.component.ts
Executable file
320
src/app/app.component.ts
Executable file
|
@ -0,0 +1,320 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app.component.ts
|
||||||
|
* 작성일자: 2018-12-17
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app component를 정의한다.
|
||||||
|
* 수정일시: 2010-01-02
|
||||||
|
* 수 정 자: 조현정
|
||||||
|
* 수정내용: SVG ICONS 주입
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
// Mat-Icons
|
||||||
|
import { MatIconRegistry } from '@angular/material/icon';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent implements OnInit {
|
||||||
|
constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
|
||||||
|
// Mat - Icons: ToolBar;
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'home-outline',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/toolbar-icons/bot_home.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'search',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/toolbar-icons/bot_search.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'upload',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/toolbar-icons/bot_upload.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'bookmark',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/toolbar-icons/bot_bookmark.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'myprofil',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/toolbar-icons/bot_my.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// Mat - Icons: General Icons
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'file-delete-circle',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/close-circle.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_bookmark',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/btn_bookmark.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_bookmark_checked',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/bookmark-check.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_close',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/btn_close.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_more',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/btn_more.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_settings',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/btn_settings.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_share',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/btn_share.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_tracing',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/btn_tracing.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_reply',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/ico_01.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_like',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/ico_02.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_like_checked',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/cards-heart.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_views',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/ico_03.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'btn_camera',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/btn_camera.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'top_recommend',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/top_recommend.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'top_upload',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/top_upload.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_mypro_01',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/my_ico_01.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_mypro_02',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/my_ico_02.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_mypro_03',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/my_ico_03.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_mypro_04',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/my_ico_04.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_write_01',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/btn_illustration.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_write_02',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/btn_cartoon.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'tab_write_03',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl('assets/img/icons/btn_novel.svg')
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_01',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_01.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_02',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_02.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_03',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_03.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_04',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_04.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_05',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_05.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_06',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_06.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_07',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_07.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_set_08',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_set_08.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_facebook',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_facebook.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_google',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_google.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_kakao',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_kakao.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_line',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_line.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_naver',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_naver.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_twitter',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_twitter.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_weibo',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_weibo.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_instagram',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_insta.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_logo_googlePlus',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_logo_gplus.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'login_caution',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/login/login_ico_01.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_share_03',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_share_03.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'ico_share_04',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_share_04.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'step-backward',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/ico_check2.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'step_backward',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/step-backward.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'msg_ok',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/comment-check.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'msg_notice',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/message-alert.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'msg_fail',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/message-bulleted-off.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
iconRegistry.addSvgIcon(
|
||||||
|
'msg_bigfail',
|
||||||
|
sanitizer.bypassSecurityTrustResourceUrl(
|
||||||
|
'assets/img/icons/alert-octagram.svg'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { }
|
||||||
|
}
|
44
src/app/app.module.ts
Executable file
44
src/app/app.module.ts
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: app.module.ts
|
||||||
|
* 작성일자: 2018-12-17
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: app 영역의 module을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
import { SharedModule } from '../modules/common/shared/shared.module';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppTranslateModule } from './app-translate.module';
|
||||||
|
import { AppStoreModule } from './app-store.module';
|
||||||
|
import { AppProviderModule } from './app-provider.module';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { LayoutModule } from './layout/layout.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
HttpClientModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
AppStoreModule,
|
||||||
|
AppProviderModule,
|
||||||
|
AppTranslateModule,
|
||||||
|
SharedModule,
|
||||||
|
LayoutModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
53
src/app/guard/article-owner.guard.ts
Executable file
53
src/app/guard/article-owner.guard.ts
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { Store, } from '@ngrx/store';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { map, take, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { ArticleGetService } from '../../modules/article/service/article.get.service';
|
||||||
|
import { ArticleMongodb } from '../../shared/article/model/article.mongodb.model';
|
||||||
|
import { AccountsUtil } from 'src/modules/accounts/util/accounts.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ArticleOwnerGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private router: Router,
|
||||||
|
private articleGetService: ArticleGetService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||||
|
return new Promise<boolean>((resolve, reject) => {
|
||||||
|
const aid = route.paramMap.get('aid');
|
||||||
|
if (!aid) {
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.articleGetService.get(aid).pipe(
|
||||||
|
take(1),
|
||||||
|
map(async (articleMongodb: ArticleMongodb) => {
|
||||||
|
if (!articleMongodb) {
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
const isOwner = await AccountsUtil.checkOwner(this.store, articleMongodb.userId);
|
||||||
|
if (!isOwner) {
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
return resolve(true);
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
reject(error);
|
||||||
|
return of(error);
|
||||||
|
}),
|
||||||
|
).subscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
src/app/guard/auth-nickname.guard.ts
Executable file
40
src/app/guard/auth-nickname.guard.ts
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { Store, } from '@ngrx/store';
|
||||||
|
|
||||||
|
import * as EventsStore from '../../modules/common/shared/store/events';
|
||||||
|
import { AccountsUtil } from '../../modules/accounts/util/accounts.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthNicknameGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private router: Router,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||||
|
return new Promise<boolean>(async (resolve, reject) => {
|
||||||
|
const user = await AccountsUtil.getUser(this.store);
|
||||||
|
if (!user) {
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.nickname) {
|
||||||
|
this.store.dispatch(new EventsStore.ExecutionFailure({
|
||||||
|
title: 'Nickname is not valid',
|
||||||
|
message: 'You need to specify your nickname before you can author.',
|
||||||
|
}));
|
||||||
|
this.router.navigate(['/user/edit']);
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
return resolve(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
src/app/guard/auth.guard.ts
Executable file
47
src/app/guard/auth.guard.ts
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map, take } from 'rxjs/operators';
|
||||||
|
import { CookieService } from 'ngx-cookie-service';
|
||||||
|
|
||||||
|
import { AuthSelector } from '../../modules/accounts/store';
|
||||||
|
import * as AppLoginStore from '../store/login';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private router: Router,
|
||||||
|
private cookieService: CookieService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
|
||||||
|
return this.store.pipe(
|
||||||
|
take(1),
|
||||||
|
select(AuthSelector.selectLogined),
|
||||||
|
map((logined) => {
|
||||||
|
if (!logined) {
|
||||||
|
if (this.cookieService.check('jwt')) {
|
||||||
|
this.store.dispatch(new AppLoginStore.LoginToken({
|
||||||
|
token: this.cookieService.get('jwt'),
|
||||||
|
returnURL: state.url
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.store.dispatch(new AppLoginStore.LoginRedirect({ returnURL: state.url }));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
src/app/guard/can-deactivate.guard.ts
Executable file
27
src/app/guard/can-deactivate.guard.ts
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
CanDeactivate as RouterCanDeactivate,
|
||||||
|
} from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
export interface CanDeactivate {
|
||||||
|
canDeactivate(): Observable<boolean> | Promise<boolean> | boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CanDeactivateGuard implements RouterCanDeactivate<CanDeactivate> {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
canDeactivate(
|
||||||
|
component: CanDeactivate,
|
||||||
|
currentRoute: ActivatedRouteSnapshot,
|
||||||
|
currentState: RouterStateSnapshot,
|
||||||
|
nextState?: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
|
||||||
|
|
||||||
|
return component.canDeactivate ? component.canDeactivate() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/app/guard/index.ts
Executable file
11
src/app/guard/index.ts
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
import { ArticleOwnerGuard } from './article-owner.guard';
|
||||||
|
import { AuthGuard } from './auth.guard';
|
||||||
|
import { AuthNicknameGuard } from './auth-nickname.guard';
|
||||||
|
import { CanDeactivateGuard } from './can-deactivate.guard';
|
||||||
|
|
||||||
|
export const GUARDS = [
|
||||||
|
ArticleOwnerGuard,
|
||||||
|
AuthGuard,
|
||||||
|
AuthNicknameGuard,
|
||||||
|
CanDeactivateGuard,
|
||||||
|
];
|
3
src/app/layout/component/accounts/accounts.layout.component.html
Executable file
3
src/app/layout/component/accounts/accounts.layout.component.html
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="accountsLayout">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
4
src/app/layout/component/accounts/accounts.layout.component.scss
Executable file
4
src/app/layout/component/accounts/accounts.layout.component.scss
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
.accountsLayout {
|
||||||
|
margin-top: -55px;
|
||||||
|
margin-bottom: -80px;
|
||||||
|
}
|
35
src/app/layout/component/accounts/accounts.layout.component.spec.ts
Executable file
35
src/app/layout/component/accounts/accounts.layout.component.spec.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AccountsLayoutComponent } from './accounts.layout.component';
|
||||||
|
|
||||||
|
describe('AccountsLayoutComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AccountsLayoutComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AccountsLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title '2nd-round'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AccountsLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('2nd-round');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title in a h1 tag', () => {
|
||||||
|
const fixture = TestBed.createComponent(AccountsLayoutComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to 2nd-round!');
|
||||||
|
});
|
||||||
|
});
|
25
src/app/layout/component/accounts/accounts.layout.component.ts
Executable file
25
src/app/layout/component/accounts/accounts.layout.component.ts
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: accounts.layout.component.ts
|
||||||
|
* 작성일자: 2018-12-21
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: Accounts layout component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-layout-accounts',
|
||||||
|
templateUrl: './accounts.layout.component.html',
|
||||||
|
styleUrls: ['./accounts.layout.component.scss']
|
||||||
|
})
|
||||||
|
export class AccountsLayoutComponent implements OnInit {
|
||||||
|
constructor(
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
}
|
3
src/app/layout/component/avatar/avatar.component.html
Executable file
3
src/app/layout/component/avatar/avatar.component.html
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
<div (click)="handleClickEvent($event)" class="avatar-container">
|
||||||
|
<img *ngIf="src" [src]="src" [width]="size" [height]="size" class="avatar-content" />
|
||||||
|
</div>
|
8
src/app/layout/component/avatar/avatar.component.scss
Executable file
8
src/app/layout/component/avatar/avatar.component.scss
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
:host {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-content {
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
28
src/app/layout/component/avatar/avatar.component.ts
Executable file
28
src/app/layout/component/avatar/avatar.component.ts
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-avatar',
|
||||||
|
templateUrl: './avatar.component.html',
|
||||||
|
styleUrls: ['./avatar.component.scss']
|
||||||
|
})
|
||||||
|
export class AvatarComponent {
|
||||||
|
@Input()
|
||||||
|
src: string;
|
||||||
|
@Input()
|
||||||
|
size = 50;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
clickOnAvatar: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickEvent(event: any) {
|
||||||
|
if (event) {
|
||||||
|
this.clickOnAvatar.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/app/layout/component/default/default.layout.component.html
Executable file
18
src/app/layout/component/default/default.layout.component.html
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
<ng-container *ngIf="environment$ | async as environment" [ngSwitch]="environment">
|
||||||
|
<!--for mobile-->
|
||||||
|
<app-navbar-mobile *ngSwitchCase="'Mobile'"></app-navbar-mobile>
|
||||||
|
<mat-progress-bar *ngIf="showProgressBar$ | async" mode="indeterminate" class="progress-bar"></mat-progress-bar>
|
||||||
|
<app-toolbar *ngSwitchCase="'Mobile'"></app-toolbar>
|
||||||
|
<div class="defaultLayout" *ngSwitchCase="'Mobile'">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
<!--for mobile-->
|
||||||
|
<!--for PC-->
|
||||||
|
<div class="pcLayout" *ngSwitchCase="'Desktop'">
|
||||||
|
<app-navbar></app-navbar>
|
||||||
|
<div class="defaultLayout">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--for PC-->
|
||||||
|
</ng-container>
|
37
src/app/layout/component/default/default.layout.component.scss
Executable file
37
src/app/layout/component/default/default.layout.component.scss
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
app-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pp-root>app-component-sidenav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-navbar-mobile {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pp-root>app-component-sidenav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
35
src/app/layout/component/default/default.layout.component.spec.ts
Executable file
35
src/app/layout/component/default/default.layout.component.spec.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { DefaultLayoutComponent } from './default.layout.component';
|
||||||
|
|
||||||
|
describe('DefaultLayoutComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DefaultLayoutComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(DefaultLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title '2nd-round'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(DefaultLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('2nd-round');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title in a h1 tag', () => {
|
||||||
|
const fixture = TestBed.createComponent(DefaultLayoutComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to 2nd-round!');
|
||||||
|
});
|
||||||
|
});
|
47
src/app/layout/component/default/default.layout.component.ts
Executable file
47
src/app/layout/component/default/default.layout.component.ts
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: default.layout.component.ts
|
||||||
|
* 작성일자: 2018-12-21
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: Default layout component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { Subscription, of, Observable } from 'rxjs';
|
||||||
|
import { map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import * as AppStore from '../../../store';
|
||||||
|
import { Environment } from '../../../type/environment.type';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-layout-default',
|
||||||
|
templateUrl: './default.layout.component.html',
|
||||||
|
styleUrls: ['./default.layout.component.scss']
|
||||||
|
})
|
||||||
|
export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
|
environment$: Observable<Environment>;
|
||||||
|
|
||||||
|
showProgressBar$: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.environment$ = this.store.pipe(
|
||||||
|
select(AppStore.AppLayoutSelector.selectEnvironment),
|
||||||
|
);
|
||||||
|
this.showProgressBar$ = this.store.pipe(
|
||||||
|
select(AppStore.AppEventsSelector.selectShowProgressBar),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
src/app/layout/component/index.ts
Executable file
17
src/app/layout/component/index.ts
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
import { AccountsLayoutComponent } from './accounts/accounts.layout.component';
|
||||||
|
import { AvatarComponent } from './avatar/avatar.component';
|
||||||
|
import { DefaultLayoutComponent } from './default/default.layout.component';
|
||||||
|
import { MainLayoutComponent } from './main/main.layout.component';
|
||||||
|
import { NavBarComponent } from './navbar/navbar.component';
|
||||||
|
import { NavBarMobileComponent } from './navbar/navbar-mobile/navbar-mobile.component';
|
||||||
|
import { ToolBarComponent } from './toolbar/toolbar.component';
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
AccountsLayoutComponent,
|
||||||
|
AvatarComponent,
|
||||||
|
DefaultLayoutComponent,
|
||||||
|
MainLayoutComponent,
|
||||||
|
NavBarComponent,
|
||||||
|
NavBarMobileComponent,
|
||||||
|
ToolBarComponent
|
||||||
|
];
|
21
src/app/layout/component/main/main.layout.component.html
Executable file
21
src/app/layout/component/main/main.layout.component.html
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
<ng-container *ngIf="environment$ | async as environment" [ngSwitch]="environment">
|
||||||
|
<!--for mobile-->
|
||||||
|
<app-navbar-mobile *ngSwitchCase="'Mobile'"></app-navbar-mobile>
|
||||||
|
<mat-progress-bar *ngIf="showProgressBar$ | async" mode="indeterminate" class="progress-bar"></mat-progress-bar>
|
||||||
|
<app-toolbar *ngSwitchCase="'Mobile'"></app-toolbar>
|
||||||
|
<div class="mainLayout" *ngSwitchCase="'Mobile'">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
<!--for mobile-->
|
||||||
|
<!--for PC-->
|
||||||
|
<div class="pcLayout" *ngSwitchCase="'Desktop'">
|
||||||
|
<app-navbar></app-navbar>
|
||||||
|
<div class="mainLayout">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
<aside class="main-rcommend">
|
||||||
|
PC용 추천작가 표출 영역
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
<!--for PC-->
|
||||||
|
</ng-container>
|
37
src/app/layout/component/main/main.layout.component.scss
Executable file
37
src/app/layout/component/main/main.layout.component.scss
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
app-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pp-root>app-component-sidenav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-navbar-mobile {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pp-root>app-component-sidenav {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
app-root>app-homepage,
|
||||||
|
app-root>app-guides,
|
||||||
|
app-root>guide-viewer {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
35
src/app/layout/component/main/main.layout.component.spec.ts
Executable file
35
src/app/layout/component/main/main.layout.component.spec.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { MainLayoutComponent } from './main.layout.component';
|
||||||
|
|
||||||
|
describe('MainLayoutComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
MainLayoutComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(MainLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title '2nd-round'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(MainLayoutComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('2nd-round');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title in a h1 tag', () => {
|
||||||
|
const fixture = TestBed.createComponent(MainLayoutComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to 2nd-round!');
|
||||||
|
});
|
||||||
|
});
|
47
src/app/layout/component/main/main.layout.component.ts
Executable file
47
src/app/layout/component/main/main.layout.component.ts
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: Main.layout.component.ts
|
||||||
|
* 작성일자: 2019-1-23
|
||||||
|
* 작 성 자: 조현정
|
||||||
|
* 설 명: Main layout component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { Subscription, of, Observable } from 'rxjs';
|
||||||
|
import { map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import * as AppStore from '../../../store';
|
||||||
|
import { Environment } from '../../../type/environment.type';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-layout-main',
|
||||||
|
templateUrl: './main.layout.component.html',
|
||||||
|
styleUrls: ['./main.layout.component.scss']
|
||||||
|
})
|
||||||
|
export class MainLayoutComponent implements OnInit, OnDestroy {
|
||||||
|
environment$: Observable<Environment>;
|
||||||
|
|
||||||
|
showProgressBar$: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.environment$ = this.store.pipe(
|
||||||
|
select(AppStore.AppLayoutSelector.selectEnvironment),
|
||||||
|
);
|
||||||
|
this.showProgressBar$ = this.store.pipe(
|
||||||
|
select(AppStore.AppEventsSelector.selectShowProgressBar),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.html
Executable file
17
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.html
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
<mat-toolbar>
|
||||||
|
<mat-toolbar-row>
|
||||||
|
<div class="tool-left">
|
||||||
|
<button mat-button onClick="javascript:history.go(-1);">
|
||||||
|
<mat-icon svgIcon="step_backward">Back ward</mat-icon>
|
||||||
|
</button></div>
|
||||||
|
<h1 class="logo">
|
||||||
|
<a [routerLink]="['/']">
|
||||||
|
<img src="../../../../assets/img/logo/logo.svg" alt="coco's logo">
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
<div class="tool-right">
|
||||||
|
<button mat-button [routerLink]="['/user/recommendations']">
|
||||||
|
<mat-icon svgIcon="top_recommend">my profile</mat-icon>
|
||||||
|
</button></div>
|
||||||
|
</mat-toolbar-row>
|
||||||
|
</mat-toolbar>
|
41
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.scss
Executable file
41
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.scss
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
@import '../../default/default.layout.component.scss';
|
||||||
|
$topbar-height:54px;
|
||||||
|
|
||||||
|
.mat-toolbar-multiple-rows {
|
||||||
|
min-height: $topbar-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-toolbar-row,
|
||||||
|
.mat-toolbar-single-row {
|
||||||
|
height: $topbar-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-toolbar {
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #e9e9e9;
|
||||||
|
|
||||||
|
.mat-button,
|
||||||
|
.mat-button * {
|
||||||
|
min-width: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-button {
|
||||||
|
padding: 0 3px !important;
|
||||||
|
color: #bababa;
|
||||||
|
}
|
||||||
|
}
|
28
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.ts
Executable file
28
src/app/layout/component/navbar/navbar-mobile/navbar-mobile.component.ts
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Component, ViewChild } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { MatMenuTrigger } from '@angular/material';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-navbar-mobile',
|
||||||
|
templateUrl: './navbar-mobile.component.html',
|
||||||
|
styleUrls: ['./navbar-mobile.component.scss']
|
||||||
|
})
|
||||||
|
export class NavBarMobileComponent {
|
||||||
|
@ViewChild('notificationMenuBtn', { read: MatMenuTrigger })
|
||||||
|
protected notificationMenuBtn: MatMenuTrigger;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private translateService: TranslateService
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage(lang: string) {
|
||||||
|
this.translateService.use(lang).pipe(take(1)).subscribe((res: any) => {
|
||||||
|
localStorage.setItem('defaultLang', lang);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
src/app/layout/component/navbar/navbar.component.html
Executable file
34
src/app/layout/component/navbar/navbar.component.html
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
<mat-toolbar>
|
||||||
|
<mat-toolbar-row>
|
||||||
|
<div class="tool-left">
|
||||||
|
<button mat-button onClick="javascript:history.go(-1);">
|
||||||
|
<mat-icon svgIcon="step_backward">Back ward</mat-icon>
|
||||||
|
</button></div>
|
||||||
|
<h1 class="logo">
|
||||||
|
<a [routerLink]="['/']">
|
||||||
|
<img src="../../../../assets/img/logo/logo.svg" alt="coco's logo">
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
<div class="tool-right">
|
||||||
|
<button mat-button [routerLink]="['/article/search']" routerLinkActive="router-link-active"
|
||||||
|
[routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="search">search</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-button [routerLink]="['/article/write']" routerLinkActive="router-link-active"
|
||||||
|
[routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="upload">upload</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-button [routerLink]="['/user/bookmarks']" routerLinkActive="router-link-active"
|
||||||
|
[routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="bookmark">bookmark</mat-icon>
|
||||||
|
</button>
|
||||||
|
<!-- session.getId의 값이 parameter로 입력되어야 함.-->
|
||||||
|
<button mat-button [routerLink]="myProfileLink" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact: true}">
|
||||||
|
<mat-icon svgIcon="myprofil">my profile</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-toolbar-row>
|
||||||
|
</mat-toolbar>
|
44
src/app/layout/component/navbar/navbar.component.scss
Executable file
44
src/app/layout/component/navbar/navbar.component.scss
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
@import '../default/default.layout.component.scss';
|
||||||
|
$topbar-height:54px;
|
||||||
|
|
||||||
|
.mat-toolbar-multiple-rows {
|
||||||
|
min-height: $topbar-height;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-toolbar-row,
|
||||||
|
.mat-toolbar-single-row {
|
||||||
|
height: $topbar-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
margin: auto;
|
||||||
|
padding-left: 125px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-toolbar {
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid #e9e9e9;
|
||||||
|
|
||||||
|
.mat-button,
|
||||||
|
.mat-button * {
|
||||||
|
min-width: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-button {
|
||||||
|
padding: 0 3px !important;
|
||||||
|
color: #bababa;
|
||||||
|
}
|
||||||
|
}
|
46
src/app/layout/component/navbar/navbar.component.ts
Executable file
46
src/app/layout/component/navbar/navbar.component.ts
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
import { Component, ViewChild, OnInit } from '@angular/core';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { MatMenuTrigger } from '@angular/material';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Store, } from '@ngrx/store';
|
||||||
|
import { User } from '../../../../shared/user/model/user.model';
|
||||||
|
import { AccountsUtil } from 'src/modules/accounts/util/accounts.util';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-navbar',
|
||||||
|
templateUrl: './navbar.component.html',
|
||||||
|
styleUrls: ['./navbar.component.scss']
|
||||||
|
})
|
||||||
|
export class NavBarComponent implements OnInit {
|
||||||
|
user$: Promise<User>;
|
||||||
|
myProfileLink = ['/accounts/authentication'];
|
||||||
|
|
||||||
|
@ViewChild('notificationMenuBtn', { read: MatMenuTrigger })
|
||||||
|
protected notificationMenuBtn: MatMenuTrigger;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private router: Router,
|
||||||
|
private store: Store<any>
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
AccountsUtil.getUser(this.store)
|
||||||
|
.then((user) => {
|
||||||
|
if (user) {
|
||||||
|
this.myProfileLink = ['/article', user.id];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
console.log(reason);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage(lang: string) {
|
||||||
|
this.translateService.use(lang).pipe(take(1)).subscribe((res: any) => {
|
||||||
|
localStorage.setItem('defaultLang', lang);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
28
src/app/layout/component/toolbar/toolbar.component.html
Executable file
28
src/app/layout/component/toolbar/toolbar.component.html
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
<mat-toolbar class="flexToolbar">
|
||||||
|
<button mat-button [routerLink]="['/']" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="home-outline">home</mat-icon>
|
||||||
|
</button>
|
||||||
|
<!-- This fills the remaining space of the current row -->
|
||||||
|
<span class="fill-remaining-space"></span>
|
||||||
|
<button mat-button [routerLink]="['/article/search']" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="search">search</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span class="fill-remaining-space"></span>
|
||||||
|
<button mat-button [routerLink]="['/article/write']" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="upload">upload</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span class="fill-remaining-space"></span>
|
||||||
|
<button mat-button [routerLink]="['/user/bookmarks']" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact:
|
||||||
|
true}">
|
||||||
|
<mat-icon svgIcon="bookmark">bookmark</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span class="fill-remaining-space"></span>
|
||||||
|
<!-- session.getId의 값이 parameter로 입력되어야 함.-->
|
||||||
|
<button mat-button [routerLink]="myProfileLink" routerLinkActive="router-link-active" [routerLinkActiveOptions]="{exact: true}">
|
||||||
|
<mat-icon svgIcon="myprofil">my profile</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</mat-toolbar>
|
30
src/app/layout/component/toolbar/toolbar.component.scss
Executable file
30
src/app/layout/component/toolbar/toolbar.component.scss
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
/** No CSS for this*/
|
||||||
|
.fill-remaining-space {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-toolbar {
|
||||||
|
$toolbarBG: #f9f9f9;
|
||||||
|
$toolbarColor: #000;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
width: 100%;
|
||||||
|
background: $toolbarBG;
|
||||||
|
|
||||||
|
.mat-button {
|
||||||
|
padding: 0 3px !important;
|
||||||
|
color: $toolbarColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toolbar size responsive
|
||||||
|
*/
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
padding: 0 16px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 801px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
29
src/app/layout/component/toolbar/toolbar.component.ts
Executable file
29
src/app/layout/component/toolbar/toolbar.component.ts
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Store, } from '@ngrx/store';
|
||||||
|
import { User } from '../../../../shared/user/model/user.model';
|
||||||
|
import { AccountsUtil } from 'src/modules/accounts/util/accounts.util';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-toolbar',
|
||||||
|
templateUrl: './toolbar.component.html',
|
||||||
|
styleUrls: ['./toolbar.component.scss']
|
||||||
|
})
|
||||||
|
export class ToolBarComponent implements OnInit {
|
||||||
|
user$: Promise<User>;
|
||||||
|
myProfileLink = ['/accounts/authentication'];
|
||||||
|
|
||||||
|
constructor(private router: Router, private store: Store<any>) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
AccountsUtil.getUser(this.store)
|
||||||
|
.then((user) => {
|
||||||
|
if (user) {
|
||||||
|
this.myProfileLink = ['/article', user.id];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
console.log(reason);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
15
src/app/layout/dialog/can-deactivate/can-deactivate.dialog.component.html
Executable file
15
src/app/layout/dialog/can-deactivate/can-deactivate.dialog.component.html
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
<mat-card class="confirm-card">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{data.title}}</mat-card-title>
|
||||||
|
<mat-card-subtitle></mat-card-subtitle>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<p>
|
||||||
|
{{data.message}}
|
||||||
|
</p>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions class="button-farm flex-row">
|
||||||
|
<button mat-stroked-button (click)="onClickChoice(false)" class="mat-primary">No</button>
|
||||||
|
<button mat-flat-button (click)="onClickChoice(true)" class="mat-primary">Yes</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
38
src/app/layout/dialog/can-deactivate/can-deactivate.dialog.component.ts
Executable file
38
src/app/layout/dialog/can-deactivate/can-deactivate.dialog.component.ts
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
import { Component, OnInit, Input, Output, EventEmitter, Inject } from '@angular/core';
|
||||||
|
import { FormGroupDirective, NgForm, FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { ErrorStateMatcher, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { take, tap, map, catchError, switchMap, finalize } from 'rxjs/operators';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
export interface CanDeactivateDialogData {
|
||||||
|
title: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CanDeactivateDialogResult {
|
||||||
|
choice: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-can-deactivate-dialog',
|
||||||
|
templateUrl: './can-deactivate.dialog.component.html',
|
||||||
|
styleUrls: ['./can-deactivate.dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class CanDeactivateDialogComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<CanDeactivateDialogComponent, CanDeactivateDialogResult>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) private data: CanDeactivateDialogData,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickChoice(choice: boolean) {
|
||||||
|
this.dialogRef.close({
|
||||||
|
choice: choice,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
15
src/app/layout/dialog/confirm/confirm.dialog.component.html
Executable file
15
src/app/layout/dialog/confirm/confirm.dialog.component.html
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
<mat-card class="confirm-card">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>{{data.title}}</mat-card-title>
|
||||||
|
<!-- <mat-card-subtitle>Confirm</mat-card-subtitle> -->
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<p class="notice">
|
||||||
|
{{data.message}}
|
||||||
|
</p>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions class="button-farm flex-row">
|
||||||
|
<button mat-stroked-button (click)="onClickChoice(false)" class="mat-primary">No</button>
|
||||||
|
<button mat-flat-button (click)="onClickChoice(true)" class="mat-primary">Yes</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
0
src/app/layout/dialog/confirm/confirm.dialog.component.scss
Executable file
0
src/app/layout/dialog/confirm/confirm.dialog.component.scss
Executable file
25
src/app/layout/dialog/confirm/confirm.dialog.component.spec.ts
Executable file
25
src/app/layout/dialog/confirm/confirm.dialog.component.spec.ts
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConfirmDialogComponent } from './confirm.dialog.component';
|
||||||
|
|
||||||
|
describe('ConfirmDialogComponent', () => {
|
||||||
|
let component: ConfirmDialogComponent;
|
||||||
|
let fixture: ComponentFixture<ConfirmDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ConfirmDialogComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ConfirmDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
49
src/app/layout/dialog/confirm/confirm.dialog.component.ts
Executable file
49
src/app/layout/dialog/confirm/confirm.dialog.component.ts
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: confirm.dialog.component.ts
|
||||||
|
* 작성일자: 2019-01-13
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: Confirm Dialog component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
export interface ConfirmDialogData {
|
||||||
|
title: string;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfirmDialogResult {
|
||||||
|
choice: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-confirm-dialog',
|
||||||
|
templateUrl: './confirm.dialog.component.html',
|
||||||
|
styleUrls: [
|
||||||
|
'./confirm.dialog.component.scss',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ConfirmDialogComponent implements OnInit {
|
||||||
|
|
||||||
|
tempAgeLimits = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfirmDialogComponent, ConfirmDialogResult>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: ConfirmDialogData
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickChoice(choice: boolean): void {
|
||||||
|
this.dialogRef.close({
|
||||||
|
choice: choice,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/app/layout/dialog/events/failure/failure.snackbar.component.html
Executable file
12
src/app/layout/dialog/events/failure/failure.snackbar.component.html
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="sb-wrap">
|
||||||
|
<b class="title-failure">
|
||||||
|
<mat-icon svgIcon="msg_fail">failure</mat-icon> {{data?.title}}
|
||||||
|
</b>
|
||||||
|
<span class="notice"> {{data?.message}}</span>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<mat-icon svgIcon="msg_ok">success</mat-icon> as ok
|
||||||
|
<mat-icon svgIcon="msg_notice">notice</mat-icon> as notice
|
||||||
|
<mat-icon svgIcon="msg_fail">fail</mat-icon> as fail
|
||||||
|
<mat-icon svgIcon="msg_bigfail">Big fail</mat-icon> as BBBBig fail
|
||||||
|
-->
|
24
src/app/layout/dialog/events/failure/failure.snackbar.component.ts
Executable file
24
src/app/layout/dialog/events/failure/failure.snackbar.component.ts
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
import { Component, OnInit, ViewChild, ElementRef, Inject } from '@angular/core';
|
||||||
|
import { MAT_SNACK_BAR_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
export interface FailureSnackBarData {
|
||||||
|
title?: string;
|
||||||
|
message?: string;
|
||||||
|
error?: Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-events-failure-snackbar',
|
||||||
|
templateUrl: './failure.snackbar.component.html',
|
||||||
|
styleUrls: ['./failure.snackbar.component.scss']
|
||||||
|
})
|
||||||
|
export class FailureSnackBarComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_SNACK_BAR_DATA) public data: FailureSnackBarData,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() { }
|
||||||
|
}
|
7
src/app/layout/dialog/events/index.ts
Executable file
7
src/app/layout/dialog/events/index.ts
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
import { FailureSnackBarComponent } from './failure/failure.snackbar.component';
|
||||||
|
import { SuccessSnackBarComponent } from './success/success.snackbar.component';
|
||||||
|
|
||||||
|
export const EVENTS_DIALOGS = [
|
||||||
|
FailureSnackBarComponent,
|
||||||
|
SuccessSnackBarComponent,
|
||||||
|
];
|
12
src/app/layout/dialog/events/success/success.snackbar.component.html
Executable file
12
src/app/layout/dialog/events/success/success.snackbar.component.html
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
<div class="sb-wrap">
|
||||||
|
<b class="title-success">
|
||||||
|
<mat-icon svgIcon="msg_ok">success</mat-icon> {{data?.title}}
|
||||||
|
</b>
|
||||||
|
<span class="notice"> {{data?.message}}</span>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
<mat-icon svgIcon="msg_ok">success</mat-icon> as ok
|
||||||
|
<mat-icon svgIcon="msg_notice">notice</mat-icon> as notice
|
||||||
|
<mat-icon svgIcon="msg_fail">fail</mat-icon> as fail
|
||||||
|
<mat-icon svgIcon="msg_bigfail">Big fail</mat-icon> as BBBBig fail
|
||||||
|
-->
|
23
src/app/layout/dialog/events/success/success.snackbar.component.ts
Executable file
23
src/app/layout/dialog/events/success/success.snackbar.component.ts
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
|
import { MAT_SNACK_BAR_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
export interface SuccessSnackBarData {
|
||||||
|
title?: string;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-events-success-snackbar',
|
||||||
|
templateUrl: './success.snackbar.component.html',
|
||||||
|
styleUrls: ['./success.snackbar.component.scss']
|
||||||
|
})
|
||||||
|
export class SuccessSnackBarComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(MAT_SNACK_BAR_DATA) public data: SuccessSnackBarData,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() { }
|
||||||
|
}
|
9
src/app/layout/dialog/index.ts
Executable file
9
src/app/layout/dialog/index.ts
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
import { CanDeactivateDialogComponent } from './can-deactivate/can-deactivate.dialog.component';
|
||||||
|
import { ConfirmDialogComponent } from './confirm/confirm.dialog.component';
|
||||||
|
import { EVENTS_DIALOGS } from './events';
|
||||||
|
|
||||||
|
export const DIALOGS = [
|
||||||
|
CanDeactivateDialogComponent,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
...EVENTS_DIALOGS,
|
||||||
|
];
|
57
src/app/layout/layout.module.ts
Executable file
57
src/app/layout/layout.module.ts
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: accounts.module.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: accounts module을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { SharedModule } from '../../modules/common/shared/shared.module';
|
||||||
|
import { AccountsModule } from '../../modules/accounts/accounts.module';
|
||||||
|
import { COMPONENTS } from './component';
|
||||||
|
import { DIALOGS } from './dialog';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule,
|
||||||
|
TranslateModule,
|
||||||
|
SharedModule,
|
||||||
|
AccountsModule,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
...COMPONENTS,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
...COMPONENTS,
|
||||||
|
...DIALOGS,
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
...DIALOGS,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class LayoutModule {
|
||||||
|
public static forRoot(): ModuleWithProviders<LayoutRootModule> {
|
||||||
|
return {
|
||||||
|
ngModule: LayoutRootModule,
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class LayoutRootModule {
|
||||||
|
}
|
45
src/app/pages/accounts/accounts-routing.page.module.ts
Executable file
45
src/app/pages/accounts/accounts-routing.page.module.ts
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: accounts-routing.module.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: account 영역의 routing을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { AccountsLayoutComponent } from '../../layout/component/accounts/accounts.layout.component';
|
||||||
|
|
||||||
|
import { AuthenticationPageComponent } from './component/authentication/authentication.page.component';
|
||||||
|
import { WelcomePageComponent } from './component/welcome/welcome.page.component';
|
||||||
|
import { AuthenticationCallbackPageComponent } from './component/authentication/authentication-callback.page.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AccountsLayoutComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'authentication',
|
||||||
|
component: AuthenticationPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'authentication/callback',
|
||||||
|
component: AuthenticationCallbackPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'welcome',
|
||||||
|
component: WelcomePageComponent
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AccountsRoutingPageModule {}
|
34
src/app/pages/accounts/accounts.page.module.ts
Executable file
34
src/app/pages/accounts/accounts.page.module.ts
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: accounts.module.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: accounts page 영역의 module을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { LayoutModule } from '../../layout/layout.module';
|
||||||
|
|
||||||
|
import { AccountsRoutingPageModule } from './accounts-routing.page.module';
|
||||||
|
import { AccountsModule } from '../../../modules/accounts/accounts.module';
|
||||||
|
|
||||||
|
import { COMPONENTS } from './component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule,
|
||||||
|
LayoutModule,
|
||||||
|
AccountsRoutingPageModule,
|
||||||
|
AccountsModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
...COMPONENTS,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AccountsPageModule { }
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: authentication-callback.page.component.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: authentication callback page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
import * as AppLoginStore from '../../../../store/login';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-accounts-authentication-callback',
|
||||||
|
templateUrl: './authentication-callback.page.component.html',
|
||||||
|
styleUrls: ['./authentication-callback.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class AuthenticationCallbackPageComponent implements OnInit {
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.activatedRoute.queryParams.subscribe(queryParams => {
|
||||||
|
const token = queryParams['token'] || null;
|
||||||
|
const result = queryParams['result'] || null;
|
||||||
|
let returnURL = queryParams['returnURL'];
|
||||||
|
if (!returnURL || 'null' === returnURL || '' === returnURL) {
|
||||||
|
returnURL = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store.dispatch(new AppLoginStore.LoginToken({ token, returnURL: returnURL }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="login-layout">
|
||||||
|
<app-authentication *ngIf="params$ | async as params" [params]="params"></app-authentication>
|
||||||
|
</div>
|
|
@ -0,0 +1,61 @@
|
||||||
|
@mixin calc($property, $expression) {
|
||||||
|
#{$property}: -moz-calc(#{$expression});
|
||||||
|
#{$property}: -webkit-calc(#{$expression});
|
||||||
|
#{$property}: calc(#{$expression});
|
||||||
|
}
|
||||||
|
|
||||||
|
$marginHeight: 170px;
|
||||||
|
|
||||||
|
.login-layout {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
@include calc(height, '100vh - '$marginHeight);
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 55px;
|
||||||
|
padding: 0;
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 205px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
|
||||||
|
@media (max-height: 640px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 195px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-height: 640px) and (min-width: 760px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right -45px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-height: 641px) and (max-height: 1024px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 65px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width:480px) and (max-width: 760px) and (min-height: 641px) and (max-height: 1024px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 40px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 761px) and (max-width:1024px) and (min-height: 641px) and (max-height: 1024px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 0px;
|
||||||
|
background-size: 500px auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1025px) and (min-height: 641px) and (max-height: 1024px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 0px;
|
||||||
|
background-size: 500px auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-height: 1025px) {
|
||||||
|
background: url(../../../../../assets/img/login/bg.png) no-repeat right 30px;
|
||||||
|
background-size: 100% auto;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: authentication.page.component.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: authentication page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
import { of, Observable } from 'rxjs';
|
||||||
|
import { take, map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-accounts-authentication',
|
||||||
|
templateUrl: './authentication.page.component.html',
|
||||||
|
styleUrls: ['./authentication.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class AuthenticationPageComponent implements OnInit {
|
||||||
|
params$: Observable<Map<string, string>>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.params$ = this.activatedRoute.queryParamMap.pipe(
|
||||||
|
take(1),
|
||||||
|
map(params => {
|
||||||
|
const _params = new Map();
|
||||||
|
_params.set('returnURL', params.get('returnURL'));
|
||||||
|
return _params;
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
return of(error);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
9
src/app/pages/accounts/component/index.ts
Executable file
9
src/app/pages/accounts/component/index.ts
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
import { AuthenticationPageComponent } from './authentication/authentication.page.component';
|
||||||
|
import { AuthenticationCallbackPageComponent } from './authentication/authentication-callback.page.component';
|
||||||
|
import { WelcomePageComponent } from './welcome/welcome.page.component';
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
AuthenticationPageComponent,
|
||||||
|
AuthenticationCallbackPageComponent,
|
||||||
|
WelcomePageComponent,
|
||||||
|
];
|
1
src/app/pages/accounts/component/welcome/welcome.page.component.html
Executable file
1
src/app/pages/accounts/component/welcome/welcome.page.component.html
Executable file
|
@ -0,0 +1 @@
|
||||||
|
welcome
|
23
src/app/pages/accounts/component/welcome/welcome.page.component.ts
Executable file
23
src/app/pages/accounts/component/welcome/welcome.page.component.ts
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: welcome.page.component.ts
|
||||||
|
* 작성일자: 2018-12-23
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: welcome page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-accounts-welcome',
|
||||||
|
templateUrl: './welcome.page.component.html',
|
||||||
|
styleUrls: ['./welcome.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class WelcomePageComponent {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/app/pages/admin/admin-routing.page.module.ts
Executable file
42
src/app/pages/admin/admin-routing.page.module.ts
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: admin-routing.page.module.ts
|
||||||
|
* 작성일자: 2019-01-08
|
||||||
|
* 작 성 자: 최지련
|
||||||
|
* 설 명: user 영역의 routing을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { DefaultLayoutComponent } from '../../layout/component/default/default.layout.component';
|
||||||
|
import { ReportPageComponent } from './component/report/report.page.component';
|
||||||
|
import { ErrorPageComponent } from './component/error/error.page.component';
|
||||||
|
import { DataPageComponent } from './component/data/data.page.component';
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: DefaultLayoutComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'report',
|
||||||
|
component: ReportPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'data',
|
||||||
|
component: DataPageComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '404',
|
||||||
|
component: ErrorPageComponent
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AdminRoutingPageModule { }
|
30
src/app/pages/admin/admin.page.module.ts
Executable file
30
src/app/pages/admin/admin.page.module.ts
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: admin.page.module.ts
|
||||||
|
* 작성일자: 2019-01-08
|
||||||
|
* 작 성 자: 최지련
|
||||||
|
* 설 명: admin page 영역의 module을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { COMPONENTS } from './component';
|
||||||
|
import { AdminRoutingPageModule } from './admin-routing.page.module';
|
||||||
|
import { LayoutModule } from '../../layout/layout.module';
|
||||||
|
import { SharedModule } from '../../../modules/common/shared/shared.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule,
|
||||||
|
AdminRoutingPageModule,
|
||||||
|
SharedModule,
|
||||||
|
LayoutModule,
|
||||||
|
],
|
||||||
|
declarations: [...COMPONENTS]
|
||||||
|
})
|
||||||
|
export class AdminPageModule { }
|
50
src/app/pages/admin/component/data/data.page.component.html
Executable file
50
src/app/pages/admin/component/data/data.page.component.html
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
<section>
|
||||||
|
<div class="section-wrap">
|
||||||
|
<h2>관리자 화면 – 기준 데이터 생성</h2>
|
||||||
|
<div class="overflowTable">
|
||||||
|
<mat-list>
|
||||||
|
<!-- <mat-list-item>
|
||||||
|
<h4 mat-line>Article Tag 데이터 생성</h4>
|
||||||
|
<p mat-line> Article Tag </p>
|
||||||
|
<button mat-raised-button (click)="onClickArticleTagData()">생성</button>
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item>
|
||||||
|
<h4 mat-line>User Analysis Favor Tag 데이터 생성</h4>
|
||||||
|
<p mat-line> User Analysis Favor Tag </p>
|
||||||
|
<button mat-raised-button (click)="onClickUserAnalysisFavorTagData()">생성</button>
|
||||||
|
</mat-list-item> -->
|
||||||
|
<!-- <mat-list-item>
|
||||||
|
<h4 mat-line>이벤트 데이터 생성</h4>
|
||||||
|
<p mat-line> User Support Event </p>
|
||||||
|
<button mat-raised-button (click)="onClickUserSupportEventData()">생성</button>
|
||||||
|
</mat-list-item> -->
|
||||||
|
<!-- <mat-list-item>
|
||||||
|
<h4 mat-line>Meta Comments Tag 데이터 생성</h4>
|
||||||
|
<p mat-line> Meta Comments Tag </p>
|
||||||
|
<button mat-raised-button (click)="onClickMetaCommentsTagData()">생성</button>
|
||||||
|
</mat-list-item> -->
|
||||||
|
<mat-list-item>
|
||||||
|
<h4 mat-line>Thumbnails 생성</h4>
|
||||||
|
<p mat-line> Thumbnails </p>
|
||||||
|
<button mat-raised-button (click)="onClickThumbnails()">생성</button>
|
||||||
|
</mat-list-item>
|
||||||
|
|
||||||
|
<mat-list-item>
|
||||||
|
<h4 mat-line>Mongodb Article 생성</h4>
|
||||||
|
<p mat-line> Mongodb Article </p>
|
||||||
|
<button mat-raised-button (click)="onClickMongodbArticleData()">생성</button>
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item>
|
||||||
|
<h4 mat-line>Random Article 생성</h4>
|
||||||
|
<p mat-line> Random Article <input type="text" style="width: 40px;" #randomArticleCount value="100" /> </p>
|
||||||
|
<button mat-raised-button (click)="onClickRandomArticleData(randomArticleCount.value)">생성</button>
|
||||||
|
</mat-list-item>
|
||||||
|
<mat-list-item>
|
||||||
|
<h4 mat-line>Random Author 생성</h4>
|
||||||
|
<p mat-line> Random Author <input type="text" style="width: 40px;" #randomAuthorCount value="100" /> </p>
|
||||||
|
<button mat-raised-button (click)="onClickRandomAuthorData(randomAuthorCount.value)">생성</button>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
4
src/app/pages/admin/component/data/data.page.component.scss
Executable file
4
src/app/pages/admin/component/data/data.page.component.scss
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
.example-button-row button,
|
||||||
|
.example-button-row a {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
197
src/app/pages/admin/component/data/data.page.component.ts
Executable file
197
src/app/pages/admin/component/data/data.page.component.ts
Executable file
|
@ -0,0 +1,197 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: data.page.component.ts
|
||||||
|
* 작성일자: 2019-01-08
|
||||||
|
* 작 성 자: 최지련
|
||||||
|
* 설 명: admin data page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { take, map, catchError, tap, finalize } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { ArticleTag } from '../../../../../shared/article/model/article-tag.model';
|
||||||
|
import { UserAnalysisFavorTag } from '../../../../../shared/user-analysis/model/user-analysis-favor-tag.model';
|
||||||
|
import { ArticleTagService } from '../../../../../modules/article/service/article-tag.service';
|
||||||
|
import { UserAnalysisFavorTagService } from '../../../../../modules/user-analysis/service/user-analysis-favor-tag.service';
|
||||||
|
import { ContentsService } from '../../../../../modules/contents/service/contents.service';
|
||||||
|
import * as AppEventsStore from '../../../../store/events';
|
||||||
|
import { MetaCommentsTag } from '../../../../../shared/meta/model/meta-comments-tag.model';
|
||||||
|
import { MetaCommentsTagService } from '../../../../../modules/meta/service/meta-comments-tag.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-admin-data',
|
||||||
|
templateUrl: './data.page.component.html',
|
||||||
|
styleUrls: ['./data.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class DataPageComponent {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient,
|
||||||
|
private store: Store<any>,
|
||||||
|
private articleTagService: ArticleTagService,
|
||||||
|
private userAnalysisFavorTagService: UserAnalysisFavorTagService,
|
||||||
|
private contentsService: ContentsService,
|
||||||
|
private metaCommentsTagService: MetaCommentsTagService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickArticleTagData() {
|
||||||
|
this.httpClient.get('./assets/json/article-tag.json').pipe(
|
||||||
|
take(1),
|
||||||
|
map((articleTagList: ArticleTag[]) => {
|
||||||
|
this.addAllArticleTagList(articleTagList);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
private addAllArticleTagList(articleTagList: ArticleTag[]) {
|
||||||
|
if (!articleTagList || 0 === articleTagList.length) {
|
||||||
|
console.log('articleTagList is not valid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const articleTag of articleTagList) {
|
||||||
|
this.articleTagService.add(articleTag).pipe(
|
||||||
|
take(1),
|
||||||
|
map((_articleTag) => {
|
||||||
|
console.log('articleTag added', _articleTag);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickUserAnalysisFavorTagData() {
|
||||||
|
this.httpClient.get('./assets/json/user-analysis-favor-tag.json').pipe(
|
||||||
|
take(1),
|
||||||
|
map((userAnalysisFavorTagList: UserAnalysisFavorTag[]) => {
|
||||||
|
this.addAllUserAnalysisFavorTagList(userAnalysisFavorTagList);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private addAllUserAnalysisFavorTagList(userAnalysisFavorTagList: UserAnalysisFavorTag[]) {
|
||||||
|
if (!userAnalysisFavorTagList || 0 === userAnalysisFavorTagList.length) {
|
||||||
|
console.log('userAnalysisFavorTagList is not valid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const userAnalysisFavorTag of userAnalysisFavorTagList) {
|
||||||
|
this.userAnalysisFavorTagService.add(userAnalysisFavorTag).pipe(
|
||||||
|
take(1),
|
||||||
|
map((_userAnalysisFavorTag) => {
|
||||||
|
console.log('userAnalysisFavorTag added', _userAnalysisFavorTag);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickUserSupportEventData() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickMetaCommentsTagData() {
|
||||||
|
this.httpClient.get('./assets/json/meta-comments-tag.json').pipe(
|
||||||
|
take(1),
|
||||||
|
map((metaCommentsTagList: MetaCommentsTag[]) => {
|
||||||
|
this.addAllMetaCommentsTagList(metaCommentsTagList);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
private addAllMetaCommentsTagList(metaCommentsTagList: MetaCommentsTag[]) {
|
||||||
|
if (!metaCommentsTagList || 0 === metaCommentsTagList.length) {
|
||||||
|
console.log('metaCommentsTagList is not valid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const metaCommentsTag of metaCommentsTagList) {
|
||||||
|
this.metaCommentsTagService.add(metaCommentsTag).pipe(
|
||||||
|
take(1),
|
||||||
|
map((_metaCommentsTag) => {
|
||||||
|
console.log('metaCommentsTag added', _metaCommentsTag);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickMongodbArticleData() {
|
||||||
|
this.contentsService.updateMongodbArticle().pipe(
|
||||||
|
take(1),
|
||||||
|
tap(() => {
|
||||||
|
this.store.dispatch(new AppEventsStore.ShowProgressBar());
|
||||||
|
}),
|
||||||
|
map((_count) => {
|
||||||
|
console.log('Mongodb Article added', _count);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
}),
|
||||||
|
finalize(() => {
|
||||||
|
this.store.dispatch(new AppEventsStore.HideProgressBar());
|
||||||
|
}),
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickRandomArticleData(count: number) {
|
||||||
|
this.contentsService.updateRandomArticle(count).pipe(
|
||||||
|
take(1),
|
||||||
|
map((_count) => {
|
||||||
|
console.log('Random Article added', _count);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickRandomAuthorData(count: number) {
|
||||||
|
this.contentsService.updateRandomAuthor(count).pipe(
|
||||||
|
take(1),
|
||||||
|
map((_count) => {
|
||||||
|
console.log('Random Author added', _count);
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
console.log(err);
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickThumbnails() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
7
src/app/pages/admin/component/error/error.page.component.html
Executable file
7
src/app/pages/admin/component/error/error.page.component.html
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="error-page">
|
||||||
|
<object class="ico-error" type="image/svg+xml" data="../../../../assets/img/error/ico_error.svg">Error</object>
|
||||||
|
<h2 class="error-title">
|
||||||
|
죄송합니다.
|
||||||
|
</h2>
|
||||||
|
<p class="error-description">페이지를 표시할 수 없습니다.</p>
|
||||||
|
</div>
|
18
src/app/pages/admin/component/error/error.page.component.scss
Executable file
18
src/app/pages/admin/component/error/error.page.component.scss
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
.error-page {
|
||||||
|
margin: 50px auto;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.ico-error {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-title {
|
||||||
|
text-align: center;
|
||||||
|
margin: 15px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-description {
|
||||||
|
color: #a5a5a5;
|
||||||
|
}
|
||||||
|
}
|
20
src/app/pages/admin/component/error/error.page.component.ts
Executable file
20
src/app/pages/admin/component/error/error.page.component.ts
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: error.page.component.ts
|
||||||
|
* 작성일자: 2019-01-09
|
||||||
|
* 작 성 자: 조현정
|
||||||
|
* 설 명: error page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-error',
|
||||||
|
templateUrl: './error.page.component.html',
|
||||||
|
styleUrls: ['./error.page.component.scss']
|
||||||
|
})
|
||||||
|
export class ErrorPageComponent {
|
||||||
|
constructor() {}
|
||||||
|
}
|
9
src/app/pages/admin/component/index.ts
Executable file
9
src/app/pages/admin/component/index.ts
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
import { DataPageComponent } from './data/data.page.component';
|
||||||
|
import { ReportPageComponent } from './report/report.page.component';
|
||||||
|
import { ErrorPageComponent } from './error/error.page.component';
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
DataPageComponent,
|
||||||
|
ReportPageComponent,
|
||||||
|
ErrorPageComponent,
|
||||||
|
];
|
53
src/app/pages/admin/component/report/report.page.component.html
Executable file
53
src/app/pages/admin/component/report/report.page.component.html
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
<section>
|
||||||
|
<div class="section-wrap">
|
||||||
|
<h2>관리자 화면 – 신고 접수 및 처리</h2>
|
||||||
|
<div class="overflowTable">
|
||||||
|
<table class="table-admin mat-table">
|
||||||
|
<colgroup class="col-width">
|
||||||
|
<col class="t1">
|
||||||
|
<col class="t2">
|
||||||
|
<col class="t3">
|
||||||
|
<col class="t4">
|
||||||
|
<col class="t5">
|
||||||
|
<col class="t6">
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> No. </th>
|
||||||
|
<th> 신고 콘텐트 </th>
|
||||||
|
<th> 신고내용 </th>
|
||||||
|
<th> 신고일시 </th>
|
||||||
|
<th> 상태 </th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td> 1 </td>
|
||||||
|
<td> xanNskdakNsjd98 </td>
|
||||||
|
<td> 저작권 위반</td>
|
||||||
|
<td> 2019-01-20 </td>
|
||||||
|
<td> 신고접수 </td>
|
||||||
|
<td>
|
||||||
|
<button mat-raised-button class="mat-primary">해제</button>
|
||||||
|
<!-- <button mat-raised-button class="mat-secondary">이의기각</button> -->
|
||||||
|
<button mat-raised-button class="mat-accent">삭제</button>
|
||||||
|
<!-- <button mat-raised-button class="mat-warn ">블라인드</button> -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> 2 </td>
|
||||||
|
<td> sdflksldkfdslksf </td>
|
||||||
|
<td> 부적절</td>
|
||||||
|
<td> 2019-01-20 </td>
|
||||||
|
<td> 블라인드 완료 </td>
|
||||||
|
<td>
|
||||||
|
<button mat-raised-button class="mat-primary">해제</button>
|
||||||
|
<button mat-raised-button class="mat-warn">이의기각</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
56
src/app/pages/admin/component/report/report.page.component.scss
Executable file
56
src/app/pages/admin/component/report/report.page.component.scss
Executable file
|
@ -0,0 +1,56 @@
|
||||||
|
.table-admin {
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
$border: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2),
|
||||||
|
0px 8px 10px 1px rgba(0, 0, 0, 0.14),
|
||||||
|
0px 3px 14px 2px rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
tr {
|
||||||
|
height: 48px;
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0 6px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 3px 6px;
|
||||||
|
border-bottom: 1px solid $border;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-width {
|
||||||
|
.t1 {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t2 {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t3 {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t4 {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t5 {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 2px;
|
||||||
|
min-width: 24px !important;
|
||||||
|
padding: 0 5px !important;
|
||||||
|
line-height: 24px !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
}
|
23
src/app/pages/admin/component/report/report.page.component.ts
Executable file
23
src/app/pages/admin/component/report/report.page.component.ts
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: report.page.component.ts
|
||||||
|
* 작성일자: 2019-01-08
|
||||||
|
* 작 성 자: 최지련
|
||||||
|
* 설 명: admin report page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-admin-report',
|
||||||
|
templateUrl: './report.page.component.html',
|
||||||
|
styleUrls: ['./report.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class ReportPageComponent {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
src/app/pages/article/article-routing.page.module.ts
Executable file
81
src/app/pages/article/article-routing.page.module.ts
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: accounts-routing.module.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: account 영역의 routing을 정의한다.
|
||||||
|
* 수정일시: 2018-12-27
|
||||||
|
* 수 정 자: 조현정
|
||||||
|
* 수정내용: Layout change
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { DefaultLayoutComponent } from '../../layout/component/default/default.layout.component';
|
||||||
|
import { ProfilePageComponent } from './component/profile/profile.page.component';
|
||||||
|
import { FormPageComponent as SearchFormPageComponent } from './component/search/form/form.page.component';
|
||||||
|
import { ResultPageComponent as SearchResultPageComponent } from './component/search/result/result.page.component';
|
||||||
|
|
||||||
|
import { DetailsPageComponent } from './component/details/details.page.component';
|
||||||
|
import { WritePageComponent } from './component/write/write.page.component';
|
||||||
|
import { EmotionsPageComponent } from './component/emotions/emotions.page.component';
|
||||||
|
import { AuthGuard } from '../../guard/auth.guard';
|
||||||
|
import { AuthNicknameGuard } from '../../guard/auth-nickname.guard';
|
||||||
|
import { CanDeactivateGuard } from '../../guard/can-deactivate.guard';
|
||||||
|
import { ArticleOwnerGuard } from '../../guard/article-owner.guard';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: DefaultLayoutComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'write',
|
||||||
|
component: WritePageComponent,
|
||||||
|
canActivate: [
|
||||||
|
AuthGuard,
|
||||||
|
AuthNicknameGuard,
|
||||||
|
],
|
||||||
|
canDeactivate: [CanDeactivateGuard],
|
||||||
|
runGuardsAndResolvers: 'always',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'write/:aid',
|
||||||
|
component: WritePageComponent,
|
||||||
|
canActivate: [
|
||||||
|
AuthGuard,
|
||||||
|
AuthNicknameGuard,
|
||||||
|
ArticleOwnerGuard,
|
||||||
|
],
|
||||||
|
canDeactivate: [CanDeactivateGuard],
|
||||||
|
runGuardsAndResolvers: 'always',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'search',
|
||||||
|
component: SearchFormPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'emotions',
|
||||||
|
component: EmotionsPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'p/:aid',
|
||||||
|
component: DetailsPageComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':uid',
|
||||||
|
component: ProfilePageComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'search/p/:tagName',
|
||||||
|
component: SearchResultPageComponent
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class ArticleRoutingPageModule { }
|
50
src/app/pages/article/article.page.module.ts
Executable file
50
src/app/pages/article/article.page.module.ts
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: article.page.module.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: article page 영역의 module을 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { LayoutModule } from '../../layout/layout.module';
|
||||||
|
import { SharedModule } from '../../../modules/common/shared/shared.module';
|
||||||
|
import { UserModule } from '../../../modules/user/user.module';
|
||||||
|
import { UserSupportModule } from '../../../modules/user-support/user-support.module';
|
||||||
|
|
||||||
|
import { ArticleRoutingPageModule } from './article-routing.page.module';
|
||||||
|
import { CartoonsModule } from '../../../modules/cartoons/cartoons.module';
|
||||||
|
import { IllustrationsModule } from '../../../modules/illustrations/illustrations.module';
|
||||||
|
import { NovelModule } from '../../../modules/novel/novel.module';
|
||||||
|
import { AttachmentsModule } from '../../../modules/attachments/attachments.module';
|
||||||
|
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import { COMPONENTS } from './component';
|
||||||
|
import { ArticleModule } from 'src/modules/article/article.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule,
|
||||||
|
SharedModule,
|
||||||
|
LayoutModule,
|
||||||
|
CartoonsModule,
|
||||||
|
IllustrationsModule,
|
||||||
|
NovelModule,
|
||||||
|
ArticleRoutingPageModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
AttachmentsModule,
|
||||||
|
UserModule,
|
||||||
|
UserSupportModule,
|
||||||
|
ArticleModule
|
||||||
|
],
|
||||||
|
declarations: [...COMPONENTS]
|
||||||
|
})
|
||||||
|
export class ArticlePageModule { }
|
17
src/app/pages/article/component/details/details.page.component.html
Executable file
17
src/app/pages/article/component/details/details.page.component.html
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
<div
|
||||||
|
*ngIf="(articleMongodb$ | async) as articleMongodb"
|
||||||
|
[ngSwitch]="articleMongodb.type"
|
||||||
|
>
|
||||||
|
<app-illustrations-details
|
||||||
|
*ngSwitchCase="'Illustrations'"
|
||||||
|
[article]="articleMongodb.article"
|
||||||
|
></app-illustrations-details>
|
||||||
|
<app-cartoons-details
|
||||||
|
*ngSwitchCase="'Cartoons'"
|
||||||
|
[article]="articleMongodb.article"
|
||||||
|
></app-cartoons-details>
|
||||||
|
<app-novel-details
|
||||||
|
*ngSwitchCase="'Novel'"
|
||||||
|
[article]="articleMongodb.article"
|
||||||
|
></app-novel-details>
|
||||||
|
</div>
|
0
src/app/pages/article/component/details/details.page.component.scss
Executable file
0
src/app/pages/article/component/details/details.page.component.scss
Executable file
76
src/app/pages/article/component/details/details.page.component.ts
Executable file
76
src/app/pages/article/component/details/details.page.component.ts
Executable file
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: details.page.component.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: details page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import {
|
||||||
|
switchMap,
|
||||||
|
tap,
|
||||||
|
map,
|
||||||
|
catchError,
|
||||||
|
take,
|
||||||
|
finalize
|
||||||
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { ArticleGetService } from '../../../../../modules/article/service/article.get.service';
|
||||||
|
import { ArticleType } from '../../../../../shared/article/type/article-type.type';
|
||||||
|
import { ArticleMongodb } from '../../../../../shared/article/model/article.mongodb.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-cartoons-details',
|
||||||
|
templateUrl: './details.page.component.html',
|
||||||
|
styleUrls: ['./details.page.component.scss']
|
||||||
|
})
|
||||||
|
export class DetailsPageComponent implements OnInit {
|
||||||
|
aid: string;
|
||||||
|
articleMongodb$: Observable<ArticleMongodb>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private articleGetService: ArticleGetService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.articleMongodb$ = this.activatedRoute.paramMap.pipe(
|
||||||
|
take(1),
|
||||||
|
tap(() => {
|
||||||
|
// display progressbar
|
||||||
|
}),
|
||||||
|
switchMap(params => {
|
||||||
|
// (+) before `params.get()` turns the string into a number
|
||||||
|
// (+) before `params.get()` turns the string into a number
|
||||||
|
this.aid = params.get('aid');
|
||||||
|
|
||||||
|
console.log('aid >> ' + this.aid);
|
||||||
|
|
||||||
|
if (this.aid) {
|
||||||
|
return this.articleGetService.get(this.aid).pipe(
|
||||||
|
map((articleMongodb: ArticleMongodb) => {
|
||||||
|
console.log(articleMongodb);
|
||||||
|
return articleMongodb;
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
console.log(error);
|
||||||
|
return of(error);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
console.log(error);
|
||||||
|
return of();
|
||||||
|
}),
|
||||||
|
finalize(() => {
|
||||||
|
// remove progressbar
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
1
src/app/pages/article/component/emotions/emotions.page.component.html
Executable file
1
src/app/pages/article/component/emotions/emotions.page.component.html
Executable file
|
@ -0,0 +1 @@
|
||||||
|
Emotions
|
23
src/app/pages/article/component/emotions/emotions.page.component.ts
Executable file
23
src/app/pages/article/component/emotions/emotions.page.component.ts
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* 파 일 명: emotions.page.component.ts
|
||||||
|
* 작성일자: 2018-12-20
|
||||||
|
* 작 성 자: 박병준
|
||||||
|
* 설 명: emotions page component를 정의한다.
|
||||||
|
* 수정일시:
|
||||||
|
* 수 정 자:
|
||||||
|
* 수정내용:
|
||||||
|
* 참고사항:
|
||||||
|
*/
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-page-cartoons-emotions',
|
||||||
|
templateUrl: './emotions.page.component.html',
|
||||||
|
styleUrls: ['./emotions.page.component.scss'],
|
||||||
|
})
|
||||||
|
export class EmotionsPageComponent {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/app/pages/article/component/index.ts
Executable file
13
src/app/pages/article/component/index.ts
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
import { DetailsPageComponent } from './details/details.page.component';
|
||||||
|
import { EmotionsPageComponent } from './emotions/emotions.page.component';
|
||||||
|
import { ProfilePageComponent } from './profile/profile.page.component';
|
||||||
|
import { WritePageComponent } from './write/write.page.component';
|
||||||
|
import { SEARCH_COMPONENTS } from './search';
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
DetailsPageComponent,
|
||||||
|
EmotionsPageComponent,
|
||||||
|
ProfilePageComponent,
|
||||||
|
WritePageComponent,
|
||||||
|
...SEARCH_COMPONENTS,
|
||||||
|
];
|
82
src/app/pages/article/component/profile/profile.page.component.html
Executable file
82
src/app/pages/article/component/profile/profile.page.component.html
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
<app-user-profile-box></app-user-profile-box>
|
||||||
|
<div #profileScroll class="my-profile">
|
||||||
|
<virtual-scroller #scroll [items]="articleMongodbList" [enableUnequalChildrenSizes]="true" [parentScroll]="profileScroll"
|
||||||
|
(vsEnd)="onVSEnd($event)" (vsUpdate)="viewPortItems = $event">
|
||||||
|
|
||||||
|
<div *ngIf="user">
|
||||||
|
<app-user-profile-box [uid]="uid" [articleCount]="articleCount" [followersCount]="followersCount"
|
||||||
|
[followingCount]="followingCount" (isFollowingYn)="setIsFollowing($event)" [favorTagList]="favorTagList">
|
||||||
|
|
||||||
|
</app-user-profile-box>
|
||||||
|
|
||||||
|
<mat-tab-group animationDuration="0ms" mat-stretch-tabs class="example-stretched-tabs" (selectedTabChange)="onSelectedTabChange($event)">
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<mat-icon svgIcon="tab_mypro_01">article thumbnails</mat-icon>
|
||||||
|
</ng-template>
|
||||||
|
<!-- 다른 component 사용 test
|
||||||
|
randomImages => 이미지 url 리스트,
|
||||||
|
columnCnt => 이미지 column 갯수,
|
||||||
|
viewTitleYn => 타이틀을 보여줄 지 여부
|
||||||
|
-->
|
||||||
|
<!-- <app-article-display-grid [articles]="articleGridList" [columnCnt]="3" [viewTitleYn]="true">
|
||||||
|
</app-article-display-grid> -->
|
||||||
|
<div #container class="thumb-wrap">
|
||||||
|
<article *ngFor="let articleMongodb of viewPortItems" class="article-display-tile">
|
||||||
|
<ng-container [ngSwitch]="articleMongodb.type">
|
||||||
|
<app-illustrations-display-tile *ngSwitchCase="'Illustrations'" [article]="articleMongodb.article"
|
||||||
|
class="pickMeup"></app-illustrations-display-tile>
|
||||||
|
<app-cartoons-display-tile *ngSwitchCase="'Cartoons'" [article]="articleMongodb.article" class="pickMeup"></app-cartoons-display-tile>
|
||||||
|
<app-novel-display-tile *ngSwitchCase="'Novel'" [article]="articleMongodb.article" class="pickMeup">
|
||||||
|
</app-novel-display-tile>
|
||||||
|
</ng-container>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<mat-icon svgIcon="tab_mypro_02">article cards</mat-icon>
|
||||||
|
</ng-template>
|
||||||
|
<!-- one card list가 들어갈 자리 -->
|
||||||
|
<div #container>
|
||||||
|
<article *ngFor="let articleMongodb of viewPortItems" class="article-display-card">
|
||||||
|
<ng-container [ngSwitch]="articleMongodb.type">
|
||||||
|
<app-illustrations-display-card *ngSwitchCase="'Illustrations'" [article]="articleMongodb.article">
|
||||||
|
</app-illustrations-display-card>
|
||||||
|
<app-cartoons-display-card *ngSwitchCase="'Cartoons'" [article]="articleMongodb.article"
|
||||||
|
[authorFollowYn]="authorFollowYn">
|
||||||
|
</app-cartoons-display-card>
|
||||||
|
<app-novel-display-card *ngSwitchCase="'Novel'" [article]="articleMongodb.article">
|
||||||
|
</app-novel-display-card>
|
||||||
|
</ng-container>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<!-- 팔로워 목록 -->
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<mat-icon svgIcon="tab_mypro_03">followerList</mat-icon>
|
||||||
|
</ng-template>
|
||||||
|
<div *ngIf="user">
|
||||||
|
<ng-container *ngFor="let followerUser of followersList">
|
||||||
|
<app-user-followers-display-list [followers]="followerUser" [uid]="uid" [currUser]="followerUser.user"></app-user-followers-display-list>
|
||||||
|
</ng-container>
|
||||||
|
<!-- <app-user-followers-display-list [followers]="followersList"></app-user-followers-display-list> -->
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<!-- 팔로잉 목록 -->
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<mat-icon svgIcon="tab_mypro_04">followingList</mat-icon>
|
||||||
|
</ng-template>
|
||||||
|
<div *ngIf="user">
|
||||||
|
<ng-container *ngFor="let followerUser of followingList">
|
||||||
|
<app-user-followers-display-list [followers]="followerUser" [uid]="uid" [currUser]="followerUser.target"></app-user-followers-display-list>
|
||||||
|
</ng-container>
|
||||||
|
<!-- <app-user-followers-display-list [followers]="followingList"></app-user-followers-display-list> -->
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</div>
|
||||||
|
</virtual-scroller>
|
||||||
|
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user